Are properties set in the specified order? - python

Suppose I have a class with 3 instance attributes, 'a', 'b' and 'c', which are initialized each with property setters. Now, my property 'b' assignment should use the value of the instance variable 'a'. So for 'b' to be initialized, 'a' has to be initialized beforehand.
Following the code below, does python set the instance 'a' first, then goes to instance 'b', and then finnally to 'c', or may the initialisation occur in any random order, which might destroy the possibility to sucessfully initialise the variables?
class Foo(object):
def __init__(self):
self.a = None
self.b = None
self.c = None
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
#property
def b(self):
return self._b
#b.setter
def b(self, value):
value = self.a
self._b = value
#property
def c(self):
return self._c
#c.setter
def c(self, value):
value = self.b
self._c = value
I am asking this question in a simplified version because I am having difficulties in a real case. In that case, I used logs to view the execution of the execution of the initialisation, and it appears to me that it starts by executing the last property ('c' in this case), instead of the desired first, 'a'.

__init__ is like any other method in Python; the statements in it are executed in the order given, so in your example code, a is set before b, which is set before c, always.
The Python language spec in general provides stronger ordering guarantees than languages like C/C++ (e.g. a, b, c = d, e, f guarantees that d is read first, then e, then f, and a is set first, then b, then c).
It does not matter if they are properties, plain attributes, or whatever; assignment might do funky things, but those things occur in the order the statements occur.

Related

Defining logic in class constructor to modify instance variable based on other constructor arguments in python

i have a python class in which i have few arguments sent to constructor as below.
class Test(object):
def __init__(self, a, b):
self.a = a
if b<10:
self.a = a*2
I know that, constructors are just meant to initialize variable's and there should be no logic inside a constructor. But, if not this way, how can i set value of "a" variable based a logic with "b" variable. I tried to use property. following is my code
class Test(object):
def __init__(self, a, b):
self.a = a
self.b = b
#property
def a(self):
self._a
#a.setter
def a(self, value):
if self.b < 10:
self._a = value*2
else:
self._a = value
But, problem is that, setter is not called when initializing with a constructor. So, how can i solve this problem of modifying the default setting of few variable inside a constructor

How to dynamically inherit at initialization time?

