I have the following problem:
class A:
animal = 'gerbil'
def __init__(self):
self.result = self.calculate_animal()
def calculate_animal(self):
print(self.animal)
return self.animal
class B(A):
animal = 'zebra'
def __init__(self):
super(B, self).__init__()
Now, I want a certain set of subclasses from A, to implement a new function that calculates something different with the animal, like so:
class CapitalizeAnimal:
def calculate_animal(self):
self.animal = self.animal.upper()
# I need to call some version of super().self.animal,
# but how will this Mixin class know of class A?
class C(A, #CapitalizeAnimal?):
animal = 'puma':
def __init__(self):
super(C, self).__init__()
How do I get class C to implement the CapitalizeAnimal version of calculate_animal, while keeping its animal as puma? I'm confused at how the Mixin class will be able to call a super() function.
The order of the parent classes is important, you should do it like so:
class C(CapitalizeAnimal, A):
animal = 'puma'
def __init__(self):
super(C, self).__init__()
More info can be found by reading about the MRO (Method Resolution Order).
Also, super only works with new style classes, so you should make A inherit object (unless of course you are using Python 3).
First of all, B and C don't need __init__() if the only action is calling the super __init__.
To your question: Have you tried class C(A, CapitalizeAnimal): and/or class C(A, CapitalizeAnimal):? I.e., omitting the # and the ??
Related
I have two classes that inherit from the same base class. In the base class I have a very expensive method that must be ran only once and whose generated attributes must be available to the child class. How do I achieve that?
In the example below, the instantiation of the B and C child classes will both run expensive_op in A. I'd like expensive_op to be called only when I call b=B(). A is never called directly.
Moreover, I want to be able to modify the attributes of the parent class from the child class as done, for example, in the modify method in B.
Anyone able to help?
class A:
def __init__(self):
self.expensive_op()
def expensive_op(self):
self.something = #something ugly and expensive
class B(A):
def __init__(self):
super().__init__()
def modify(self,mod):
self.something = self.something+mod
class C(A):
def __init__(self):
super().__init__()
b = B()
c = C()
EDIT: in response to #0x5453's comment, do you mean the modification of A below?
class A:
def __init__(self):
self.something = None
def expensive_op(self):
if self.something is not None:
self.something = #something ugly and expensive
But if I call b=B() and then c=C(), the latter won't know about self.something. The output is
b=B()
c=C()
b.expensive_op(3)
print(b.something)
>>> 3
print(c.something is None)
>>> True
Am I missing something?
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.
Currently I am starting to revise my python's OOP knowledge. I stumbled upon super() definition, which suggests, that it provides a derived class with a set of instance variables and methods from a base class.
So I have this piece of code:
class foo:
bar = 5
def __init__(self, a):
self.x = a
def spam(self):
print(self.x)
class baz(foo):
pass
b = baz(5)
b.spam()
And this executed with no super() calls, no errors, and printed out 5.
Now when I add an __init__ method to the derived class, like this:
class foo:
bar = 5
def __init__(self, a):
self.x = a
def spam(self):
print(self.x)
class baz(foo):
def __init__(self, a):
self.b = a
b = baz(5)
b.spam()
the script gives me an error: AttributeError: 'baz' object has no attribute 'x'.
So this would suggest, that if my class has a default __init__, it also has an explicit super() call. I couldn't actually find any info confirming this, so I just wanted to ask if I am correct.
The problem is that when you define the method __init__ in your subclass baz, you are no longer using the one in the parent class foo. Then, when you call b.spam(), x does not exist because that is define in the __init__ method of the parent class.
You can use the following to fix this if what you want is to call the __init__ method of the parent class and also add your own logic:
class baz(foo):
def __init__(self, a):
super().__init__(10) # you can pass any value you want to assign to x
self.b = a
>>> b = baz(5)
>>> b.spam()
10
This is about Method resolution order in Python. Lets say we have 3 classes: A, B, C.
C(A,B) - multiple inheritance.
In the absence of constructor in the child class C, and parent left class A, does the python engine look for the constructor from the RHS class B and execute it if it is present OR does it look to see if A has any parent class with constructor?
Example: What if Class A inherits from Class X that has a constructor. Then will the constructor from Class X run or the constructor from Class B run?
class A:
pass
class B:
def __init__(self):
print("I am class B")
class C(A, B):
pass
print(C())
I am class B
With this other example, you will understand better how multiple inheritance works:
class A:
def __init__(self):
print("I am class A")
class B:
def __init__(self):
print("I am class B")
class C(A, B):
pass
print(C())
I am class A
As you can see, B __init__ didn't get called, this is because parent classes are called from left to right, but each one must not forget to call "super init", otherwise it breaks the inheritance chain
class A:
def __init__(self):
print("I am class A")
super().__init__()
class B:
def __init__(self):
print("I am class B")
class C(A, B):
pass
print(C())
I am class A
I am class B
class Person:
def _init_(self):
self.A=1
class Employee(Person):
def _init_(self):
print(A)
object1=Person()
object2=Employee()
There are actually multiple problems with that code, besides the misspelled constructor...
Your _init_ method should be __init__, otherwise it's not a constructor but just a method that happens to be called _init_, and thus never called.
You have to call the constructor of the super-class, or A will not be set, e.g. using super().__init__() or Person.__init__(self)
You have to use self.A to read the field A of the instance; otherwise it will look for a local variable called A
This should work:
class Person:
def __init__(self): # misspelled
self.A = 1
class Employee(Person):
def __init__(self): # misspelled
super().__init__() # call super constructor
print(self.A) # use self.A