For example, if I have two classes :
class A:
def __init__(self):
self.a = 1;
def update(self, val):
self.a = val;
class B:
def __init__(self, default = A()):
self.b = default.a;
Using them :
object_a = A(); object_b = B(object_a);
Then, I would like to update the object_a.a attribute using object_a.update(update_val) but also concurrently update at all other dependent objects (object_b.b will also be updated to update_val).
How to do this in Python, is there a 'built-in' way?
I already have some manual solutions in mind, such as:
class A:
def __init__(self):
self.a = 1;
self.dependent = None;
def update(self, val):
self.a = val;
if self.dependent != None:
self.dependent.b = self.a;
class B:
def __init__(self, default = A()):
default.dependent = self;
self.b = default.a;
One way to accomplish what you are asking is use a mutable object, such as a list, to store the attribute's data. Since the objects will reference the list, changing the values of the list will be shared to both objects.
Here is a version that uses a list to store the underlying value, but maintains the attribute behavior .a and .b
class A:
def __init__(self):
self._a = [1]
def update(self, val):
self._a[0] = val
#property
def a(self):
return self._a[0]
class B:
def __init__(self, default):
self._b = default._a
#property
def b(self):
return self._b[0]
a = A()
b = B(a)
a.update(4)
b.b
# returns:
4
Related
After creating an object(second) inside an object(first) i want to get access to the first object. Is this possible without giving the second object the first object as an attribute?
In the code below i have access to my first object. I'm just curious if there is a better way to achive something similiar, without pass on my first object to my second object.
class first():
def __init__(self,v):
self.a = v
self.b = second(self)
class second():
def __init__(self, first):
self.changefirst(first)
def changefirst(self,first):
first.a = 5
x = first(3)
print(x.a)
Output:
5
You can use a method within first, like this :
class first:
def __init__(self, v):
self.a = v
self.b = second()
self.update_a(5)
def update_a(self, val):
self.a = val
class second:
def __init__(self):
pass
x = first(3)
print(x.a)
5
Now, if you want to trigger the update of a from b, you have to pass self since the attributes are attached to it.
Another way :
class first:
def __init__(self, v):
self.a = v
self.b = second(self)
def update_a(self, val):
self.a = val
class second:
def __init__(self, that):
that.update_a(5)
I have a class and a sub-class, I'd like to pass the whole of the self of the class to the sub-class. I can pass self over to the new class explicitly easily enough, e.g.
class foo:
def __init__(self, a, b):
self.a = a
self.b = b
self.c = 'foo'
def foo_method(self):
print('a foo method')
class bar(foo):
def __init__(self, foo_object):
self.a = foo_object.a
self.b = foo_object.b
self.c = foo_object.c
def bar_method(self):
print('a bar method')
foo_object = foo(a = 'a', b = 'b')
bar_object = bar(foo_object)
bar_object.a
Is there a more succinct way to pass these over? Something like:
class bar(foo):
def __init__(self, foo_object):
self = self.foo_object
Update:
Thanks https://stackoverflow.com/users/10104112/bastien-antoine, the following solution worked:
class bar(foo):
def __init__(self, foo_object):
self.__dict__ = foo_object.__dict__.copy()
def bar_method(self):
print('a bar method with ' + str(self.c))
Have you tried the copy builtins library?
Otherwise I think you can easily implement your own .copy() method that would copy the values from the old object __dict__ to the new one. Something like this:
class MyObject:
a = None
def set_default_values(self):
self.a = 1
def copy(self, old):
if type(self) == type(old):
self.__dict__ = old.__dict__.copy()
else:
raise TypeError('Wrong type')
if __name__ == "__main__":
obj_1 = MyObject()
print(obj_1.a)
obj_1.set_default_values()
print(obj_1.a)
obj_2 = MyObject()
print(obj_2.a)
obj_2.copy(obj_1)
print(obj_2.a)
Note that I've added a type checking to be sure that you copy attributes that would exist otherwise, but I think simply self.__dict__ = old.__dict__.copy() would work fine, thought you might end up with attributes you might not suppose to have in the new object.
Hope this helps!
I think that you can do that with
class bar(foo):
def __init__(self):
super(bar, self).__init__()
with this code, you ran the init function for the subclass
I have two python classes:
class A:
def __init__(self, param1):
self.param1 = param1
class B:
def __init__(self, a):
self.a = a
Now I have an instance of B and need to access param1, I can just write b.a.param1. But the goal is to omit the 'a' part, so access this param with b.param1. I could add property to class B, but I am searching for generic solution - when A class has a lot variables. Is it possible? And would it be clean solution?
This is not the most elegant option and probably a bad practice but you can copy all the attributes of a to be attributes of b using getattr and setattr:
import inspect
class A:
def __init__(self, param1):
self.param1 = param1
class B:
def __init__(self, a):
self.a = a
variables = [i for i in dir(a) if not inspect.ismethod(i) and i[:2] != '__']
for var in variables:
setattr(self, var, getattr(a, var))
This way you can access a's attributes directly:
a = A(1)
b = B(a)
b.param1
which will return
1
I have a class that takes a single parameter a on instantiation, which is stored in the _a attribute. For a number of methods (operators), I need to set also a _b attribute on the result. This is currently implemented in a straight-forward way:
class SomeClass(object):
def __init__(self, a=0):
self._a = a
self._b = 0
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
Now, I have an number of members like _b, such as _c and _d, so __add__ will need an extra line for each of these attributes. Being able to pass these on object instantiation would result in cleaner code:
class SomeClass(object):
def __init__(self, a=0, _b=0):
self._a = a
self._b = 0
def __add__(self, other):
return self.__class__(_b=self._a + other._a)
However, I don't want the user to pass values for all of the parameters, except for a as _b, _c and _d are implementation specifics. I could simply state in the docstring not to pass more than one argument. Preceding the 'private' attributes with an underscore is intended to reflect this.
Alternatively, I can try to make it harder for the user to misbehave, by providing a second, private constructor:
class SomeClass(object):
def __init__(self, a=0):
self._a = a
self._init()
def _init(self, _b=0):
self._b = _b
#classmethod
def _constructor(cls, a, _b):
obj = cls(a)
obj._init(b)
return obj
def __add__(self, other):
return self.__class__._constructor(_b=self._a + other._a)
I'm thinking this is a rather clunky solution.
What would be the preferred way to solve this problem? Are there other, more elegant, solutions? Is this really a problem; should I just use the first option and end up with some more lines of code?
The _ underscore convention is clear and prevalent through the python world.
You document your 'public' attributes, and just use default arguments with underscores to your __init__ method. Keep it simple.
If someone wants to screw up a class by using those private parameters anyway, you are not going to stop them, not in Python.
To tidy it up a tiny bit, you could set _b before __init__:
class SomeClass(object):
_b = 0
def __init__(self, a=0):
self._a = a
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
Or if there are heaps of private variables, put them into a list and do some magic?
class SomeClass(object):
calculated_vars = ['_b'] # All your calculated variables
def __init__(self, a=0):
self._a = a
def __getattr__(self, k):
if k in self.calculated_vars:
return 0 # Default value for calculated variables
else:
raise AttributeError('{} not found'.format(k))
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
if __name__ == '__main__':
i = SomeClass(1)
print '_a attr: ', i._a # 1
print '_b attr: ', i._b # 0 (Default value)
print '_c attr: ', i._c # AttributeError: _c not found
i2 = SomeClass(3)
i3 = i + i2
print '_b attr: ', i3._b # 4 (Calculated value)
class A()
att = B()
class B()
...
a = A()
b = B()
a.att = b
How can b get reference of a ? I need to get an attribute of a here.
Thanks!
You can make a generic "Reference()" class, that keep any reference of itself in an attributes dictionnary.
class Reference(object):
def __init__(self):
self.references = {}
def __setattr__(self, key, value):
if hasattr(self, 'references'):
if isinstance(value, Reference):
if not key in value.references:
value.references[key] = []
value.references[key].append(self)
elif value is None and hasattr(self, key):
old = getattr(self, key).references
if key in old and self in old[key]:
old[key].remove(self)
super(Reference, self).__setattr__(key, value)
And then, create your classes :
class A(Reference):
def __init__(self):
super(A, self).__init__()
self.att = None
class B(Reference):
def __init__(self):
super(B, self).__init__()
self.att = None
And use it :
a = A()
b = B()
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {}
a.att = b
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {'att': [<__main__.A object at 0x7f731c8fc910>]}
At the end, you'll have back reference to all Reference class from any properties
Easiest way would be to just add an extra function parameter to the method in B that needs A, and pass it through when called. Or, just make B's init take an A as argument, and change the bit in A's init to be att = B(self)
class A(object):
def __init__(self):
self.att = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
a.att.a is a
Or another way,
class A(object):
def __init__(self, b):
b.a = self
self.att = b
class B(object):
pass
a = A(B())
a.att.a is a
This code doesn't make a lot of sense... but if I correctly understand your question...
class A(object):
pass #or whatever you like
class B(object):
def __init__(self, ref): #accept one argument
self.ref = ref
a = A()
b = B(a) #pass `a` as that argument
a.att = b
Might be one answer.
class A(object):
def __init__(self):
self._att=None
#property
def att(self):
return self._att
#att.setter
def att(self, value):
self._att = value
value.parent = self
class B(object):
pass
a = A()
b = B()
a.att = b
print b.parent