I have this code:
class main():
params = {}
class a(main):
def __init__(self):
self.params['test'] = "111aa"
print self.params
class b(main):
def __init__(self):
self.params['be'] = "222bbb"
print self.params
a()
#{'test': '111aa'}
b()
#{'test': '111aa', 'be': '222bbb'}
I need from b to print only {'be': '222bbb'}
Is there any way how to do it ?
Thanks
Try this:
class main(object): # use new-style classes!
def __init__(self):
self.params = {}
class a(main):
def __init__(self):
super(a, self).__init__()
self.params['test'] = "111aa"
print self.params
class b(main):
def __init__(self):
super(b, self).__init__()
self.params['be'] = "222bbb"
print self.params
Notice that in your code params was defined as a class attribute. By defining it in __init__ of the superclass, we're stating that it's an instance attribute. Also notice that the subclasses call __init__ on the superclass.
In this way, we're making sure that each instance has its own params attribute, without sharing it. You can't expect to share an object between instances and have each one with different values for it, it's a contradiction.
Related
I am trying to call an instance variable from a "parent" class (subclass) to it's "child" class (subsubclass)
class mainclass():
def __init__(self):
self.mainclassvar1 = "mainclass"
class subclass(mainclass):
def __init__(self):
self.subclassvar1 = "subclass"
def changeval(self):
self.subclassvar1 = "subclassedited"
class subsubclass(subclass):
def __init__(self):
self.subsubclassvar1 = subclass.subclassvar1 #<- naturally this fails
def handler():
main=mainclass()
sub = subclass()
sub.changeval()
subsub = subsubclass()
print(subsub.subsubclassvar1)# <- how do I achieve this? I would expect "subclassedited" but it doesn't
if __name__ == "__main__":
handler()
The above does not work obviously but I am trying to show what I am trying to achieve in my head.
if I change the class subsubclass(subclass) as follows it semi-works:
class subsubclass(subclass):
def __init__(self):
subclass.__init__(self)
self.subsubclassvar1 = self.subclassvar1
however the returned value is the original default value of subclass instead of the expected subclassedited.
I am not sure if I should even be trying to do this but I've got some code where the logic has now come to this point and I want to try see if I can get details from the middle class in to the final child class in their final modified states instead of the defaults and without refactoring a lot of code.
Each __init__ method should be invoking the parent's __init__ method, so that the instance is properly initialized for all the classes in the hierarchy.
class mainclass:
def __init__(self):
super().__init__()
self.mainclassvar1 = "mainclass"
class subclass(mainclass):
def __init__(self):
super().__init__()
self.subclassvar1 = "subclass"
def changeval(self):
self.subclassvar1 = "subclassedited"
class subsubclass(subclass):
def __init__(self):
super().__init__()
# Not sure why you would really need this, but...
self.subsubclassvar1 = self.subclassvar1
There's no reason, though that subsub.subclassvar1 should be related to sub.subclassvar1, though. Calling sub.changeval() has nothing to do with subsub.
I am trying to make it to where I can have multiple child classes from, for example class a, and I want all of the variables declared in class a's __init__ method to be in all of the child classes, while also not needing to enter any *args into the __init__ method.
My example parent class is:
class a:
def __init__(self):
self.t = 5
and my example child class is:
class c(a):
def __init__(self):
super().__init__()
does class c have the variable t from class a?
Would it be equal to 5?
While messing around with this, I get the error AttributeError: type object 'c' has no attribute 't', but shouldn't super().__init__() get the variable t from class a and make it to where class c has it too?
Yes, you're right, but the error occurs because you trying to access t on the class itself and not its instance. The following should work:
inst = c()
print(inst.t) # 5
class A:
def __init__(self):
self.a = 1
class B(A):
def __init__(self):
super().__init__()
self.b = self.a
print(self.b)
if __name__ == '__main__':
B()
Code example like this. You'll get 1 in command line. So just use self.attr.
Here's an example of what I'm trying to do:
class Parent():
def __init__():
self.parent_var = 'ABCD'
x = Child(self) # self would be passing this parent instance
class Child():
def __init__(<some code to pass parent>):
print(self.parent_var)
foo = Parent()
Now I know what you're thinking, why not just pass parent_var itself to the child instance? Well my actual implementation has over 20 class variables in Parent. I don't want to have to manually pass each variable to the __init__ of the Child instance that's instantiated in Parent-- is there a way to make all Parent class variables available to Child?
EDIT - SOLVED:
This is the way I found that works:
class Parent():
def __init__(self):
self.parent_var = 'ABCD' # but there are 20+ class vars in this class, not just one
x = Child(self) # pass this parent instance to child
class Child():
def __init__(self, parent):
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()
If you inherit from the parent class all variables will be present in child classes. Use super init in the child to make sure the parent class instantiates.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
class Child(Parent):
def __init__(self):
super().__init__()
child = Child()
print(child.parent_var)
prints:
'ABCD'
You would pass the instance of Parent like you would any value.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
x = Child(self)
class Child:
def __init__(self, obj):
print(obj.parent_var)
Found a solution and wanted to post the answer in case anyone who finds this needs it:
class Parent():
def __init__(self):
self.parent_var = "ABCD" # just an example
x = Child(self) # pass this parent instance (this object) to child
class Child():
def __init__(self, parent):
# copies variables from passed-in object to this object
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()
I have a class scheme with 2-levels of inheritance. My expectation is that each class constructor would run through- and yet the mid-level class constructor never seems to get hit. What's missing here?
class Base(object):
def __init__(self):
print "BASE"
class Next(Base):
def __init__(self):
super(Base, self).__init__()
print "NEXT"
class Final(Next):
def __init__(self):
super(Next, self).__init__()
print "FINAL"
f = Final()
Outputs:
BASE
FINAL
Why does "NEXT" not print??
You should be calling super() with the current class, not the parent.
class Base(object):
def __init__(self):
super(Base, self).__init__()
print "BASE"
class Next(Base):
def __init__(self):
super(Next, self).__init__()
print "NEXT"
class Final(Next):
def __init__(self):
super(Final, self).__init__()
print "FINAL"
f = Final()
At first glance this might seem redundant ("why can't it just get the class from self?") - but keep in mind that the same self is passed to all three of these __init__ methods when f is created, and that self is always of class Final. Thus, you have to pass super() the class that you want it to find the parent of.
class Base(object):
def __init__(self):
print "BASE"
class Next(Base):
def __init__(self):
super(Next, self).__init__()
print "NEXT"
class Final(Next):
def __init__(self):
super(Final, self).__init__()
print "FINAL"
f = Final()
Im a bit confused about inherited instance variables in ABCs. I have written an example to show my confusion. Class A needs a list which class B inherits but it must be an instance object rather than a class object. However class B also needs its own instance variable local. Can anyone set me straight?
#!python
from abc import ABCMeta, abstractmethod, abstractproperty
import unittest
class A(object):
__metaclass__ = ABCMeta
_internal = ['initialized']
#property
def internal(self):
return self._internal
def get_a(self):
return self._internal
#abstractmethod
def set_a(self, value):
pass
class B(A):
def __init__(self):
self.local = 'OK'
def get_local(self):
return self.local
def set_a(self, value):
self._internal.append(value)
class TestCase(unittest.TestCase):
def test_implementation(self):
self.assertEqual(['initialized'], B().get_a() ) # this passes but for wrong reason
b_used = B().set_a('used')
b_unused = B()
print "b_used.get_a() should return ['initialized','used']"
print "b_unused.get_a() should return ['initialized']"
print "b_used.get_local() should equal b_unused.get_local() = 'OK'"
self.assertEqual(['initialized'], b_unused.get_a()) # >> fails with ['initialized'] =! ['initialized', 'used']
self.assertNotEqual(b_unused.get_a(), b_used.get_a())
if __name__ == "__main__":
unittest.main()
The problem is that _internal is a class obj of class A. I need it to be an instance object of class B.
Thanks In advance
You should initialize instance attributes in __init__() and call the base class __init__() in B:
class A(object):
__metaclass__ = ABCMeta
def __init__(self):
self._internal = ['initialized']
...
class B(A):
def __init__(self):
A.__init__(self)
self.local = 'OK'
...
You should also fix your unit test:
class TestCase(unittest.TestCase):
def test_implementation(self):
self.assertEqual(['initialized'], B().get_a() ) # this passes but for wrong reason
b_used = B()
b_used.set_a('used')
b_unused = B()
...
Instance attributes should be defined in a method, eg __init__, by setting them on self.