I want a child class to inherit from a parent class all methods and attributes with one small change - setting a default value for one argument in the child class shared with the parent class. How can I do it? With following code, I get an AttributeError when trying to call add method on the child class' instance.
https://pastebin.com/WFxmbyZD
def ParentClass():
"""An exemplary parent class."""
def __init__(self, a, b):
self.a = a
self.b = b
def adder(self):
return a + b
def ChildClass(ParentClass):
"""An exemplary child class."""
def __init__(self, a, b=3):
super().__init__(a, b)
child_class_instance = ChildClass(5)
print(child_class_instance.adder())
You have a mistake declaring the class.
I will show you examples here. The child class can have a different signature for the constructor and the methods.
class ParentClass:
"""An exemplary parent class."""
def __init__(self, a, b):
self.a = a
self.b = b
def adder(self):
return self.a + self.b
def adder_bis(self, c):
return self.a + self.b + c
class ChildClass(ParentClass):
"""An exemplary child class."""
def __init__(self, a, b=3):
super().__init__(a, b)
def adder_bis(self):
return super().adder_bis(self.a)
child_class_instance = ChildClass(5)
print(child_class_instance.adder())
print(child_class_instance.adder_bis())
I commented what I thought was wrong:
class ParentClass(): #class instead of def
"""An exemplary parent class."""
def __init__(self, a, b):
self.a = a
self.b = b
def adder(self):
return self.a + self.b #use self here
class ChildClass(ParentClass): #class instead of def
"""An exemplary child class."""
def __init__(self, a, b=3):
super().__init__(a, b)
child_class_instance = ChildClass(5)
print(child_class_instance.adder())
output:
8
I want to use a variable from class A for some computation in class B. I,m not sure that I use the self.out from the class A in class B appropriately?
Class A:
class A(nn.Module):
def __init__(self):
super(A, self).__init__()
self.out = func()
Class B:
class B(nn.Module):
def __init__(self):
super(A, self).__init__()
self.result = function_1() + A.self.out
Maybe this is what you need. I made a small example of what I understood.
These "prints" were placed to improve the understanding that Class "C" can fetch any function or variable from the other parent classes.
class A():
def __init__(self):
variable = None
def test(self, number):
return f'another class {number}'
class B():
def __init__(self):
self.data = None
self.out = self.print_data(5)
def print_data(self, number):
return number
def print_elem(self):
return self.data
class C(A, B):
def __init__(self):
super().__init__()
c = C()
print(c.print_data(8))
print(c.out)
c.data = 100
print(c.print_elem())
print(c.test(3))
I have two python classes, A and B that inherits from A.
At runtime, I only have one instance of class A, but many instances of class B.
class A:
def __init__(self, a):
self.a = a
def _init2 (self, AA)
self.a = AA.a
class B(A):
def __init__(self, AA, b):
super()._init2(AA)
self.b = b
AA = A(0)
BB = B(AA, 1)
Is this the good way of writing it ? It seems ugly ...
It would probably be better to remove init2 and only use __init__. Having both is confusing and unnatural.
class A:
def __init__(self, obj):
# I believe that this is what you tried to achieve
if isinstance(obj, type(self)):
self.a = obj.a
else:
self.a = obj
class B(A):
def __init__(self, A, b):
super().__init__(A)
self.b = b
On a side note, there are too many things called A here. The A in def __init__(self, A, b): is most probably not referring to the A that you expect.
I need something like this
class Parent(object):
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Derived(Base):
def __init__(self, a, b, c):
super(Derived,self).__init__(a, b)
self.c = c
def doit():
pass
parent = Parent()
derived = parent.Derived(x,y,z)
derived.doit()
When I try to run this, i get this following error: NameError: name 'Derived' is not defined
I tried with 'Base' in the place of 'Derived' in super() - didn't help
Class inheritance does not change the parent class. In this case your Parent class only contains the original Base class and not the derived class.
You can simply use monkey-patching to solve this problem,
class Parent(object):
pass
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Derived(Base):
def __init__(self, a, b, c):
super(Derived,self).__init__(a, b)
self.c = c
def doit(self):
pass
Parent.Derived = Derived
parent = Parent()
x, y , z = 1, 1, 1
derived = parent.Derived(x,y,z)
derived.doit()
Prefixing 'Derived' with 'Parent.', made it. As I already have commented on the question. This is just for experimenting with the 'Derived' class. But I am still wondering how the, 'class Derived(Base):' is fine (without 'Parent.' prefix for 'Base' class)
class Parent(object):
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Derived(Base):
def __init__(self, a, b, c):
super(Parent.Derived,self).__init__(a, b)
self.c = c
def doit():
pass
parent = Parent()
derived = parent.Derived(x,y,z)
derived.doit()
I want to add some attributes and methods into various class. The methods and attributes that I have to add are the same but not the class to assign them, so I want to construct a class who assign new methods and attributes for a class given in argument.
I try this but it's not working:
(I know that is a very wrong way to try to assign something to self, it's just to show what I want to do)
class A:
def __init__(self):
self.a = 'a'
def getattA(self):
return self.a
class B:
def __init__(self, parent) :
self = parent
# This is working :
print self.getattA()
def getattB(self):
return self.getattA()
insta = A()
instb = B(insta)
# This is not working :
print instb.getattB()
The result is :
a
Traceback (most recent call last):
File "D:\Documents and settings\Bureau\merge.py", line 22, in <module>
print instb.getattB()
File "D:\Documents and settings\Bureau\merge.py", line 16, in getattB
return self.getattA()
AttributeError: B instance has no attribute 'getattA'
And I expected to got 'a' for the call of instb.gettattB()
To resume I want to inherit class B from class A giving class A in argument of class B because my class B will be a subclass of various class, not always A.
The Best answer is in the comments, it was useful for me so I decided to show it in an answer (thank to sr2222):
The way to dynamicaly declare inherance in Python is the type() built-in function.
For my example :
class A(object) :
def __init__(self, args):
self.a = 'a'
self.args = args
def getattA(self):
return self.a, self.args
class B(object) :
b = 'b'
def __init__(self, args) :
self.b_init = args
def getattB(self):
return self.b
C = type('C', (A,B), dict(c='c'))
instc = C('args')
print 'attributes :', instc.a, instc.args, instc.b, instc.c
print 'methodes :', instc.getattA(), instc.getattB()
print instc.b_init
The code return :
attributes : a args b c
methodes : ('a', 'args') b
Traceback (most recent call last):
File "D:\Documents and settings\Bureau\merge2.py", line 24, in <module>
print instc.b_init
AttributeError: 'C' object has no attribute 'b_init'
My class C inerhite attributes and methods of class A and class B and we add c attribute. With the instanciation of C (instc = C('args')) The init for A is call but not for B.
Very useful for me because I have to add some attributes and methodes (the same) on different class.
I was having trouble with calling different constructors, using super doesn't necessarily make sense in a case like this, I opted to inherit and call each constructor on the current object manually:
class Foo(object):
def __init__(self, foonum):
super(Foo, self).__init__()
self.foonum = foonum
class Bar(object):
def __init__(self, barnum):
super(Bar, self).__init__()
self.barnum = barnum
class DiamondProblem(Foo, Bar):
# Arg order don't matter, since we call the `__init__`'s ourself.
def __init__(self, barnum, mynum, foonum):
Foo.__init__(self, foonum)
Bar.__init__(self, barnum)
self.mynum = mynum
How about this?
class A:
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B:
def __init__(self, parent) :
self.parent = parent
def __getattr__(self, attr):
return getattr(self.parent, attr)
def getattB(self):
return self.parent.getatt()
insta = A()
instb = B(insta)
print instb.getattB()
print instb.getatt()
But method in class A can not access attr in class B.
Another way:
import functools
class A:
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B:
def __init__(self, parent):
for attr, val in parent.__dict__.iteritems():
if attr.startswith("__"): continue
self.__dict__[attr] = val
for attr, val in parent.__class__.__dict__.iteritems():
if attr.startswith("__"): continue
if not callable(val): continue
self.__dict__[attr] = functools.partial(val, self)
def getattB(self):
return self.getatt()
insta = A()
instb = B(insta)
print instb.__dict__
print instb.getattB()
print instb.getatt()
Slow with init but call fast.
Since B is not a subclass of A, there is no path in B to getatt() in A
I guess i have a easier method
class fruit1:
def __init__(self):
self.name = "apple"
self.color = "blue"
class fruit2:
def __init__(self):
self.name = "banana"
self.size = 100
def merge(ob1, ob2):
ob1.__dict__.update(ob2.__dict__)
return ob1
f1 = fruit1()
f2 = fruit2()
fruit = merge(f1, f2)
print("name:",fruit.name," color:",fruit.color, " size:",fruit.size)
#output: name: banana color: blue size: 100
I'm not certain what you are trying to do, but the code below is giving my the output I think you are expecting. notice:
a is initialized outside the constructor in A
B is declared as a subclass of A
Code:
class A:
a='' #Initialize a
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B(A): #Declare B as subclass
def __init__(self, parent) :
self = parent
print self.getatt()
def getattB(self):
return self.getatt()
insta = A()
instb = B(insta)
print instb.getattB()
Helper function below conducts the merge of the dataclass instances, the attributes orders is derived from *args order:
from dataclasses import dataclass
#dataclass
class A:
foo: str
bar: str
def merge_dataclasses(*args):
if len({e.__class__.__name__ for e in args}) > 1:
raise NotImplementedError('Merge of non-homogeneous entries no allowed.')
data = {}
for entry in args[::-1]:
data.update(vars(entry))
return entry.__class__(**data)
print(merge_dataclasses(A(foo='f', bar='bar'), A(foo='b_foo', bar='b_bar')))
One easy way to merge two or more classes is through the tool set dyndesign:
from dyndesign import mergeclasses
class Base:
def __init__(self, init_value):
self.param = init_value
def m1(self):
print(f"Method `m1` of class `Base`, and {self.param=}")
def m2(self):
print(f"Method `m2` of class `Base`")
class Ext:
def m1(self):
print(f"Method `m1` of class `Ext`, and {self.param=}")
MergedClass = mergeclasses(Base, Ext)
merged_instance = MergedClass("INITIAL VALUE")
merged_instance.m1()
# Method `m1` of class `Ext`, and self.param='INITIAL VALUE'
merged_instance.m2()
# Method `m2` of class `Base`
Emphasizing ThorSummoner's's answer and Hong's comment; this method appears to be cleaner than the excepted answer. Notice Hong's use of super().init(self) in all but the last object added to the merge class.
class Foo(object):
def __init__(self, foonum):
super(Foo, self).__init__(self)
self.foonum = foonum
class Bar(object):
def __init__(self, barnum):
super(Bar, self).__init__(self)
self.barnum = barnum
class Oops(object):
def __init__(self, oopsnum):
super(Oops, self).__init__()
self.oopsnum = oopsnum
class DiamondProblem(Foo, Bar, Oops):
def __init__(self, mynum, foonum, barnum, oopsnum):
Foo.__init__(self, foonum)
Bar.__init__(self, barnum)
Oops.__init__(self, oopsnum)
self.mynum = mynum
def main():
dia = DiamondProblem(1, 10, 20, 30)
print(f"mynum: {dia.mynum}")
print(f"foonum: {dia.foonum}")
print(f"barnum: {dia.barnum}")
print(f"oopsnum: {dia.oopsnum}")