Consider such code snippet:
class C:
def __init__(self):
print(id(self))
class D(C):
def __init__(self):
super(D, self).__init__()
print(id(super(D, self)))
if __name__ == '__main__':
d = D()
which produces for me:
140267543158096
140267543678800
Why this happens?
I expected that result should be the same because super(D, self) and self in C is the same object.
Related
I have a class and a sub-class, I'd like to pass the whole of the self of the class to the sub-class. I can pass self over to the new class explicitly easily enough, e.g.
class foo:
def __init__(self, a, b):
self.a = a
self.b = b
self.c = 'foo'
def foo_method(self):
print('a foo method')
class bar(foo):
def __init__(self, foo_object):
self.a = foo_object.a
self.b = foo_object.b
self.c = foo_object.c
def bar_method(self):
print('a bar method')
foo_object = foo(a = 'a', b = 'b')
bar_object = bar(foo_object)
bar_object.a
Is there a more succinct way to pass these over? Something like:
class bar(foo):
def __init__(self, foo_object):
self = self.foo_object
Update:
Thanks https://stackoverflow.com/users/10104112/bastien-antoine, the following solution worked:
class bar(foo):
def __init__(self, foo_object):
self.__dict__ = foo_object.__dict__.copy()
def bar_method(self):
print('a bar method with ' + str(self.c))
Have you tried the copy builtins library?
Otherwise I think you can easily implement your own .copy() method that would copy the values from the old object __dict__ to the new one. Something like this:
class MyObject:
a = None
def set_default_values(self):
self.a = 1
def copy(self, old):
if type(self) == type(old):
self.__dict__ = old.__dict__.copy()
else:
raise TypeError('Wrong type')
if __name__ == "__main__":
obj_1 = MyObject()
print(obj_1.a)
obj_1.set_default_values()
print(obj_1.a)
obj_2 = MyObject()
print(obj_2.a)
obj_2.copy(obj_1)
print(obj_2.a)
Note that I've added a type checking to be sure that you copy attributes that would exist otherwise, but I think simply self.__dict__ = old.__dict__.copy() would work fine, thought you might end up with attributes you might not suppose to have in the new object.
Hope this helps!
I think that you can do that with
class bar(foo):
def __init__(self):
super(bar, self).__init__()
with this code, you ran the init function for the subclass
Consider the code below:
class A(object):
attr = None
def __init__(self):
assert A.attr is not None
class B(object):
def __init__(self, attr):
A.attr = attr
class C(A):
def __init__(self):
super().__init__()
class D(A):
def __init__(self):
super().__init__()
nested_classes = {cls.__name__: cls for cls in {C, D}}
Above doesn't seem to work as I intend because:
>>> first_class = B("first")
>>> first_sub_class = first_class.C()
>>> first_sub_class.attr
'first'
>>> second_class = B("second")
>>> second_sub_class = second_class.C()
>>> second_sub_class.attr
'second'
>>> first_sub_class.attr
'second'
Is there a way to have first_sub_class.attr be first while having second_sub_class.attr be second? Possibly by having a metaclass whose scope is within B?
A few points:
I don't want to pass attr around, I want to set it while B is being initialized.
I don't want to circumnavigate the point above by using partial, since it breaks the rest of the code relying on __name__ or __qualname__ or alike.
I want to keep faithful to the current structure as much as possible.
To solve this problem just add the line self.attr = self.attr inside the __init__ function of A. Since you don't want to change the attributes of A, you will have to make the following changes:
class A(object):
attr = None
def __init__(self):
assert self.attr is not None # Don't refer to A, but to self to get the correct value
self.attr = self.attr
class B(object):
def __init__(self, attr):
self.attr = attr # Don't edit A, just save the value in own instance
def __getattribute__(self, item): # completely added, does some magic to ensure class.attr is set correctly
if item in B.nested_classes:
c = B.nested_classes[item]
c.attr = self.attr
return c
return super().__getattribute__(item)
class C(A):
def __init__(self):
super().__init__()
class D(A):
def __init__(self):
super().__init__()
nested_classes = {cls.__name__: cls for cls in {C, D}}
first_class = B("first")
first_sub_class = first_class.C()
print(first_sub_class.attr)
second_class = B("second")
second_sub_class = second_class.C()
print(second_sub_class.attr)
print(first_sub_class.attr)
You're insanely overcomplicating this:
class A:
def __init__(self, attr):
self.attr = attr
class C(A):
pass
class D(A):
pass
class B:
def __init__(self, attr):
self.attr = attr
def C(self):
return C(self.attr)
def D(self):
return D(self.attr)
Behaves exactly as desired:
>>> first_class = B("first")
>>> first_sub_class = first_class.C()
>>> first_sub_class.attr
'first'
>>> second_class = B("second")
>>> second_sub_class = second_class.C()
>>> second_sub_class.attr
'second'
>>> first_sub_class.attr
'first'
I have the following inheritance chain:
class Foo(object):
def __init__(self):
print 'Foo'
class Bar(Foo):
def __init__(self):
print 'Bar'
super(Foo, self).__init__()
class Baz(Bar):
def __init__(self):
print 'Baz'
super(Bar, self).__init__()
When instantiating Baz class the output is:
Baz
Foo
Why isn't Bar's constructor isn't called?
The call to super() takes the current class as the first argument, not the super class (super() works that out for itself). In this case, the following should fix it... note the change to both super() calls:
class Foo(object):
def __init__(self):
print 'Foo'
class Bar(Foo):
def __init__(self):
print 'Bar'
super(Bar, self).__init__()
class Baz(Bar):
def __init__(self):
print 'Baz'
super(Baz, self).__init__()
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()
Let's say, I have the following two classes:
class A(object):
def __init__(self, i):
self.i = i
class B(object):
def __init__(self, j):
self.j = j
class C(A, B):
def __init__(self):
super(C, self).__init__(self, 4)
c = C()
c will only have the i attribute set, not the j.
What should I write to set both of attributes/only the j attribute?
If you want to set only the j attribute, then only call B.__init__:
class C(A, B):
def __init__(self):
B.__init__(self,4)
If you want to manually call both A and B's __init__ methods, then
of course you could do this:
class C(A, B):
def __init__(self):
A.__init__(self,4)
B.__init__(self,4)
Using super is a bit tricky (in particular, see the section entitled "Argument passing, argh!"). If you still want to use super, here is one way you could do it:
class D(object):
def __init__(self, i):
pass
class A(D):
def __init__(self, i):
super(A,self).__init__(i)
self.i = i
class B(D):
def __init__(self, j):
super(B,self).__init__(j)
self.j = j
class C(A, B):
def __init__(self):
super(C, self).__init__(4)
c = C()
print(c.i,c.j)
# (4, 4)