Fetching parent's function from parent - python

I override a function, but would like to get hold of the parent's function from within the parent.
>>> class a:
... def __init__(self):
... print(self.f)
... def f(self):
... pass
...
>>> class b(a):
... def __init__(self):
... super(b, self).__init__()
... def f(self):
... pass
...
>>> b()
<bound method b.f of <__main__.b object at 0x000002E297A96160>>
I'd like the printout to say a.f.

You could use name mangling to make self.__f refer to A.__f from within A's class definition.
Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls
class A:
def __init__(self):
self.__f()
def f(self):
print('A.f')
__f = f # Private copy of A's `f` method
class B(A):
def __init__(self):
super(B, self).__init__()
def f(self):
print('B.f')
b = B()
b.f()
prints
A.f
B.f

class a(object):
def __init__(self):
pass
def f(self):
print 'Parent Method...'
class b(a):
def __init__(self):
super(b, self).__init__()
a.f(self) #referance the parent class rather than the child class, because the child overrides the parent method.
self.f()
def f(self):
print "Childs Method..."
b()

Related

how to modify parent class variable with the child class and use in another child class in python

class A(object):
__A = None
def get_a(self):
return self.__A
def set_a(self, value):
self.__A = value
class B(A):
def method_b(self, value):
self.set_a(value)
class C(A):
def method_c(self)
self.get_a()
Someone can to explain me how can i to catch installed value in method_b inside my 'C' class method?
P.S. In this variant i just getting nothing.
Python isn't Java; you don't need setters & getters here: just access the attributes directly.
There are three problems with your code.
C.method_c() has no return statement, so it returns None.
You are using __ name mangling when that's exactly what you don't want.
In A.set_a() you want to set a class attribute, but your assignment instead creates an instance attribute which shadows the class attribute.
Here's a repaired version.
class A(object):
_A = 'nothing'
def get_a(self):
return self._A
def set_a(self, value):
A._A = value
class B(A):
def method_b(self, value):
self.set_a(value)
class C(A):
def method_c(self):
return self.get_a()
b = B()
c = C()
print(c.method_c())
b.method_b(13)
print(c.method_c())
output
nothing
13
Here's a slightly more Pythonic version:
class A(object):
_A = 'nothing'
class B(A):
def method_b(self, value):
A._A = value
class C(A):
pass
b = B()
c = C()
print(c._A)
b.method_b(13)
print(c._A)

Access to the methods of the class from which it was instantiated another class

I'm trying to access the methods of the class from which it was instantiated another class, I mean, accessing to the "parent" instance without creating a new instance of it.
class A():
def __init__(self):
...
b_instance = B()
...
class B():
def __init__(self):
...
def function1(self):
...
def function2(self):
C().run() # I need to use class C functionalities
...
class C():
def __init__(self):
...
def run(self):
classB.function1() #I can't access to these methods without instantiating again class B
# I have to execute:
>>> a = A()
>>> a.b_instance.function2()
Sorry if I have not explained well, is a bit confusing. If you need any clarification do not hesitate to ask.
EDIT.
In class C a specific handling of the execution of class B methods is done. Is not possible to instanciate again inside C because class B contains the initialization of hardware.
It's still not clear what exactly you're trying to achieve, but here's one fix:
class A():
def __init__(self):
...
b_instance = B()
...
class B():
def __init__(self):
...
def function1(self):
...
def function2(self):
C().run(self) # pass class B instance to C instance run method
...
class C():
def __init__(self):
...
def run(self, classB): # note additional parameter
classB.function1()
However, note that this represents a very high level of coupling between your various classes, which seems suspicious to me and may indicate a deeper flaw in your design.
This can access the class methods from other classes.
use instance method, class methods and static methods, if you are using various types of functins.
class A():
def __init__(self):
print 'in __init__'
self.b_instance = B() # making an instance of class
#self.b_instance.function2()
class B():
def __init__(self):
print 'in __init__, B'
#staticmethod
def function1():
print 'func1'
def function2(self):
C().run() # I need to use class C functionalities
# if you trying to access `run` method of `class C` make
# it instance bound method"""
class C():
def __init__(self):
pass
def run(self):
print 'in run'
B.function1() #I can't access to these methods without instantiating again class B
#you are passing class instance as `B` while calling function1
# so make it either classmethod `#classmethod` or `static method`
# I have to execute:
a = A()
a.b_instance.function2() # calling b_instance variable of class A

