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.
Related
Let's say I have the following classes:
import math
class LineSegment:
def __init__(
self,
origin,
termination,
):
self.origin = origin
self.termination = termination
self.length = self.calculate_length()
def calculate_length(self):
return math.sqrt(
(self.origin.x - self.termination.x) ** 2
+ (self.origin.y - self.termination.y) ** 2
)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
An object of the LineSegment class is composed of two objects of the Point class. Now, let's say I initialize an object as so:
this_origin = Point(x=0, y=0)
this_termination = Point(x=1, y=1)
this_line_segment = LineSegment(origin=this_origin, termination=this_termination)
Note: The initialization of the line segment automatically calculates its length. This is critical to other parts of the codebase, and cannot be changed. I can see its length like this:
print(this_line_segment.length) # This prints "1.4142135623730951" to the console.
Now, I need to mutate one parameter of this_line_segment's sub-objects:
this_line_segment.origin.x = 1
However, the this_line_segments length attribute does not update based on the new origin's x coordinate:
print(this_line_segment.length) # This still prints "1.4142135623730951" to the console.
What is the pythonic way to implement updating a class's attributes when one of the attributes they are dependent upon changes?
Option 1: Getter and Setter Methods
In other object-oriented programming languages, the behavior you desire, adding additional logic when accessing the value of an instance variable, is typically implemented by "getter" and "setter" methods on all instance variables in the object:
class LineSegment:
def __init__(
self,
origin,
termination,
):
self._origin = origin
self._termination = termination
# getter method for origin
def get_origin(self):
return self._origin
# setter method for origin
def set_origin(self,new_origin):
self._origin = new_origin
# getter method for termination
def get_termination(self):
return self._termination
# setter method for termination
def set_termination(self,new_termination):
self._termination = new_termination
def get_length(self):
return math.sqrt(
(self.get_origin().x - self.get_termination().x) ** 2
+ (self.get_origin().y - self.get_termination().y) ** 2
) #Calls the getters here, rather than the instance vars in case
# getter logic is added in the future
So that the extra length calculation is performed every time you get() the length variable, and instead of this_line_segment.origin.x = 1, you do:
new_origin = this_line_segment.get_origin()
new_origin.x = 1
this_line_segment.set_origin(new_origin)
print(this_line_segment.get_length())
(Note that I use _ in front of variables to denote that they are private and should only be accessed via getters and setters. For example, the variable length should never be set by the user--only through the LineSegment class.)
However, explicit getters and setters are clearly a clunky way to manage variables in Python, where the lenient access protections make accessing them directly more transparent.
Option 2: The #property decorator
A more Pythonic way to add getting and setting logic is the #property decorator, as #progmatico points out in their comment, which calls decorated getter and setter methods when an instance variable is accessed. Since all we need to do is calculate the length whenever it is needed, we can leave the other instance variables public for now:
class LineSegment:
def __init__(
self,
origin,
termination,
):
self.origin = origin
self.termination = termination
# getter method for length
#property
def length(self):
return math.sqrt(
(self.origin.x - self.termination.x) ** 2
+ (self.origin.y - self.termination.y) ** 2
)
And usage:
this_line_segment = LineSegment(origin=Point(x=0,y=0),
termination=Point(x=1,y=1))
print(this_line_segment.length) # Prints 1.4142135623730951
this_line_segment.origin.x = 1
print(this_line_segment.length) # Prints 1.0
Tested in Python 3.7.7.
Note: We must do the length calculation in the length getter and not upon initialization of the LineSegment. We can't do the length calculation in the setter methods for the origin and termination instance variables and thus also in the initialization because the Point object is mutable, and mutating it does not call LineSegment's setter method. Although we could do this in Option 1, it would lead to an antipattern, in which we would have to recalculate every other instance variable in the setter for each instance variable of an object in the cases for which the instance variables depend on one another.
I was wondering if all self. has to be defined in __init__, for example, i have this code right here:
class Colour:
def __init__(self, r, g, b):
self._red = r
self._green = g
self._blue = b
self._rgb = (self._red, self._green, self._blue)
def luminosity(self):
self._luminosity = 0.5 * ((max(self._red, self._green, self._blue))/255)+((min(self._red, self._green, self._blue))/255)
return self._luminosity
Am i right to define self.luminosity in the function def luminosity(self) or should i define it in __init__?
In this case, you don't need to define it, because it's only set and then returned when you could directly return the calculated value from your method!
Additionally, you can simplify the calculation a little, though I am not sure it is really luminosity, as there are a variety of interpretations different to yours
def luminosity(self):
return 0.5 * (
max(self._red, self._green, self._blue) + \
min(self._red, self._green, self._blue)
) / 255
If instead, you were caching the value (which may make sense if you do a more complex calculation or call the luminosity method many times), it would make sense to set it in __init__() and check before calculating (effectively caching the last call)
As #laol suggests, you can also use #property to simplify some of the its use
And finally, you can take advantage of your combined RGB for the calculation
class Colour():
def __init__(self, r, g, b):
self._red = r
self._green = g
self._blue = b
self._luminosity = None
#property
def rgb(self):
return (self._red, self._green, self._blue)
#property
def luminosity(self):
if self._luminosity is None:
self._luminosity = 0.5 * (max(self.rgb) + min(self.rgb)) / 255
return self._luminosity
c = Colour(128,100,100)
print(c.luminosity)
0.44705882352941173
Extending this even further, setting new values for the color components can set the cached value back to None, triggering re-calculation on the next call (rather than immediately, saving some calculation if many changes are made before the value is wanted), but this is left as an exercise to the reader
I suggest to define it as a property:
#property
def luminosity(self):
return 0.5 * ((max(self._red, self._green, self._blue))/255)+((min(self._red, self._green, self._blue))/255)
By this you can directly return it from any Colour c by
c.luminosity
No, instance variables do not need to be defined in __init__. Instance variables are completely dynamic and can be added any time either in a method or outside of the object (see note). However, if you don't define them, you have created an object access protocol that needs to be managed. Suppose another method is added:
def half_luminosity(self):
return self._luminosity/2
It is an error to call it before luminosity. This code will raise AttributeError if its called at the wrong time. You could assign self._luminosity = None in __init__ and check it
def half_luminosity(self):
if self._luminosity is None:
raise ValueError("Attempt to use luminosity before set")
but that's not much different than
def half_luminosity(self):
if not hasattr(self, '_luminosity'):
raise ValueError("Attempt to use luminosity before set")
If you have a class that is setup in more than one step, either way will do. PEP8 favors the first because its easier for a futurer reader to see what's going on.
NOTE: Classes that use __slots__ or one of the getattr methods can change the rules as can C extensions.
I know first argument in Python methods will be an instance of this class. So we need use "self" as first argument in methods. But should we also specify attribures (variables) in method starting with "self."?
My method work even if i don't specify self in his attributes:
class Test:
def y(self, x):
c = x + 3
print(c)
t = Test()
t.y(2)
5
and
class Test:
def y(self, x):
self.c = x + 3
print(self.c)
t = Test()
t.y(2)
5
For what i would need specify an attribute in methods like "self.a" instead of just "a"?
In which cases first example will not work but second will? Want to see situation which shows really differences between two of them, because now they behave the same from my point of view.
The reason you do self.attribute_name in a class method is to perform computation on that instances attribute as opposed to using a random variable.For Example
class Car:
def __init__(self,size):
self.size = size
def can_accomodate(self,number_of_people):
return self.size> number_of_people
def change_size(self,new_size):
self.size=new_size
#works but bad practice
def can_accomodate_v2(self,size,number_of_people):
return size> number_of_people
c = Car(5)
print(c.can_accomodate(2))
print(c.can_accomodate_v2(4,2))
In the above example you can see that the can_accomodate use's self.size while can_accomodate_v2 passes the size variable which is bad practice.Both will work but the v2 is a bad practice and should not be used.You can pass argument into a class method not related to the instance/class for example "number_of_people" in can_accomodate funtion.
Hope this helps.
I have the following Python code to represent the velocity of an object.
class Vector(object):
def __init__(self, x, y):
self.x, self.y = x, y
class Physics(object):
def __init__(self, velocity):
self.velocity = velocity
#property
def velocity(self):
return self._velocity
#velocity.setter
def velocity(self, velocity):
self._velocity = velocity
self._hi_res_velocity = Vector(velocity.x * 1000, velocity.y * 1000)
My intent is for velocity.x to set both _velocity.x and _hi_res_velocity.x, but the setter isn't run in this case. I get the following:
>>> myObject = Physics(Vector(10, 20))
>>> myObject.velocity.x = 30
>>> myObject._velocity.x, myObject._hi_res_velocity.x
(30, 10000)
I think the getter for velocity is run and then x is set on that returned value, but is it possible to implement the behavior I want using properties? I feel like I'll have to rewrite my logic to make this work.
When you do this:
myObject.velocity.x = 30
|_______________|
|
|___ this part already resolved the property
The myObject.velocity is already returning a Velocity instance, and this happens first. Then the .x which follows is just a normal attribute access, since the Vector class doesn't define a descriptor for handling x.
I'll suggest a different design, make either the "velocity" or the "hi_res_velocity" a getter-only, i.e. one of them is computed from the other whenever needed. This will resolve your issue, and also has the advantage that you don't have to store the same state twice.
I would like to be able to add to a custom class in the style of:
x=myclass("Something", 7)
x + 3
7, of course, corresponds with an inner property that I'd like to increment by adding to it.
The class holds a number that refers to a location in a list. This might seem like something that can be done by a normal integer, but I need it to act as a separate type. This is all done to emulate an old game language. The class is its 'variable' class, and the value of the variable is stored in the aforementioned list. Apparently, on older version of the game, arrays were faked by doing math on the variable object instance to grab a different variable. So I'm trying to emulate that.
If you want to support addition for class instances, you need to define an __add__() method on your class:
class MyClass(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other
Example:
>>> a = MyClass(7)
>>> a + 3
10
To also support 3 + a, define the __radd__() method.
If you want to be able to update the x attribute of MyClass instances using
a += 3
you can define __iadd__().
If you want class instances to behave like integers with some additional methods and attributes, you should simply derive from int.
What you're looking to do is operator overloading. You can do this in python new style classes by overloading the __add__ method like so:
>>> class Test(object):
... def __init__(self): self.prop = 3
... def __add__(self, x):
... return self.prop + x
...
>>> Test() + 4
7
>>>