Python setter not executed when setting nested property - python

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.

Related

Updating Dependent Attributes After Mutation

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.

How to set class atributes for all objects?

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.

Return different objects from a method, depending on whether method parameter is present

I am creating a class with a number of methods, as one of the steps, I want to change one of the args to call the new version in a different method from the class.
I am sure it’s something simple but I just can’t figure out where it is going wrong.
For brevity, I have tried to make a simple example from what I am actually coding.
class Double:
def __init__(self, x):
self.x = x
def double(self):
self.x = self.x * 2
# change the x item to x*2
return self.x
def return1(self, xg=x):
# if xg isn’t defined by user, this method should return
# the new version of x created above
return xg
I would also appreciate any other feedback on my class coding.
It is not clear what you are trying to accomplish and there is probably a better design, but to answer your question, you can use the following idiom:
def return1(self, xg=None):
return xg if xg is not None else self.x

What's the Pythonic way to initialize, set and get my custom object's attributes, by name?

I'm quite new to Python and I need to make declare my own data structure, I'm a bit confused on how to do this though. I currently have:
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position, self.velocity, self.force = position, velocity, force
def __getitem__(self, mass):
return self.mass
def __getitem__(self, position):
return self.position
def __getitem__(self, velocity):
return self.velocity
def __getitem__(self, force):
return self.force
This isn't working, however, when I try to define an instance of the class with:
p1 = Particle(mass, position, velocity, force)
Every value just ends up as a (0.0, 0.0) (which is the value for velocity and force).
Could someone explain where I'm going wrong, all I need from the data structure is to be able to pull the data out of it, nothing else. (edit: actually, sorry, I will have to change them a bit later on)
Thanks
First off, you should understand that __getitem__ is syntactic sugar. It's nice to have, but if you don't need it, don't use it. __getitem__ and __setitem__ are basically if you want to be able to access items from your object using bracket notation like:
p= Particle(foo)
bar = p[0]
if you don't need to this, don't worry about it.
Now, onto everything else. It looks like you've got the main characteristics you want your object to carry around in your __init__ definition, which is fine. Now you need to actually bind those values onto your object using self:
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
That's really it. You can now access these values using dot notation, like so:
mass,pos,vel,f = 0,0,0,0 # just for readability
p = Particle(mass,pos,vel,f)
print p.mass, p.position, p.velocity, p.force
One of the nice things we get out of this is that if we ask python what p is, it will tell you that it is an instance of the Particle type, like so:
in [1]: p
out[1]: <__main__.Particle instance at 0x03E1fE68>
In theory, when you work with objects like this you want there to be a "layer of abstraction" between the user and the data such that they don't access or manipulate the data directly. To do this, you create functions (like you tried to do with __getitem__) to mediate interactions between the user and the data through class methods. This is nice, but often not necessary.
In your simpler case, to update the values of these attributes, you can just do it directly the same way we accessed them, with dot notation:
in [2]: p.mass
out[2]: 0
in [3]: p.mass = 2
in [4]: p.mass
out[4]: 2
You might have figured this out already, but there's nothing magical about the __init__ function, or even the class definition (where you would/should generally be defining most of your class's attributes and methods). Certain kinds of objects are pretty permissive about allowing you to add attributes whenever/wherever you want. This can be convenient, but it's generally very hacky and not good practice. I'm not suggesting that you do this, just showing you that it's possible.
in [5]: p.newattr ='foobar!'
in [6]: p.newattr
out[6]: 'foobar!'
Weird right? If this makes your skin crawl... well, maybe it should. But it is possible, and who am I to say what you can and can't do. So that's a taste of how classes work.
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
particle = Particle(1, 2, 3, 4)
print(particle.mass) # 1
If you want to pretend your class has properties, you can use the #property decorator:
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
#property
def acceleration(self):
return self.force / self.mass
particle = Particle(2, 3, 3, 8)
print(particle.acceleration) # 4.0
Seems like collections.namedtuple is what you're after:
from collections import namedtuple
Particle = namedtuple('Particle', 'mass position velocity force')
p = Particle(1, 2, 3, 4)
print p.velocity
you can just put this class definition ahead before you use it. If you want to declare it, check this site: http://www.diveintopython.net/getting_to_know_python/declaring_functions.html
By the way, your question is similar to this post: Is it possible to forward-declare a function in Python? and also this post: Is it possible to use functions before declaring their body in python?
If you just need to store some attribute values (similar to a C-language struct), you can just do:
class myContainer(object):
pass # Do nothing
myContainerObj = myContainer()
myContainerObj.storedAttrib = 5
print myContainerObj.storedAttrib
In Python 3.7+ there is the data class library. This library will allow you to create your own class to hold data quickly using a decorator, #dataclass.
The #dataclass decorator allows you to quickly define and add functionality to a class you intend to mostly be used to hold data.
A data class for your problem might be implemented as below. I've included type hints and default values which you might also find helpful.
from dataclasses import dataclass
#dataclass
class Particle:
mass: float
position: float
velocity: float = 0.0
force: float = 0.0
Here is a useful article which explains how to use data classes in Python 3.7+ and some other features.

Python class variable access speed

Say there is a class:
class x(obj):
y = 1
What is faster (or preferred):
def __init__(self):
print self.y
or:
def __init__(self):
print x.y
I assume x.y better communicates the intend but I'm interested in the speed implications.
The performance gain you could possibly achieve with these micro optimizations doesn't matter. The impact of the printing dwarfs the cost of attribute access by far. For reference, here's a test script:
import sys,timeit
class ClassAccess(object):
y = 1
def __init__(self):
print(ClassAccess.y)
class SelfAccess(object):
y = 1
def __init__(self):
print(self.y)
ca = timeit.timeit(ClassAccess, number=100000)
sa = timeit.timeit(SelfAccess, number=100000)
sys.stderr.write(str(ca) + "\n")
sys.stderr.write(str(sa) + "\n")
On my machine (with the yakuake terminal), this outputs
0.640013933182
0.628859043121
This is within experimental error of both variants being identical. Crude experimentation shows that:
Approximately 90% of the runtime is caused by actually displaying the printed result.
Of the rest, approximately 50% is the time that the print statement alone takes up.
Approximately 80% of the rest of that is caused by the allocation of the objects.
Therefore, it's safe to say to derive the conclusion that there is no difference in performance.
Note that depending on the class implementation the returned values may differ.
This returns the y attribute of the instance :
def __init__(self):
print self.y
While this returns the y attribute of the class :
def __init__(self):
print x.y
If the constructor override the y attribute a la :
def __init__(self, y=None):
self.y = y
def print(self):
print self.y
the returned values will differ.
Python looks up the instance internal dictionary checking for y before to check for the class internat dictionary.
So I think that print x.y should be slightly faster because it avoids looking up the instance dictionary.

Categories