My code is like this:
size = 50
class cube:
def setsize(sizechoice):
size = sizechoice
However, when I do cube.setsize(200) and then print(size) It says 50 not 200. Idk what the problem is, I'm new to python and I just learned how classes work so I hope you can help me!
size = 50
Here size is a global variable; there's only one instance of it and it's the same throughout the whole module.
class cube:
def setsize(sizechoice):
size = sizechoice
Here however size refers to a local variable, also named size, which shadows (hides) the global one. This comes from the fact that Python assumes that if you are inside a function and assign to a variable without explicitly saying that you refer to a global, you want to create a local with that name. So, as it is, if you do
c = cube()
c.setsize(100)
print(size)
print(c.size)
you'll get 50 for the first print (as the global size won't be affected), and an error on the second one (as you didn't create any instance attribute named size).
Now, if you want to explicitly refer to the global size you would have to do:
class cube:
def setsize(sizechoice):
global size
size = sizechoice
so if you do
c = cube()
c.setsize(100)
print(size)
it'll print 100; but most probably this is not what you want: an instance method generally is expected to affect instance-specific attributes, not globals - IOW, in this implementation all cubes would have the same size!
c = cube()
d = cube()
c.setsize(100)
print(size) # prints 100
d.setsize(200)
print(size) # prints 200
# why did I even bother creating two instances?
What you probably want is to have a size specific of each cube; to do this, you must esplicitly refer to self.size, as in Python there's no "implicit this" rule (such as in Java, C#, C++, ...). You may also want to provide an easy way to set it on construction, so you should probably do:
class cube:
def __init__(self, size):
self.size = size
def setsize(self, size):
self.size = size
and get rid of the now useless global size.
c = cube(100)
d = cube(200)
print(c.size) # 100
print(d.size) # 200
d.setsize(300)
print(c.size) # 100
print(d.size) # 300
Finally, you may even get rid of the setsize setter: it doesn't add anything useful over straight assigning to the size member, and if you want to add validation logic on assignment later you can always change size to be a property.
I see, that you are really new in Python. Take your time and go thru python class tutorial.
Because you are new I wrote simple code, that should work for you. With classes you always initialize class, and with that you get an object.
size = 50 # Does not influence the class
class cube: # Class name
def __init__(self, size): # Initialization
self.size = size # Sets the size of cube
def setSize(self, sizechoice): # Set method (sets size of cube)
self.size = sizechoice
def getSize(self): # Get method (gets size of cube)
return self.size
c = cube(200) # Creation of object cube with size of 200
print(c.getSize()) # Gets the cube size and prints it out
I hope it helps :)
Best of luck with future programming.
You need to set size as a class or instance attribute.
To set a class or instance attribute, you need to do this:
class cube:
def __init__(self):
self.size = 0
def setsize(self, sizechoice):
self.size = sizechoice
so you have to set class or instance attributes inside the __init__ method with the self. keyword.
Now you can do this:
cube = cube()
cube.setsize(200)
print(cube.size)
and it would print 200.
I would recommend to change the class name to Cube (upper C) or something
Welcome to S.O. #pytusiast. The issue is that you are setting the size locally within that function and anywhere else the value is what it was before.
You can define size as a global variable:
class cube:
def setsize(sizechoice):
global size
size = sizechoice
but I'm not sure this is the best way as size now is a global variable.
Related
What is a proper way to set an class atribute which is valid for all objects and the class itself?
My Code looks like this:
class Bacteria(Contour):
min_bacteria_size = 22.56 * 10 ** -15
def __init__(self, contour):
super().__init__(contour.contour, contour.hierarchy)
self.area = contour.area
self.mean_gray = contour.mean_gray
rect = cv2.minAreaRect(self.contour)
self.center = rect[0]
self.width = rect[1][0]
self.height = rect[1][1]
self.rotation = rect[2]
#property
def min_bacteria_size(self):
return Bacteria.min_bacteria_size
#min_bacteria_size.setter
def min_bacteria_size(self, min_bacteria_size):
# min_bacteria_size in fm²
self.min_bacteria_size = min_bacteria_size * 10 ** -15
For min_bacteria_size there is default value, but it should be possible to change this value for all objects and the class itself. Since i want to set the variable min_bacteria_size in femto (10^-15) units i tried to use property setter but it doesn´t worked:
Bacteria.min_bacteria_size = 50
print(Bacteria.min_bacteria_size)
>> 50
Your code is almost just right - just two points of confusion: the name of
the class attribute where the value is stored must not be the same name as the property itself.
The major problem with your code is that when you create the property, you overwrite the default class value. Then your setter sets the new value to the instance only (self.min_bacteria-size) - instead of the class (self.__class__.min_bacteria_size) - however, if it were written exactly like that, it would overwrite the property itself - so it could be used only once.
Then, there is a 3rdy point, if you will sometimes to see the value in raw meters (the number already multiplied by 10e-15) and sometimes the number in femtometers (the human friendly "50") - you should make BOTH numbers available when reading from the class instances (even if the raw pre-multiplied metric value is only used internally by the class).
So, one way to go is to have an ordinary class attribute which holds the raw value in meters, and a property that will scale and store that same attribute, to be consumed by the code that uses the class:
class Bacteria(Contour):
min_bacteria_size_raw = 22.56 * 10e-15
def __init__(self, contour):
...
#property
def min_bacteria_size(self):
return self.__class__.min_bacteria_size_raw / 10e-15
#min_bacteria_size.setter
def min_bacteria_size(self, min_bacteria_size):
# min_bacteria_size in fm²
self.__class__.min_bacteria_size_raw = min_bacteria_size * 10e-15
And here is the class working (with a dummy "contour" class) on the interactive prompt:
In [9]: b = Bacteria(1)
In [10]: b.min_bacteria_size
Out[10]: 22.56
In [11]: b.min_bacteria_size = 50
In [12]: b.min_bacteria_size
Out[12]: 50.0
In [13]: b.min_bacteria_size_raw
Out[13]: 5e-13
# And checking a new instance:
In [14]: Bacteria(2).min_bacteria_size
Out[14]: 50.0
Note that te way properties work, you can't retrieve the transformed value from the class itself with Bacteria.min_bacteria_size: that will retrieve the property object itself. It is possible to create an object just like a property, but that will return the guarded value instead of itself when called on the class - but unless you really need this, or if you will want this for several classes and values, it would be overcomplicate the code. You can easily just invert the logic, and keep the class attribute value in fentometres, and use the property to get the multiplied meter value - that way the human friendly value is readl available as a simple class attribute, just like the multiplied value is in this implementation:
In [15]: Bacteria.min_bacteria_size
Out[15]: <property at 0x7fa61e469f40>
In [16]: Bacteria.min_bacteria_size_raw
Out[16]: 5e-13
I think you're looking for classmethod in python.
class A:
a = 3
#classmethod
def set_a(cls, value):
cls.a = value * 10 # or whatever calculation
def update_a(self): # use in other functions as normal
self.set_a(10)
a = A()
a.set_a(3) # use classmethod
print(A.a) # 30
a.update_a() # or normal
print(A.a) # 100
class SetSize:
def __init__(self, storage_name):
self.storage_name = storage_name
def __set__(self, instance, value):
instance.__dict__[self.storage_name] = value * 10 ** -15
class Bacteria(Contour):
min_bacteria_size = SetSize(‘min_bacteria_size’)
I couldn’t test it but this idea would help you I think.
For my application I have an object which has some set of attributes. One set of attributes, the parameters, can be accessed and adjusted by the user. The other set of attributes, the outputs, should be accessible by the user but are calculated using internal methods. Furthermore, if any of the parameter attributes are adjusted the outputs must also be re-calculated from the internal methods and adjusted accordingly. However, as these calculations may be costly I do not want to needlessly run them unless (or until) they are requested.
Currently I can implement this by making each "parameter" attribute a property and including a self.calculated flag which is raised whenever any of the parameters are changed and also making each "output" attribute a property which checks the self.calculated flag and accordingly either returns the output directly if no calculation is needed or performs the calculation, lowers the flag, and returns the output.
See code
class Rectangle(object):
def __init__(self, length=1, width=1):
self._length = length
self._width = width
self._area = self.calc_area()
self._perim = self.calc_perim()
self.calculated = True
#property
def length(self):
return self._length
#length.setter
def length(self, value):
if value != self._length:
self._length = value
self.calculated = False
#property
def width(self):
return self._width
#width.setter
def width(self, value):
if value != self._width:
self._width = value
self.calculated = False
#property
def area(self):
if self.calculated is True:
return self._area
else:
self.recalculate()
return self._area
#property
def perim(self):
if self.calculated is True:
return self._perim
else:
self.recalculate()
return self._perim
def calc_area(self):
return self.length * self.width
def calc_perim(self):
return 2 * (self.length + self.width)
def recalculate(self):
self._area = self.calc_area()
self._perim = self.calc_perim()
self.calculated = True
def double_width(self):
self.width = 2 * self.width
This gives the desired behavior but seems like an excessive proliferation of properties which would be especially problematic if there got to be a large number of parameters and outputs.
Is there a cleaner way to implement this attribute change/recalculation structure? I have found a couple of posts where a solution is presented involving writing a __setattr__ method for the class but I'm not sure if that would be straight forward to implement in my since the behavior should be different depending on the particular attribute being set. I guess this could be handled with a check in the __setattr__ method about whether the attribute is a parameter or output...
Decorating a class to monitor attribute changes
How to identify when an attribute's attribute is being set?
There are several different options, and which to use is highly dependent on the use case. Clearly, the options below can be quite bad in many use cases.
Delete outputs when inputs change
An example of implementing this:
#width.setter
def width(self, value):
if value != self._width:
self._width = value
(self._area,self._perim) = (None,None)
def perim(self):
if not self._perim:
self._perim = calc_perim(self)
return self._perim
This doesn't address most of your concern, but it does get rid of the calculated flag (and while your code recalculates all of the outputs when any of them are requested after an update, this code just calculates the requested one).
Update values when inputs change
When you increase the width by x, the perimeter increases by 2*x and the area increases by x*length. In some cases, applying formulae such as these to update the values as the inputs change can be more efficient that calculating the outputs from scratch every time the inputs change.
Keep track of last values
Whenever you calculate the outputs, keep track not only of what results you got, but what inputs you used to calculate them. Then next time an object is asked what its outputs are, it can check whether the outputs were calculated according to its current attributes. Obviously, this requires multiplying the input storage space.
Memoization
Going even further than the previous option, create a dictionary where the keys are tuples of attributes, and the values are output. If you currently have a function calculate_output(attributes), replace all calls to the function with
def output_lookup(attributes):
if not attributes in output_dict.keys():
output_dict[attributes] = calculate_output(attributes)
return output_dict[attributes]
You should use this option if you expect particular combinations of attributes to be repeated often, calculating the outputs is expensive, and/or memory is cheap. This can be shared across the class, so if you have several instances of rectangles that have the same length and width, you can have one (_perim,_area) value stored, rather than duplicating it across each instance. So for some use cases, this can be more efficient.
Note that your issue ultimately derives from the fact that you are trying to engage in some memoization (you want to save the results from your calculations, so that when someone accesses an object's outputs, you don't have to calculate the outputs if they've already been calculated for the current inputs), but you need to keep track of when to "invalidate the cache", so to speak. If you were to simply treat the area and perimeter as methods rather than attributes, or you were to treats instances as immutable and require resetting attributes be done by creating a new instance with the new values, you would eliminate the complexities that you've added to the length and width. You can't have it all: you can't have cached values from mutable attributes without some overhead.
PS is True is redundant in if self.calculated is True:.
So, I'm foraying into the world of plasma simulation. Now, while I'm aware that top-level simulations are written in fortran and have ultra-memory efficient subroutines and specialized code, I'm hoping to just run some low-level simulations.
My problem is that, when simulating a large number of particles in a time-varying environment (well, time-stepped), keeping track of all that data is a trick. I've used multi-dimensional arrays before - using the column number for the particle, and the row number for the attribute, however this feels rather clumsy. It does, however, seem to be more quickly executed.
I recently tried defining my own class, however being a python newbie, I probably did it in a very inefficient way. For each particle in 3 dimensions, I needed to be able to store the particle's position, velocity and Force (with the potential to add more variables once the code becomes more complex). Using what I knew of classes, I defined a particle object (I think) that make my code much easier to read and follow:
# Define Particle as a class
class particle():
def __init__(self, index=0, pos=np.array([0, 0, 0]), vel=np.array([0,0,0]),
F=np.array([0, 0, 0])):
self.index = index # Particle index (identifier)
self.pos = pos # Position 3-vector
self.vel = vel # Velocity 3-vector
self.F = F # Net force 3-vector (at particle)
So, I can easily initialize an array containing lots of these objects, and modify each value in a reasonably straightforward way. However as I mentioned, this ran slower for simulations involving only a few particles. I will be playing with my code to compare it to a purely matrix-oriented method to see which one scales better with large simulations.
My question I suppose then is this: Is defining a "particle" in this way the most efficient? Or is there a more CPU/memory efficient way to define such an object. I would like to keep it's method ability (i.e. particle[i].pos = [1,2,3] or particle[2].vx[1] = 3) so I can set values for each particle, as well as pass them through functions. Keep in mind I'm a Python newbie, so I probably won't have great success with large, complex code.
Save memory with __slots__
One way to save memory is using slots:
class Particle(): # Python 3
__slots__ = ['index', 'pos', 'vel', 'F']
def __init__(self, index=0, pos=None, vel=None, F=None):
# Particle index (identifier)
self.index = index
# Position 3-vector
self.pos = np.array([0, 0, 0]) if pos is None else pos
# Velocity 3-vector
self.vel = np.array([0,0,0]) if vel is None else vel
# Net force 3-vector (at particle)
self.F = np.array([0, 0, 0]) if F is None else F
From the docs:
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __slots__ reserves space for the declared variables and prevents the automatic creation of __dict__ and __weakref__ for each instance.
Side note: I fixed the mutable default argument problem by setting them to None and creating a new NumPy array in the __init__() for None values.
Cannot add new attributes to instance
One important difference is that you cannot add attributes after instantiation that are not listed in __slots__:
p = Particle()
p.new_attr = 45
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-664-a970d86f4ca3> in <module>()
1 p = Particle()
2
----> 3 p.new_attr = 45
AttributeError: 'Particle' object has no attribute 'new_attr'
Compare to a class without __slots__:
class A: # Python 3
pass
a = A()
a.new_attr = 10
No exception is raised.
It sounds like you want the flyweight pattern. Maybe store one integer in the object as an index into an array with rows of 9 elements?
I am reading a binary file into a list of class instances. I have a loop that reads data from the file into an instance. When the instance is filled, I append the instance to a list and start reading again.
This works fine except that one of the elements of the instance is a Rect (i.e. rectangle), which is a user-defined type. Even with deepcopy, the attributes are overwritten.
There are work-arounds, like not having Rect be a user-defined type. However, I can see that this is a situation that I will encounter a lot and was hoping there was a straightforward solution that allows me to read nested types in a loop.
Here is some code:
class Rect:
def __init__(self):
self.L = 0
class groundtruthfile:
def __init__(self):
self.rect = Rect
self.ht = int
self.wt = int
self.text = ''
...
data = []
g = groundtruthfile()
f = open("datafile.dtf", "rb")
length = unpack('i', f.read(4))
for i in range(1,length[0]+1): #length is a tuple
g.rect.L = unpack('i',f.read(4))[0]
...
data.append(copy.deepcopy(g))
The results of this are exactly what I want, except that all of the data(i).rect.L are the value of the last data read.
You have two problems here:
The rect attribute of a groundtruthfile instance (I'll just put this here...) is the Rect class itself, not an instance of that class - you should be doing:
self.rect = Rect() # note parentheses
to create an instance, instead (similarly e.g. self.ht = int sets that attribute to the integer class, not an instance); and
The line:
g.rect.L = unpack('i',f.read(4))[0]
explicitly modifies the attribute of the same groundtruthfile instance you've been using all along. You should move the line:
g = groundtruthfile()
inside the loop, so that you create a separate instance each time, rather than trying to create copies.
This is just a minimal fix - it would make sense to actually provide arguments to the various __init__ methods, for example, such that you can create instances in a more intuitive way.
Also, if you're not actually using i in the loop:
for _ in range(length[0]):
is neater than:
for i in range(1,length[0]+1):
How would i go about making a function to create a certain number of uniquely named variables at runtime, based on initial user input? For instance, user enters dimensions 400 x 400, (x and y), so i would want the function to create 1600 (400 * 400) variables, each to represent every different point on a grid 400 by 400.
What you really want is an array, a list or a tuple of 400*400 points.
So create a class that stores the information you want at each point, and then create a list of size 400*400 of those class objects.
You can do it this way:
width = 400
height = 400
m = [[0]*width for i in range(height)]
And then access points in your field like so:
m[123][105] = 7
To set point (123,105) to 7.
If you want to store more than just a number at each point, create a class like I suggested:
class MyClass:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
And then create your list of "MyClass" objects like so:
m = [[MyClass(0,0,0) for i in range(400)] for j in range(400)]
Are you sure you need to create a different variable for each point on the grid? If there are lots of points with default value of say 0, don't create an array with a bunch of 0s. Instead, create an empty dictionary D = {}. Store data as D[(x,y)] = anything. Access your data by D.get((x,y), 0). Where D.get(key, default value) This saves memory.
Btw, 400*400 is not 1600. Rather 160,000