#staticmethod, can anyone explain the following python code? - python

class A:
def __init__(self):
pass
#staticmethod
def a():
return "a"
class B1(A):
def __init__(self):
super().__init__()
#staticmethod
def a():
return "b"
class B2(A):
def __init__(self):
super().__init__()
class C1(B1):
def __init__(self):
super().__init__()
#staticmethod
def a():
return super(C1, C1).a()
class C2(B1):
def __init__(self):
super().__init__()
#staticmethod
def a():
return super(B1, B1).a()
So here's a tricky thing I'm having understanding.
B2().a() returns a, even though B2 doesn't have a method called a().
How come?
Also, I don't quite understand how staticmethod differs from the other methods.

Every class here inherits (directly or indirectly) from A (that's what class B2(A): is telling you).
Since they inherit from A, they have access to A's methods. All the #staticmethod decorator does is suppress passing self to the method implicitly when it's called on an instance, so that A.a() and A().a() work the same; similarly, B2.a() and B2().a() work the same way, invoking A.a().

Related

Handling custom __new__() and __del__() with inheritance

When I derive a class in Python, I need to call the Base.__init__(self) from the derived __init__(self) function like
class Base(object):
def __init__(self):
pass
class Der(Base):
def __init__(self) :
Base.__init__(self)
Do I need to do the same for __new__(self) and __del__(self) functions like
class Base(object):
def __new__(self):
pass
def __init__(self):
pass
def __del__(self) :
pass
class Der(Base):
def __new__(self):
Base.__new__(self)
def __init__(self) :
Base.__init__(self)
def __del__(self) :
Base.__del__(self)
I am wondering because nothing seems to go WRONG if I don't do that.
I am sure that python gc will take care, but is there anything I need to be worried about if I don't call them from Derived chain
The usage of __init__() and __del() is straightforward but not the __new()__
Since __new()__ returns an instance of the class, we need to call super().__new()__ till the object chain as given below
class Base(object):
def __new__(self):
return super().__new__(self)
class Derive(Base):
def __new__(self):
return super().__new__(self);
The __del()__ can be using similar to __init()__, calling Base.__del()__ is not mandatory unless and until some cleanup is required in base __del() function.
The correct way of writing the code asked in the question is
class Base(object):
def __new__(self):
return super().__new__(self)
def __init__(self):
self.Value = 200
def __del__(self):
pass
class Derive(Base):
def __new__(self):
return super().__new__(self);
def __init__(self):
Base.__init__(self)
def __del__(self):
Base.__del__(self)
It's always better not to implement __new()__ and __del()__ unless we really need it

Python: Inheriting methods of a parent class without being a child of the class

I can't seem to find information regarding what I'm trying to do, so I'm afraid the answer is "you can't do it" or "that's bad practice." But, here it goes:
Given the following:
Class A(object):
def __init__(self):
pass
def methoda(self):
return 1
Class C(object):
def __init__(self):
pass
def methodc(self):
return 2
import A, C
Class B(object):
def __init__(self, classC):
A.__init__(self)
if classC:
C.__init__(self)
def methodb(self):
return 2
Obviously, running:
b = A()
b.methoda()
Is going to crash with an error:
Unbound method __init()___ must be called with A class as first argument (got B instance instead)
However, I am basically looking for a way to make this work. My motivation:
There are classes (maybe in the future) that will duplicate a certain group of methods (say some fancy conversions). In an effort to reduce code, I'd like for the future classes to inherit the methods; but for legacy reasons, I don't want B to inherit C.
A couple solutions:
Don't use special methods directly:
class A(object):
def __init__(self):
self._init(self)
#staticmethod
def _init(self):
...actual initialization code here...
def methoda(self):
return 1
class C(object):
def __init__(self):
self._init(self)
#staticmethod
def _init(self):
...actual initialization code here...
def methodc(self):
return 2
import A, C
class B(object):
def __init__(self, classC):
A._init(self)
if classC:
C._init(self)
def methodb(self):
return 2
Or silly hacks involving copying from initialized objects:
import A, C
class B(object):
def __init__(self, classC):
vars(self).update(vars(A()))
if classC:
vars(self).update(vars(C()))
def methodb(self):
return 2
Note that none of these solutions will give access to methods from A or C on instances of B. That's just ugly. If you really need inheritance, use inheritance, don't do terrible things trying to simulate it poorly.
I ended up just inheriting multiple classes. It's not exactly the way I wanted it done, but it's cleaner and easier for the IDE to follow
Class A(object):
def __init__(self):
super(A, self).__init__()
pass
def methoda(self):
return 1
Class C(object):
def __init__(self):
super(C, self).__init__()
def _C_init(self):
# some init stuff
pass
def methodc(self):
return 1
Class B(A, C):
def __init__(self, use_C):
super(B, self).__init__()
if use_C:
self._C_init()
def methodb(self):
return 2

Method accessible only from class descendants in python

Let's say I have the following two classes
class A:
def own_method(self):
pass
def descendant_method(self):
pass
class B(A):
pass
and I want descendant_method to be callable from instances of B, but not of A, and own_method to be callable from everywhere.
I can think of several solutions, all unsatisfactory:
Check some field and manually raise NotImplementedError:
class A:
def __init__(self):
self.some_field = None
def own_method(self):
pass
def descendant_method(self):
if self.some_field is None:
raise NotImplementedError
class B(A):
def __init__(self):
super(B, self).__init__()
self.some_field = 'B'
pass
But this is modifying the method's runtime behaviour, which I don't want to do
Use a mixin:
class A:
def own_method(self):
pass
class AA:
def descendant_method(self):
pass
class B(AA, A):
pass
This is nice as long as descendant_method doesn't use much from A, or else we'll have to inherit AA(A) and this defies the whole point
make method private in A and redefine it in a metaclass:
class A:
def own_method(self):
pass
def __descendant_method(self):
pass
class AMeta(type):
def __new__(mcs, name, parents, dct):
par = parents[0]
desc_method_private_name = '_{}__descendant_method'.format(par.__name__)
if desc_method_private_name in par.__dict__:
dct['descendant_method'] = par.__dict__[desc_method_private_name]
return super(AMeta, mcs).__new__(mcs, name, parents, dct)
class B(A, metaclass=AMeta):
def __init__(self):
super(B, self).__init__()
This works, but obviously looks dirty, just like writing self.descendant_method = self._A__descendant_method in B itself.
What would be the right "pythonic" way of achieving this behaviour?
UPD: putting the method directly in B would work, of course, but I expect that A will have many descendants that will use this method and do not want to define it in every subclass.
What is so bad about making AA inherit from A? It's basically an abstract base class that adds additional functionality that isn't meant to be available in A. If you really don't want AA to ever be instantiated then the pythonic answer is not to worry about it, and just document that the user isn't meant to do that. Though if you're really insistent you can define __new__ to throw an error if the user tries to instantiate AA.
class A:
def f(self):
pass
class AA(A):
def g(self):
pass
def __new__(cls, *args, **kwargs):
if cls is AA:
raise TypeError("AA is not meant to be instansiated")
return super().__new__(cls)
class B(AA):
pass
Another alternative might be to make AA an Abstract Base Class. For this to work you will need to define at least one method as being abstract -- __init__ could do if there are no other methods you want to say are abstract.
from abc import ABCMeta, abstractmethod
class A:
def __init__(self, val):
self.val = val
def f(self):
pass
class AA(A, metaclass=ABCMeta):
#abstractmethod
def __init__(self, val):
super().__init__(val)
def g(self):
pass
class B(AA):
def __init__(self, val):
super().__init__(val)
Very finally, what's so bad about having the descendant method available on A, but just not using it. You are writing the code for A, so just don't use the method... You could even document the method that it isn't meant to be used directly by A, but is rather meant to be available to child classes. That way future developers will know your intentions.
As far as I can tell, this may be the most Pythonic way of accomplishing what you want:
class A:
def own_method(self):
pass
def descendant_method(self):
raise NotImplementedError
class B(A):
def descendant_method(self):
...
Another option could be the following:
class A:
def own_method(self):
pass
def _descendant_method(self):
pass
class B(A):
def descendant_method(self):
return self._descendant_method(self)
They're both Pythonic because it's explicit, readable, clear and concise.
It's explicit because it's not doing any unnecessary magic.
It's readable because
one can tell precisely what your doing, and what your intention was
at first glance.
It's clear because the leading single underscore is
a widely used convention in the Python community for private
(non-magic) methods—any developer that uses it should know to tread
with caution.
Choosing between one of these approaches will depend on how you intend on your use case. A more concrete example in your question would be helpful.
Try to check the class name using __class__.__name__ .
class A(object):
def descendant_method(self):
if self.__class__.__name__ == A.__name__:
raise NotImplementedError
print 'From descendant'
class B(A):
pass
b = B()
b.descendant_method()
a = A()
a.descendant_method()

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.

Categories

Resources