calling child class method from parent class file in python

parent.py:
class A(object):
def methodA(self):
print("in methodA")
child.py:
from parent import A
class B(A):
def methodb(self):
print("am in methodb")
Is there anyway to call methodb() in parent.py?
Doing this would only make sense if A is an abstract base class, meaning that A is only meant to be used as a base for other classes, not instantiated directly. If that were the case, you would define methodB on class A, but leave it unimplemented:
class A(object):
def methodA(self):
print("in methodA")
def methodB(self):
raise NotImplementedError("Must override methodB")
from parent import A
class B(A):
def methodB(self):
print("am in methodB")
This isn't strictly necessary. If you don't declare methodB anywhere in A, and instantiate B, you'd still be able to call methodB from the body of methodA, but it's a bad practice; it's not clear where methodA is supposed to come from, or that child classes need to override it.
If you want to be more formal, you can use the Python abc module to declare A as an abstract base class.
from abc import ABC, abstractmethod
class A(ABC):
def methodA(self):
print("in methodA")
#abstractmethod
def methodB(self):
raise NotImplementedError("Must override methodB")
Or if using Python 2.x:
from abc import ABCMeta, abstractmethod
class A(object):
__metaclass__ = ABCMeta
def methodA(self):
print("in methodA")
#abstractmethod
def methodB(self):
raise NotImplementedError("Must override methodB")
Using this will actually prevent you from instantiating A or any class that inherits from A without overriding methodB. For example, if B looked like this:
class B(A):
pass
You'd get an error trying to instantiate it:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class B with abstract methods methodB
The same would happen if you tried instantiating A.
You can do something like this:
class A():
def foo(self):
self.testb()
class B(A):
def testb(self):
print('lol, it works')
b = B()
b.foo()
Which would return this of course:
lol, it works
Note, that in fact there is no call from parent, there is just call of function foo from instance of child class, this instance has inherited foo from parent, i.e. this is impossible:
a=A()
a.foo()
will produce:
AttributeError: A instance has no attribute 'testb'
because
>>> dir(A)
['__doc__', '__module__', 'foo']
>>> dir(B)
['__doc__', '__module__', 'foo', 'testb']
What I've wanted to show that you can create instance of child class, and it will have all methods and parameters from both parent and it's own classes.
There are three approaches/ways to do this ! but I highly recommend to use the approach #3 because composition/decoupling has certain benefits in terms of design pattern. (GOF)
## approach 1 inheritance
class A():
def methodA(self):
print("in methodA")
def call_mehtodB(self):
self.methodb()
class B(A):
def methodb(self):
print("am in methodb")
b=B()
b.call_mehtodB()
## approach 2 using abstract method still class highly coupled
from abc import ABC, abstractmethod
class A(ABC):
def methodA(self):
print("in methodA")
#abstractmethod
def methodb(self):
pass
class B(A):
def methodb(self):
print("am in methodb")
b=B()
b.methodb()
#approach 3 the recommended way ! Composition
class A():
def __init__(self, message):
self.message=message
def methodA(self):
print(self.message)
class B():
def __init__(self,messageB, messageA):
self.message=messageB
self.a=A(messageA)
def methodb(self):
print(self.message)
def methodA(self):
print(self.a.message)
b=B("am in methodb", "am in methodA")
b.methodb()
b.methodA()
You could use the function anywhere so long as it was attached to an object, which it appears to be from your sample. If you have a B object, then you can use its methodb() function from absolutely anywhere.
parent.py:
class A(object):
def methoda(self):
print("in methoda")
def aFoo(obj):
obj.methodb()
child.py
from parent import A
class B(A):
def methodb(self):
print("am in methodb")
You can see how this works after you import:
>>> from parent import aFoo
>>> from child import B
>>> obj = B()
>>> aFoo(obj)
am in methodb
Granted, you will not be able to create a new B object from inside parent.py, but you will still be able to use its methods if it's passed in to a function in parent.py somehow.
If the both class in same .py file then you can directly call child class method from parents class.
It gave me warning but it run well.
class A(object):
def methodA(self):
print("in methodA")
Self.methodb()
class B(A):
def methodb(self):
print("am in methodb")
You can certainly do this -
parent.py
class A(object):
def __init__(self,obj):
self.obj_B = obj
def test(self):
self.obj_B.methodb()
child.py
from parent import A
class B(A):
def __init__(self,id):
self.id = id
super().__init__(self)
def methodb(self):
print("in method b with id:",self.id)
Now if you want to call it from class B object
b1 = B(1)
b1.test()
>>> in method b with id: 1
Or if you want to call it from class A object
b2 = B(2)
a = A(b2)
a.test()
>>> in method b with id: 2
You can even make new objects in super class by invoking class dict objects of the object passed to super class from child class.

