How to determine the relationship between classes? - python

I have two classes:
class A(object):
"""Instance of this class must by only one"""
def some_function(self):
print "A function"
[... other functions ...]
class B(object):
"""Many instances of this class"""
[... functions ...]
And I want to init only one object of class A from class B, I write this:
class B(object):
a_instance = A()
b_instances = []
def __init__(self, *args, **kwargs):
B.a_instance.some_function()
B.b_instances.append(self)
super(B, self).__init__(*args, **kwargs)
def update(self):
print "Update instance"
#classmethod
def super_function(self):
print "My super B function"
for instance in B.b_instances:
instance.update()
Is this correct?
And second question: How to call "super_function" from instance of class A?

Related

How to inherit constructor into class method in python

I have one base class constructor. from that i want to inherit into class method. But it showing the error like TypeError: __init__() missing 1 required positional argument: 'name'
Here is my code snippet.
class A:
def __init__(self,name):
self.name = name
def m1(self):
print(self.name)
class B(A):
#classmethod
def m2(cls):
super(B,cls).__init__(cls.m1)
b=B('siddarth')
b.m2 ()
Here it is another example. but without having any parameters in constructor it is working fine.
class A:
def __init__(self):
print('This is constructor method..!!')
class B(A):
#classmethod
def m2(cls):
super(B,cls).__init__(cls)
b=B('siddarth')
b.m2()
You can code it like this:
class A:
def __init__(self,name):
self.name = name
def m1(self):
print(self.name)
class B(A):
def __init__(self, cls):
super(B, self).__init__(cls)
b=B('siddarth')
b.m1()
OUTPUT
siddarth

Overloading and wrapping method of field of parent class in python

For example I have something like this:
class A(object):
def __init__(self):
pass
def foo(self, a, b, c):
return a + b + c
class B(object):
def __init__(self):
self.b = A()
def wrapper_func(func):
def wrapper(self, *args, **kwargs):
return func(self, a=3, *args, **kwargs)
return wrapper
class C(B):
def __init__(self):
pass
#wrapper_func
def ???
Is it possible to some how overload and then wrap method foo of the field of parent B class in python without inherits from class A? I need the wrapper indeed because I have the different methods with same arguments, but in the same time I have to save original class B methods native (besides overloading).
Initialize C's parent class using super and then pass all the parameters to the foo method of the composed class instance A() via the inherited attribute b of the class C:
def wrapper_func(func):
def wrapper(self, *args, **kwargs):
kwargs['a'] = 3
return func(self, *args, **kwargs)
return wrapper
class C(B):
def __init__(self):
super(C, self).__init__()
#wrapper_func
def bar(self, *args, **kwargs):
return self.b.foo(*args, **kwargs) # access foo via attribute b
Trial:
c = C()
print(c.bar(a=1, b=2, c=3))
# 8 -> 3+2+3
To make the call to the decorated function via c.b.foo, patch the c.b.foo method with the new bar method:
class C(B):
def __init__(self):
super(C, self).__init__()
self._b_foo = self.b.foo
self.b.foo = self.bar
#wrapper_func
def bar(self, *args, **kwargs):
return self._b_foo(*args, **kwargs)
Trial:
c = C()
print(c.b.foo(a=1, b=2, c=3))
# 8 -> 3+2+3

How can I set override default kwargs in a parent class?

Let's say I have the following parent and child classes:
class A(object):
def __init__(self, *args, **kwargs):
self.a = kwargs.get('a', 'default_A')
self.b = kwargs.get('b', 'default_B')
class B(A):
a = "override_A"
def __init__(self, *args, **kwargs):
super(B, self).__init__(**kwargs)
b = B()
print b.b # this is "default_B", as expected
print b.a # I expected this to be "override_A"
What am I doing wrong here? I've tried to understand how inheritance works via answers like this one but haven't found something that describes this specific requirement.
You're mixing class and instance variables. B.a is a class variable, which is shadowed by the instance variable set in A.__init__().
You could for example use dict.setdefault():
class B(A):
def __init__(self, *args, **kwargs):
# If the key 'a' exists, this'll be effectively no-operation.
# If not, then 'a' is set to 'override_A'.
kwargs.setdefault('a', 'override_A')
super(B, self).__init__(**kwargs)

Mixins, multi-inheritance, constructors, and data

I have a class:
class A(object):
def __init__(self, *args):
# impl
Also a "mixin", basically another class with some data and methods:
class Mixin(object):
def __init__(self):
self.data = []
def a_method(self):
# do something
Now I create a subclass of A with the mixin:
class AWithMixin(A, Mixin):
pass
My problem is that I want the constructors of A and Mixin both called. I considered giving AWithMixin a constructor of its own, in which the super was called, but the constructors of the super classes have different argument lists. What is the best resolution?
class A_1(object):
def __init__(self, *args, **kwargs):
print 'A_1 constructor'
super(A_1, self).__init__(*args, **kwargs)
class A_2(object):
def __init__(self, *args, **kwargs):
print 'A_2 constructor'
super(A_2, self).__init__(*args, **kwargs)
class B(A_1, A_2):
def __init__(self, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print 'B constructor'
def main():
b = B()
return 0
if __name__ == '__main__':
main()
A_1 constructor
A_2 constructor
B constructor
I'm fairly new to OOP too, but what is the problem on this code:
class AWithMixin(A, Mixin):
def __init__(self, *args):
A.__init__(self, *args)
Mixin.__init__(self)

Constructor B is not called in an A -> B -> C inheritance chain

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__()

Categories