I have the following class structure:
class Base:
def z(self):
raise NotImplementedError()
class A(Base):
def z(self):
self._x()
return self._z()
def _x(self):
# do stuff
def _a(self):
raise NotImplementedError()
class B(Base)
def z(self):
self._x()
return self._z()
def _x(self):
# do stuff
def _z(self):
raise NotImplementedError()
class C(A):
def _z(self):
print(5)
class D(B):
def _z(self):
print(5)
The implementation of C(A) and D(B) is exactly the same and does not really care which class it inherits from. The conceptual difference is only in A and B (and these need to be kept as separate classes). Instead of writing separate definitions for C and D, I want to be able to dynamically inherit from A or B based on an argument provided at time of creating an instance of C/D (eventually C and D must be the same name).
It seems that metaclasses might work, but I am not sure how to pass an __init__ argument to the metaclass __new__ (and whether this will actually work). I would really prefer a solution which resolves the problem inside the class.
Have you considered using composition instead of inheritance? It seems like it is much more suitable for this use case. See the bottom of the answer for details.
Anyway,
class C(A): ......... class C(B): ..... is not even valid, and will result with only class C(B) getting defined.
I'm not sure a metaclass will be able to help you here. I believe the best way would be to use type but I'd love to be corrected.
A solution using type (and probably misusing locals() but that's not the point here)
class A:
def __init__(self):
print('Inherited from A')
class B:
def __init__(self):
print('Inherited from B')
class_to_inherit = input() # 'A' or 'B"
C = type('C', (locals()[class_to_inherit],), {})
C()
'A' or 'B'
>> A
Inherited from A
'A' or 'B'
>> B
Inherited from B
Composition
Tracking back to the question in the beginning of my answer, you state yourself that the implementation of both "C(A)" and "C(B)" is identical and they don't actually care about A or B. It seems more correct to me to use composition. Then you can do something along the lines of:
class A: pass
class B: pass
class C:
def __init__(self, obj): # obj is either A or B instance, or A or B themselves
self.obj = obj # or self.obj = obj() if obj is A or B themselves
c = C(A()) # or c = C(A)
In case C should expose the same API as A or B, C can overwrite __getattr__:
class A:
def foo(self):
print('foo')
class C:
def __init__(self, obj):
self.obj = obj
def __getattr__(self, item):
return getattr(self.obj, item)
C(A()).foo()
# foo

python: bookkeeping dependencies in cached attributes that might change

I have a class A with three attributes a,b,c, where a is calculated from b and c (but this is expensive). Moreover, attributes b and c are likely to change over times. I want to make sure that:
a is cached once it is calculated and then reproduced from cache
if b or c change then the next time a is needed it must be recomputed to reflect the change
the following code seems to work:
class A():
def __init__(self, b, c):
self._a = None
self._b = b
self._c = c
#property
def a(self):
if is None:
self.update_a()
return self._a
def update_a(self):
"""
compute a from b and c
"""
print('this is expensive')
self._a = self.b + 2*self.c
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
self._a = None #make sure a is recalculated before its next use
#property
def c(self):
return self._c
#c.setter
def c(self, value):
self._c = value
self._a = None #make sure a is recalculated before its next use
however this approach does not seem very good for many reasons:
the setters of b and c needs to know about a
it becomes a mess to write and maintain if the dependency-tree grows larger
it might not be apparent in the code of update_a what its dependencies are
it leads to a lot of code duplication
Is there an abstract way to achieve this that does not require me to do all the bookkeeping myself?
Ideally, I would like to have some sort of decorator which tells the property what its dependencies are so that all the bookkeeping happens under the hood.
I would like to write:
#cached_property_depends_on('b', 'c')
def a(self):
return self.b+2*self.c
or something like that.
EDIT: I would prefer solutions that do not require that the values assigned to a,b,c be immutable. I am mostly interested in np.arrays and lists but I would like the code to be reusable in many different situations without having to worry about mutability issues.
You could use functools.lru_cache:
from functools import lru_cache
from operator import attrgetter
def cached_property_depends_on(*args):
attrs = attrgetter(*args)
def decorator(func):
_cache = lru_cache(maxsize=None)(lambda self, _: func(self))
def _with_tracked(self):
return _cache(self, attrs(self))
return property(_with_tracked, doc=func.__doc__)
return decorator
The idea is to retrieve the values of tracked attributes each time the property is accessed, pass them to the memoizing callable, but ignore them during the actual call.
Given a minimal implementation of the class:
class A:
def __init__(self, b, c):
self._b = b
self._c = c
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
#property
def c(self):
return self._c
#c.setter
def c(self, value):
self._c = value
#cached_property_depends_on('b', 'c')
def a(self):
print('Recomputing a')
return self.b + 2 * self.c
a = A(1, 1)
print(a.a)
print(a.a)
a.b = 3
print(a.a)
print(a.a)
a.c = 4
print(a.a)
print(a.a)
outputs
Recomputing a
3
3
Recomputing a
5
5
Recomputing a
11
11
Fortunately, a dependency management system like this is easy enough to implement - if you're familiar with descriptors and metaclasses.
Our implementation needs 4 things:
A new type of property that knows which other properties depend on it. When this property's value changes, it will notify all properties that depend on it that they have to re-calculate their value. We'll call this class DependencyProperty.
Another type of DependencyProperty that caches the value computed by its getter function. We'll call this DependentProperty.
A metaclass DependencyMeta that connects all the DependentProperties to the correct DependencyProperties.
A function decorator #cached_dependent_property that turns a getter function into a DependentProperty.
This is the implementation:
_sentinel = object()
class DependencyProperty(property):
"""
A property that invalidates its dependencies' values when its value changes
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dependent_properties = set()
def __set__(self, instance, value):
# if the value stayed the same, do nothing
try:
if self.__get__(instance) is value:
return
except AttributeError:
pass
# set the new value
super().__set__(instance, value)
# invalidate all dependencies' values
for prop in self.dependent_properties:
prop.cached_value = _sentinel
#classmethod
def new_for_name(cls, name):
name = '_{}'.format(name)
def getter(instance, owner=None):
return getattr(instance, name)
def setter(instance, value):
setattr(instance, name, value)
return cls(getter, setter)
class DependentProperty(DependencyProperty):
"""
A property whose getter function depends on the values of other properties and
caches the value computed by the (expensive) getter function.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.cached_value = _sentinel
def __get__(self, instance, owner=None):
if self.cached_value is _sentinel:
self.cached_value = super().__get__(instance, owner)
return self.cached_value
def cached_dependent_property(*dependencies):
"""
Method decorator that creates a DependentProperty
"""
def deco(func):
prop = DependentProperty(func)
# we'll temporarily store the names of the dependencies.
# The metaclass will fix this later.
prop.dependent_properties = dependencies
return prop
return deco
class DependencyMeta(type):
def __new__(mcls, *args, **kwargs):
cls = super().__new__(mcls, *args, **kwargs)
# first, find all dependencies. At this point, we only know their names.
dependency_map = {}
dependencies = set()
for attr_name, attr in vars(cls).items():
if isinstance(attr, DependencyProperty):
dependency_map[attr] = attr.dependent_properties
dependencies.update(attr.dependent_properties)
attr.dependent_properties = set()
# now convert all of them to DependencyProperties, if they aren't
for prop_name in dependencies:
prop = getattr(cls, prop_name, None)
if not isinstance(prop, DependencyProperty):
if prop is None:
# it's not even a property, just a normal instance attribute
prop = DependencyProperty.new_for_name(prop_name)
else:
# it's a normal property
prop = DependencyProperty(prop.fget, prop.fset, prop.fdel)
setattr(cls, prop_name, prop)
# finally, inject the property objects into each other's dependent_properties attribute
for prop, dependency_names in dependency_map.items():
for dependency_name in dependency_names:
dependency = getattr(cls, dependency_name)
dependency.dependent_properties.add(prop)
return cls
And finally, some proof that it actually works:
class A(metaclass=DependencyMeta):
def __init__(self, b, c):
self.b = b
self.c = c
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value + 10
#cached_dependent_property('b', 'c')
def a(self):
print('doing expensive calculations')
return self.b + 2*self.c
obj = A(1, 4)
print('b = {}, c = {}'.format(obj.b, obj.c))
print('a =', obj.a)
print('a =', obj.a) # this shouldn't print "doing expensive calculations"
obj.b = 0
print('b = {}, c = {}'.format(obj.b, obj.c))
print('a =', obj.a) # this should print "doing expensive calculations"

Programming dependencies/relationships in python

I am designing a class in python whose properties have a mesh of interdepencies.
Say like it has a property A. When A is set to True then properties B and C can be used. Or else they cant be used. Property B and C may be of any type. May be a boolean or int or string or any custom class.
Also say if B is enabled then we can have either properties D or E or F ( a checkbox like behaviour).
How do i design such dependencies in python class?.
Also i may have similar classes which have such dependencies.. So i am thinking of making a metaclass or baseclass or template like design where user will specify dependencies and code is internally generated.
Any design inputs on how to proceed?
I'm not sure exactly what you mean by "designing dependencies", but I'd just give the class some methods decorated with the #property tag that check self.a and self.b prior to returning some value.
class Foo:
def __init__(self, a):
self.a = a
#property
def b():
return "b" if self.a else None
#property
def c():
return "c" if self.a else None
#property
def d():
return "d" if self.b else None
#property
def e():
return "e" if self.b else None
#property
def f():
return "f" if self.b else None

How can I call methods between two classes?

I have a class A. During the __init__ method of an instance of A;
I create these following two instances of classes B and C:
b = B()
c = C()
Once all's set, I need to call, within a method of B, a method from C.
Example:
Triggered:
b.call_c()
Does:
def call_c(self):
parent.c.a_method_of_c()
What do I need to do to achieve this structure?
You need to pass either of self or c to B() so that it can know about the other object.
Here is how this looks if you pass the A object to both B and C as a parent/container object:
class A(object):
def __init__(self):
self.b = B(self)
self.c = C(self)
class B(object):
def __init__(self, parent):
self.parent = parent
def call_c(self):
self.parent.c.a_method_of_c()
class C(object):
def __init__(self, parent):
self.parent = parent
# whatever...
Or, you can just pass the C instance to B's initializer like this:
class A(object):
def __init__(self):
self.c = C()
self.b = B(self.c)
class B(object):
def __init__(self, c):
self.cobj = c
def call_c(self):
self.cobj.a_method_of_c()
class C(object):
# whatever...
I like the second approach better, since it cuts out the dependencies of B and C on A, and the necessity of A to implement b and c attributes.
If B and C have to call methods on each other, you can still use A to make these associations, but keep B and C ignorant of A:
class A(object):
def __init__(self):
self.b = B()
self.c = C()
self.b.cobj = self.c
self.c.bobj = self.b
class B(object):
def __init__(self, c):
self.cobj = None
def call_c(self):
if self.cobj is not None:
self.cobj.a_method_of_c()
else:
raise Exception("B instance not fully initialized")
class C(object):
# similar to B
In general, your goal is to try to avoid or at least minimize these dependencies - have a parent know about a child, but a child be ignorant of the parent. Or a container knows its contained objects, but the contained objects do not know their container. Once you add circular references (back references to a parent or container object), things can get ugly in all kinds of surprising ways. A relationship can get corrupted when one of the links gets cleared but not the reflecting link. Or garbage-collection in circular relations can get tricky (handled in Python itself, but may not be handled if these objects and relations are persisted or replicated in a framework).
I need to call, within a method of B, a method from C.
Basically, if the method is not a class method or a static method, then calling a method always means that you have access to the (c) object of the C class.
Have a look at the example:
#!python3
class B:
def __init__(self, value):
self.value = value
def __str__(self):
return 'class B object with the value ' + str(self.value)
class C:
def __init__(self, value):
self.value = value
def __str__(self):
return 'class C object with the value ' + str(self.value)
class A:
def __init__(self, value):
self.value = value
self.b = B(value * 2)
self.c = C(value * 3)
def __str__(self):
lst = ['class A object with the value ' + str(self.value),
' containing the ' + self.b.__str__(),
' containing also the ' + str(self.c),
]
return '\n'.join(lst)
a = A(1)
print(a)
print(a.b)
print(a.c)
The self.b.__str__() is the example of calling the method of the object of the B class from the method of the object of the A class. The str(self.c) is the same, only called indirectly via the str() function.
The following is displayed:
class A object with the value 1
containing the class B object with the value 2
containing also the class C object with the value 3
class B object with the value 2
class C object with the value 3

Categories

Resources