How do I call a method on a specific base class in Python?

How do I call a method on a specific base class? I know that I can use super(C, self) in the below example to get automatic method resolution - but I want to be able to specify which base class's method I am calling?
class A(object):
def test(self):
print 'A'
class B(object):
def test(self):
print 'B'
class C(A,B):
def test(self):
print 'C'
Just name the "base class".
If you wanted to call say B.test from your C class:
class C(A,B):
def test(self):
B.test(self)
Example:
class A(object):
def test(self):
print 'A'
class B(object):
def test(self):
print 'B'
class C(A, B):
def test(self):
B.test(self)
c = C()
c.test()
Output:
$ python -i foo.py
B
>>>
See: Python Classes (Tutorial)

Implicitly invoking parent class initializer

class A(object):
def __init__(self, a, b, c):
#super(A, self).__init__()
super(self.__class__, self).__init__()
class B(A):
def __init__(self, b, c):
print super(B, self)
print super(self.__class__, self)
#super(B, self).__init__(1, b, c)
super(self.__class__, self).__init__(1, b, c)
class C(B):
def __init__(self, c):
#super(C, self).__init__(2, c)
super(self.__class__, self).__init__(2, c)
C(3)
In the above code, the commented out __init__ calls appear to the be the commonly accepted "smart" way to do super class initialization. However in the event that the class hierarchy is likely to change, I have been using the uncommented form, until recently.
It appears that in the call to the super constructor for B in the above hierarchy, that B.__init__ is called again, self.__class__ is actually C, not B as I had always assumed.
Is there some way in Python-2.x that I can maintain proper MRO (with respect to initializing all parent classes in the correct order) when calling super constructors while not naming the current class (the B in in super(B, self).__init__(1, b, c))?
Short answer: no, there's no way to implicitly invoke the right __init__ with the right arguments of the right parent class in Python 2.x.
Incidentally, the code as shown here is incorrect: if you use super().__init__, then all classes in your hierarchy must have the same signature in their __init__ methods. Otherwise your code can stop working if you introduce a new subclass that uses multiple inheritance.
See http://fuhm.net/super-harmful/ for a longer description of the issue (with pictures).
Your code has nothing to do with method resolution order. Method resolution comes in the case of multiple inheritance which is not the case of your example. Your code is simply wrong because you assume that self.__class__ is actually the same class of the one where the method is defined and this is wrong:
>>> class A(object):
... def __init__(self):
... print self.__class__
...
>>>
>>> class B(A):
... def __init__(self):
... A.__init__(self)
...
>>> B()
<class '__main__.B'>
<__main__.B object at 0x1bcfed0>
>>> A()
<class '__main__.A'>
<__main__.A object at 0x1bcff90>
>>>
so when you should call:
super(B, self).__init__(1, b, c)
you are indeed calling:
# super(self.__class__, self).__init__(1, b, c)
super(C, self).__init__(1, b, c)
EDIT: trying to better answer the question.
class A(object):
def __init__(self, a):
for cls in self.__class__.mro():
if cls is not object:
cls._init(self, a)
def _init(self, a):
print 'A._init'
self.a = a
class B(A):
def _init(self, a):
print 'B._init'
class C(A):
def _init(self, a):
print 'C._init'
class D(B, C):
def _init(self, a):
print 'D._init'
d = D(3)
print d.a
prints:
D._init
B._init
C._init
A._init
3
(A modified version of template pattern).
Now parents' methods are really called implicitly, but i have to agree with python zen where explicit is better than implicit because the code is lesser readable and the gain is poor. But beware that all _init methods have the same parameters, you cannot completely forget about parents and I don't suggest to do so.
For single inheritance, a better approach is explicitly calling parent's method, without invoking super. Doing so you don't have to name the current class, but still you must care about who is the parent's class.
Good reads are: how-does-pythons-super-do-the-right-thing and the links suggested in that question and in particularity Python's Super is nifty, but you can't use it
If hierarchy is likely to change is symptoms of bad design and has consequences in all the parts who are using that code and should not be encouraged.
EDIT 2
Another example comes me in mind, but which uses metaclasses. Urwid library uses metaclass to store an attribute, __super, in class so that you need just to access to that attribute.
Ex:
>>> class MetaSuper(type):
... """adding .__super"""
... def __init__(cls, name, bases, d):
... super(MetaSuper, cls).__init__(name, bases, d)
... if hasattr(cls, "_%s__super" % name):
... raise AttributeError, "Class has same name as one of its super classes"
... setattr(cls, "_%s__super" % name, super(cls))
...
>>> class A:
... __metaclass__ = MetaSuper
... def __init__(self, a):
... self.a = a
... print 'A.__init__'
...
>>> class B(A):
... def __init__(self, a):
... print 'B.__init__'
... self.__super.__init__(a)
...
>>> b = B(42)
B.__init__
A.__init__
>>> b.a
42
>>>
Perhaps what you are looking for is metaclasses?
class metawrap(type):
def __new__(mcs,name, bases, dict):
dict['bases'] = bases
return type.__new__(mcs,name,bases,dict)
class A(object):
def __init__(self):
pass
def test(self):
print "I am class A"
class B(A):
__metaclass__ = metawrap
def __init__(self):
pass
def test(self):
par = super(self.bases[0],self)
par.__thisclass__.test(self)
foo = B()
foo.test()
Prints "I am class A"
What the metaclass does is overriding the initial creation of the B class (not the object) and makes sure that the builtin dictionary for each B object now contains a bases array where you can find all the baseclasses for B
To my knowledge, the following isn't commonly done. But it does seem to work.
Methods in a given class definition always mangle double-underscore attributes to include the name of the class they're defined in. So, if you stash a reference to the class in name-mangled form where the instances can see it, you can use that in the call to super.
An example stashing the references on the object itself, by implementing __new__ on the baseclass:
def mangle(cls, name):
if not name.startswith('__'):
raise ValueError('name must start with double underscore')
return '_%s%s' % (cls.__name__, name)
class ClassStasher(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
for c in cls.mro():
setattr(obj, mangle(c, '__class'), c)
return obj
class A(ClassStasher):
def __init__(self):
print 'init in A', self.__class
super(self.__class, self).__init__()
class B(A):
def __init__(self):
print 'init in B', self.__class
super(self.__class, self).__init__()
class C(A):
def __init__(self):
print 'init in C', self.__class
super(self.__class, self).__init__()
class D(B, C):
def __init__(self):
print 'init in D', self.__class
super(self.__class, self).__init__()
d = D()
print d
And, doing a similar thing, but using a meta-class and stashing the __class references on the class objects themselves:
class ClassStasherType(type):
def __init__(cls, name, bases, attributes):
setattr(cls, mangle(cls, '__class'), cls)
class ClassStasher(object):
__metaclass__ = ClassStasherType
class A_meta(ClassStasher):
def __init__(self):
print 'init in A_meta', self.__class
super(self.__class, self).__init__()
class B_meta(A_meta):
def __init__(self):
print 'init in B_meta', self.__class
super(self.__class, self).__init__()
class C_meta(A_meta):
def __init__(self):
print 'init in C_meta', self.__class
super(self.__class, self).__init__()
class D_meta(B_meta, C_meta):
def __init__(self):
print 'init in D_meta', self.__class
super(self.__class, self).__init__()
d = D_meta()
print d
Running this all together, as one source file:
% python /tmp/junk.py
init in D <class '__main__.D'>
init in B <class '__main__.B'>
init in C <class '__main__.C'>
init in A <class '__main__.A'>
<__main__.D object at 0x1004a4a50>
init in D_meta <class '__main__.D_meta'>
init in B_meta <class '__main__.B_meta'>
init in C_meta <class '__main__.C_meta'>
init in A_meta <class '__main__.A_meta'>
<__main__.D_meta object at 0x1004a4bd0>

Categories

Resources