Here are the few classes let's say, B, C, D and A, while in class A I am using super method which have class 'B' as an argument.
Where classes are as defined as below:
class B:
def __init__(self):
print('B')
class C:
def __init__(self):
print('C')
class D:
def __init__(self):
print('D')
class A(B,C,D):
def __init__(self):
super(B,self).__init__()
A()
When I am trying to initiate the class A, it should invoke class B as I passed B in super method. But it is giving me output 'C'. If I am passing D in super instead of B it's not giving any output. Why? Instead it just invoke class A and leave.
Why is this happening?
The class you pass as an argument to super should be the current class whose superclass we want to look for, not the target superclass. With your class A, the method resolution order is
A < B < C < D < object
So super(A, self).__init__() would call the method on the class following A in the MRO, which is B. Likewise, super(B, self).__init__() would call the one following B, which is C. super(C, self) would give us D, and super(D, self) would give us object (Side note: I don't know what super(object, self) does, but it seems to return a proxy object that just eats all method calls).
What you're looking for is
super(A, self).__init__()
but since you're inside a method and want to call the next method in the MRO chain anyway (the default, and most sane, behavior), you can use the 0-argument form.
super().__init__()
Here is a simplified code of my main code illustrating the behaviour I obtain.
Suppose I have a main class (MAIN) and two classes (A,B) inheriting from it. This main class has a method which is overwriten by A but not by B, which means that B inherits the method from main.
Then I have a class D which inherits from A and from B, and has a method which calls the aforementioned method. From what I have understood in the way multiple inheritance work, if I define D as class D(A,B) then if A and B have a shared method, calling D.method() will call A.method, and vice-versa (i.e if class D(B,A) then B.method is called. The following code exemplifies this text.
class MAIN(object):
def __init__(self):
pass
def print(self):
print('HELLO MAIN')
class A(MAIN):
def __init__(self):
pass
def print(self):
print('HELLO A')
class B(MAIN):
def __init__(self):
pass
class C(A,B):
def __init__(self):
pass
def Cprint(self):
self.print()
c = C()
c.Cprint()
class C(B,A):
def __init__(self):
pass
def Cprint(self):
self.print()
c = C()
c.Cprint()
However this code always print 'HELLO A', i.e even in the case class C(B,A) I don't get a HELLO MAIN as I would expect. What is happening here? Thanks so much in advance
The mro is (C, A, B, MAIN) with class C(A, B) and (C, B, A, MAIN) with class C(B, A). In both cases, A is before MAIN. B doesn't define .print, so it doesn't matter.
The method uplooks works like this: (pseudo code)
def find_attribute(obj, name):
if name in obj.__dict__:
return obj.__dict__[name]
mro = type(obj).__mro__
for cls in mro:
if name in cls.__dict__:
return cls.__dict__[name] # (Here a bit more magic for descriptors happens)
raise AttributeError(name)
For the classes this is what their __dict__ look like:
MAIN.__dict__ = {"print": <method MAIN.print>}
A.__dict__ = {"print": <method A.print>}
B.__dict__ = {}
C.__dict__ = {"Cprint": <method C.Cprint>}
As you can see, B does not have a print defined, so in mro=(C, B, A, MAIN) the first print that does get found is in A.
You are inheriting the Class A everywhere and class A overrrides Main functions print() thats why you dont get the "HELLO MAIN"
class C(B):
def __init__(self):
pass
def Cprint(self):
self.print()
inherit only B class which does not overrides Main class print function then you will get the HELLO MAIN output
i have a little question that is discouraging me i have this portion of code:
class A(object):
def __init__(self):
self.variable = "Hello World!!!"
class B(A):
def __init__(self):
self.A = A()
self.inherited = self.A.variable
the thing is that i have a bunch of variables on class A that i don't want to instantiate and declare on class B one by one
is there a way to improve the code?
You are using a mix of composition and inheritance. It seems like you want to exclusively use composition:
class A(Object):
def __init__(self):
self.c = C()
self.e = E()
class B(Object):
def __init__(self):
self.c = C()
self.d = D()
Where C, D, and E are components that group variables and methods together. Now A and B only share the component of C. You should look for more complete composition tutorials
Edit: Actually just double checking it looks like your just confused about instantiating super class variables. Other answers correctly addressed this with super
You are misunderstanding two concepts.
For example, you are trying to do both composition and inheritance.
class A(Object):
def __init__(self):
self.variable = "Hello World!!!"
class B(A):
def __init__(self):
self.A = A()
self.inherited = self.A.variable
When you do this, you are saying, "Make B also an A object." In other words, the following works:
class A(object): # can omit this (object) in python3
def __init__(self):
self.value_from_a = 'Im from A!'
class B(A):
def __init__(self):
super().__init__()
self.value_from_b = 'im a bbbbb!'
b = B()
print(b.value_from_a)
print(b.value_from_b)
So, in your case the way to do this is to not try to make an A both the base as well as part of B.
Note if you are using Python2 the above syntax will be slightly different.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I currently have some class foo() with some variables that are not only shared among all instances of the foo class, but also by other classes bar.
i.e.
class foo():
__init__(self, a, b):
self.a = a
self.b = b
class bar():
__init__(self, a, b):
self.a = a
self.b = b
One solution would be to make a and b class variables, but how do I do that cleanly during construction? Could I just put both classes in the same file and have them reference some global variables a and b? Is that bad practice?
Since you did not provide your intention or real-world situation, I'll just provide some ways of sharing variable access.
1st option: global.
a=b=None
class foo():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
2nd option: foo's class vars
class foo():
a = b = None
def __init__(self, a, b):
foo.a, foo.b = a, b
class bar():
def __init__(self, a, b):
foo.a, foo.b = a, b
3rd option: inheritance
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar(foo):
pass
4th option: outer class
class outer():
a = b = None
class foo():
def __init__(self, a, b):
outer.a, outer.b = a, b
class bar():
def __init__(self, a, b):
outer.a, outer.b = a, b
5th option: compsition
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
def __init__(self, a, b):
self.foo = foo(a,b)
6th option: closure over outer-function local variables
def outer():
a = b = None
class foo():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
... #things with foo and bar
7th option: closure over foo's __init__ local variables.
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
nonlocal a, b
#do things with a and b directly
self.bar = bar()
You could do this:
class Foo(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
pass
By inheriting from Foo, you'll be adopting Foo's construction method as well so it will act the same way. If you need to override it, you can set it up this way in Bar:
def __init__(self, a, b, c):
super(Bar, self).__init__(a, b)
self.c = c
super will call your base class' method first (in this case, Foo) and then allow you to add on if you'd like. Here's the documentation on super, if you're interested.
The usual solution is to make an object that stores the shared information, then pass that when instantiating the classes that need it. Often this is some kind of configuration information, so we'll call the class Config:
class Config(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# default values
number = 0
text = "Nothing"
Since Python is duck-typed, any object can be used to hold this configuration; it can be an instance of a class or the class itself. The former is handy when the data is specified at runtime. The latter can be convenient since it allows the programmer to define the various bundles of attributes using inheritance at coding time. The Config class here lets you have it either way: you can instantiate it, passing keyword arguments with the shared values, or you can subclass it, providing the shared values as class attributes.
In your Foo and Bar classes you then just accept the shared data in the constructor:
# these classes both need certain pieces of data
# but are not related by inheritance
class Foo(object):
def __init__(self, shared):
self.shared = shared
class Bar(object):
def __init__(self, config):
self.config = config
And then you can either instantiate the Config class, or define a subclass, and pass the resulting object to the new objects:
# use an instance
adams_config = Config(text="Don't Panic", number=42)
foo1, bar1 = Foo(adams_config), Bar(adams_config)
# use a subclass
class LincolnConfig(Config):
number = 87
text = "Four score and seven years ago"
foo2, bar2 = Foo(LincolnConfig), Bar(LincolnConfig)
Now methods of your Foo and Bar class can get self.shared.number or self.config.text (and so on) to access the data.
Since the instances of your various classes are all holding references to the same object, a change to e.g. adams_config or LincolnConfig would be seen by any instance of any class that holds a reference to one of these objects. If this isn't the behavior you want, you could fish the data you want to "freeze" out of the config object at instantiation and set it as attributes of your instance.
You could also just use a dictionary for data you want to access in various places, but I think the benefits of inheritance and attribute-access syntax are a good argument for doing it with classes.
You could even have a global configuration object that is used as a default value so you don't need to explicitly specify it if you want things to "just work." Here we'll just use the Config class itself for that, since it already has default values for the attributes we're interested in:
class Baz(object):
def __init__(self, config=Config):
self.config = config
By using this approach instead of global variables, you make it easier for clients using your objects to have numerous instances with different settings, rather than being limited to one "bundle" of settings for all instances.
I'm not sure what you mean by "cleanly during construction"
You can use class variables by defining them outside the function like:
class A:
x = 1
def __init__(self):
pass
And just call A.x whenever you need the variable, within other classes or wherever
I have class A class B and class C.
class A and B can affect class C. so they need to refer to the same instance of the class.
#a.py
from C import C
Cinstance = C()
Cinstance.add()
#b.py
class b(object)
#i need to refer to 'cinstance' here to control the same instance of the class
#C.py
class C(object)
def __init__(self):
self.a=1
def add(self):
self.a += 1
print a
How do i need to import and instanciate the classes for it to work this way? I am new to programming and still learning so things that are obvious are still a little difficult for me right now.
class A:
def __init__(self,cInst):
self.c = cInst
class B:
def __init__(self,cInst):
self.c = cInst
cInst = C()
a = A(cInst)
b = B(cInst)
something like that maybe
based on what you have there I think the easiest thing would be to import Cinstance from module a.
from a import Cinstance
You can pass an instance of A and B to your C.__init__ method and save them as attributes of C.
I'm on my phone, so the code below isn't tested
class C(object):
def __init__(self, a, b):
self.a = a
self.b = b
>>> c = C(A(), B())