Reputation: 53
I need to change object variable directly from inherited class. Here is my code example:
class A(object):
def __init__(self,initVal=0):
self.myVal = initVal
def worker(self):
self.incrementor = B()
self.incrementor.incMyVal(5)
class B(A):
def incMyVal(self,incVal):
super().myVal += incVal
obj = A(5)
print(obj.myVal)
obj.worker()
print(obj.myVal)
But it doesn't work:
AttributeError: 'super' object has no attribute 'myVal'
I also tried to use global/nonlocal keywords with my variable in B class, but no luck.
In my main case, the B
class is an event handler. And it should change the attribute of an object when an event fires. So I'm not able to use return
in the incMyVal
method.
Upvotes: 0
Views: 2047
Reputation: 1121744
super()
can only search for class attributes in the class MRO, not instance attributes. myVal
is set on an instance of the class, not on a class itself.
There is only ever one instance; it doesn't matter if code from class A
or a derived class is altering attributes on an instance, it is just one namespace.
However, in your case, you shouldn't even be using inheritance. You are trying to use an independent, second instance to alter the attributes of an instance of A
. Class inheritance doesn't give you access to instances of the base class like this.
Refactor B
to take an instance of A
, then act on that instance:
class B:
def __init__(self, ainstance):
self.ainstance = ainstance
def incMyVal(self, incVal):
self.ainstance.myVal += incVal
Note that B
is not a subclass of A
here; it is not a (specialised) object of the same type at all; it is a different kind of thing, something that increments attributes of another object.
Pass in the instance when you create an instance of B
:
def worker(self):
self.incrementor = B(self)
self.incrementor.incMyVal(5)
This does create a circular reference, which can keep objects alive for longer than perhaps needed. You may want to use a weak reference instead:
import weakref
class B:
def __init__(self, ainstance):
self.ainstance_ref = weakref.ref(ainstance)
def incMyVal(self, incVal):
ainstance = self.ainstance_ref()
if ainstance is not None:
ainstance.myVal += incVal
Now B
instances only hold a weak reference to their A
instance, and will do nothing if that instance no longer exists.
Upvotes: 3