I have two classes:
class A(object):
def __init__(self, b):
self b = b
class B(object):
def __init__(self, a):
self a = a
I'd like to init them like this:
a = A(b)
b = B(a)
But I can't since 'b' doesn't exist when doing a = A(b). I have to do:
a = A()
b = B(a)
b.a = a
But that seems unclean. Is this solvable?
You could either make one class instantiate the other:
class A(object):
def __init__(self):
self.b = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
b = a.b
Or make one class tell the other about itself, like this:
class A(object):
def __init__(self, b):
self.b = b
b.a = self
class B(object):
def __init__(self):
#Will be set by A later
self.a = None
b = B()
a = A(b)
Related
Imagine I have:
class ABC():
def main(self, x):
self.x = x
class A(ABC):
def afunction(self):
self.a = 2
class B(ABC):
def bfunction(self):
self.b = self.a * self.x
return self.b
How is it possible that class B inherits the self.a and self.x from class A and ABC? (I do not care about inheriting the methods)
If I understand correctly, what you want is to get B to inherit from A.
Notice that what will happen is that it will inherit A variables, and because A inherits from ABC, B will inherit ABC's variables as well.
Also, please note that you will have to initialize the x variable for example inside an B object in order to use the bFunction, and in general it is proper coding to set a constructor as follows:
class ABC():
def __init__(self, x=0):
self.x = x
def main(self, x):
self.x = x
class A(ABC):
def __init__(self, a=2):
super().__init__()
self.a = a
def afunction(self):
self.a = 2
class B(A):
def __init__(self, b=0):
super().__init__()
self.b = b
def bfunction(self):
self.b = self.a * self.x
return self.b
b = B()
b.main(3)
b.afunction()
print(b.bfunction())
Output:
6
If B inherits from A, which inherits from ABC, then B will have ABC and A's methods but neither the 'x' or 'a' attributes which are only set after the methods are run. This works if you rewrite B as:
class B(A):
def bfunction(self, x):
self.main(x)
self.afunction()
self.b = self.a * self.x
return self.b
b = B()
print(b.bfunction(10))
You have to supply 'x' to b.bfunction so that self.b = self.a * self.x works.
Given a parent class 'A'
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
def methodA():
# do something
What is the difference between making a subclass 'B' among the below options
Option 1
class B(A):
def methodB():
# do something
Option 2
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
# do something
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
pass
class C(A):
def methodB():
pass
b = B(1,2)
c = C(1,2)
print b.a == c.a # True
print b.b == c.b # True
In both class instantiation, init under class A will be ran only once.
so no, there is nothing significantly different.
class B is not clean IMO and poses no real purpose at all. It will be ran anyways.
If you wish to do something different in class B init, then yes, you can use this code.
class B(A):
def __init__(self,a,b):
A.__init__(self, a+1, b+1)
def methodB():
pass
I have a class that inherits from two other classes whose __init__ take both a parameter like this:
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
super(C, self).__init__(a, b)
c = ClassC(1, 2)
This gives a TypeError: __init__() takes exactly 2 arguments (3 given).
When setting b in B to a fixed value and passing only 1 parameter to super then trying to access b in C gives an AttributeError: 'ClassC' object has no attribute 'b':
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = 2
class C(A, B):
def __init__(self, a, b):
super(C, self).__init__(a)
print self.a
print self.b
c = ClassC(1, 2)
When calling the __init__ manually everything seems to be fine:
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
A.__init__(a)
B.__init__(b)
print self.a
print self.b
c = ClassC(1, 2)
So how can I get this inheritance straight and how can I manage the parameters for __init__ of inherited classes when using super? Is it even possible? How does super know which parameters are to pass to which class?
Why does c.print_a() output 'B'?
class A(object):
def __init__(self):
self.some_name = 'A'
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
if __name__ == '__main__':
c = C()
c.print_a()
class A(object):
def __init__(self, some_name='A'):
self.some_name = some_name
def print_a(self):
print self.some_name
class B(object):
def __init__(self, some_name='B'):
self.some_name = some_name
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
A.__init__(self, some_name='AAAAA')
B.__init__(self, some_name='BBBBB')
if __name__ == '__main__':
c = C()
c.print_a()
You only have a single object here; the some_name property is shared between methods from all inherited classes. You call A.__init__, which sets it to A, then B.__init__, which changes it to B.
Also note that you're calling base methods incorrectly; use super:
class A(object):
def __init__(self):
self.some_name = 'A'
super(A, self).__init__()
def print_a(self):
print self.some_name
class B(object):
def __init__(self):
self.some_name = 'B'
super(B, self).__init__()
def print_b(self):
print self.some_name
class C(A, B):
def __init__(self):
super(C, self).__init__()
if __name__ == '__main__':
c = C()
c.print_a()
There's only one self, and you're overwriting its some_name in B.__init__. Maybe you're used to C++, where there would be two separate fields, A.some_name and B.some_name. This concept doesn't apply to Python, where attributes are created dynamically on assignment.
Say you want C to set names for some objects of types A and B and later calling some print_a and print_b methods on objects of type C get these names back ?
You can get this type of behavior using C++ inheritance model, but python model is very different. Only one object with one set of fields. If you want the C++ behavior, the simplest way is probably to declare subobjects (and it looks like a common abuse of inheritance over composition).
Looks like you are trying to do something like below:
class Printable(object):
def __init__(self, name):
self.name = name
def myprint(self):
print self.name
class C(object):
def __init__(self):
self.a = Printable('A')
self.b = Printable('B')
def print_a(self):
self.a.myprint()
def print_b(self):
self.a.myprint()
if __name__ == '__main__':
c = C()
c.print_a()
class A()
att = B()
class B()
...
a = A()
b = B()
a.att = b
How can b get reference of a ? I need to get an attribute of a here.
Thanks!
You can make a generic "Reference()" class, that keep any reference of itself in an attributes dictionnary.
class Reference(object):
def __init__(self):
self.references = {}
def __setattr__(self, key, value):
if hasattr(self, 'references'):
if isinstance(value, Reference):
if not key in value.references:
value.references[key] = []
value.references[key].append(self)
elif value is None and hasattr(self, key):
old = getattr(self, key).references
if key in old and self in old[key]:
old[key].remove(self)
super(Reference, self).__setattr__(key, value)
And then, create your classes :
class A(Reference):
def __init__(self):
super(A, self).__init__()
self.att = None
class B(Reference):
def __init__(self):
super(B, self).__init__()
self.att = None
And use it :
a = A()
b = B()
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {}
a.att = b
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {'att': [<__main__.A object at 0x7f731c8fc910>]}
At the end, you'll have back reference to all Reference class from any properties
Easiest way would be to just add an extra function parameter to the method in B that needs A, and pass it through when called. Or, just make B's init take an A as argument, and change the bit in A's init to be att = B(self)
class A(object):
def __init__(self):
self.att = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
a.att.a is a
Or another way,
class A(object):
def __init__(self, b):
b.a = self
self.att = b
class B(object):
pass
a = A(B())
a.att.a is a
This code doesn't make a lot of sense... but if I correctly understand your question...
class A(object):
pass #or whatever you like
class B(object):
def __init__(self, ref): #accept one argument
self.ref = ref
a = A()
b = B(a) #pass `a` as that argument
a.att = b
Might be one answer.
class A(object):
def __init__(self):
self._att=None
#property
def att(self):
return self._att
#att.setter
def att(self, value):
self._att = value
value.parent = self
class B(object):
pass
a = A()
b = B()
a.att = b
print b.parent