Can python's 'super' give child classes its parent classes class variables - python

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.

Related

Setting self as an instance from another class doesn't work [Python]

Let's assume I have a class A and a class B.
class A:
def __init__(self):
self.variable1 = 1
self.variable2 = 'sometext'
class B:
def __init__(self, inst):
self = inst
print(self.__dict__.keys(), inst.__dict__.keys())
The print function returns
b = B(inst)
dict_keys(['variable1', 'variable2']) dict_keys(['variable1', 'variable2'])
However when I try
b.variable1
It returns the following error
AttributeError: 'B' object has no attribute 'variable1'
In my more complex code I need almost all variable from class A in class B.
I tried using class inheritance however I couldn't make it work with class methods and constructors.
Is there a reason why the above method doesn't work?
Thx
You're trying to overwrite self, but that only works while you're in the init. Instead, try assigning the inst to a variable of the class B:
class B:
def __init__(self, inst):
self.inst = inst
print(self.__dict__.keys(), inst.__dict__.keys())
Now you can access the variables of class A via:
inst = A()
b = B(inst)
b.inst.variable1
Not sure what you're trying to achieve here exactly, but you could also initiate the class A object inside the init of class B instead of passing the object to class B.
To use variable from class A in B you have to access to class A from B. Then execute class B
class A:
variable1 = 1
variable2 = 'sometext'
class B:
def __init__(self, inst=None):
self.f1 = A().variable1
self.f2 = A().variable2
def get_var(self):
print (self.f1)
B().get_var()

Expensive operation in parent class performed once for all child classes

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?

How to find out that I have called Child.parent_funcn through Child but not through Parent class?

Here is an example in easy form what I am trying to achieve.
class Parent:
def abc():
pass
class Child(Parent):
def pqr():
pass
Child.abc
<function Parent.abc()>
Child.abc.__qualname__
'Parent.abc'
figure_out_class_from_class_func(class_func):
...
derive class from class_func.__qualname__
return class
figure_out_class_from_class_func(Child.abc) returns -> Parent.
Actually I want it to return Child as actually I am passing Child class.
So basically __qualname__ is not my friend here. Is it anyhow possible to figure out actual class rather than the parent class(where function is implemented) using Class.function ?
EDIT:
bit better example:
class Parent():
def __init__(self):
print(self.x)
def parent_func1(self):
pass
class Child(Parent):
x=1
def __init__(self):
print(self.x)
def child_func1(self):
pass
def special_function(class_func):
func_module = inspect.getmodule(class_func)
class_name = getattr(class_func, "__qualname__", None).split(".")[0]
class_obj = getattr(func_module, class_name)
class_obj()
Now calling special_function(Child.child_func1) is fine-> print 1
But special_function(Child.parent_func1) gives error:
ERROR:root:Internal Python error in the inspect module.
Below is the traceback from this internal error.
1 class Parent():
2 def __init__(self):
----> 3 print(self.x)
4 def parent_func1(self):
5 pass
AttributeError: 'Parent' object has no attribute 'x'
Is there any way to find out that I have called Child.parent_funcn through Child but not through Parent ?

Python base class' implicit super() call

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

Python Multiple Inheritance/Mixin

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 ??

Categories

Resources