In Python, class methods and static methods can be defined using decorators such as @ classmethod and @staticmethod.
On the other hand, ordinary methods (instance methods) can be defined normally, but in fact they can be called in two ways:
class MyClass:
def mymethod(self,x):
print(x)
x = 1
myclass = MyClass()
myclass.mymethod(x) #Normal usage
MyClass(None,1) # !?!?
The second usage is to use the defined function as it is (the first argument is self, but it is not used in the function, so None is fine).
However, even though it is an instance method, if you inadvertently call it like a class method, it will cause an confusing error.
For example, if you take multiple arguments as below:
class MyClass:
def mymethod(self,*x):
print(x)
x = list(range(4))
myclass = MyClass()
myclass.mymethod(*x) # [0,1,2,3]
MyClass.mymethod(*x) # [1,2,3]
In order to avoid this, I want to be angry when I call it something like the second one.
Reference 1: stackoverflow-"Get defining class of unbound method object in Python 3" [Reference 2: Mastering Python-Who is converting from a method to a function? ](Https://python.ms/descriptor/#%E7%96%91%E5%95%8F-get-%E3%83%A1%E3%82%BD%E3%83%83%E3%83 % 89% E3% 81% A3% E3% 81% A6% E3% 81% AA% E3% 81% AB% EF% BC% 9F)
Define a decorator.
import functools
import inspect
# a.x -> type(a).__dict__['x'].__get__(a, type(a))
# A.x -> A.__dict__['x'].__get__(None, A)
#
# --> __get__When the first argument of is None, when it is called from the class.
#So A.__dict__['x']To__get__If you leave the object with
#You can hack it nicely. However,__get__(obe,objtype)Also pay attention to the return value of.
# a.For x, the return value must be a method. In other words, the one with the first argument of the function fixed.
# A.If it's x, don't worry (make an error).
#def pure_instancemethod(func):
# functools.wraps(func)
# def wrapped_func(self,*args,**kwargs):
# if not isinstance(self,)
# raise TypeError("Not a class method")
class PureInstanceMethod:
def __init__(self,func):
self.func = func
def __get__(self,obj,objtype):
if obj is None: #Call from class:
raise TypeError("Don't call from class Octopus")
else: #Call from instance
def instancemethod(*args,**kwargs):
return self.func(obj,*args,**kwargs)
return instancemethod #I'll return the method
def __call__(self,*args,**kwargs):
return self.func(*args,**kwargs)
class MyClass:
@PureInstanceMethod
def mymethod(self,*x):
print(x)
# MyClass.__dict__["mymethod"] = pureinstancemethod(mymethod)Almost the same as.
#In other words, here is an instance of the pure instance method initialized by mymethod.
myclass.mymethod(*[1,2,3])
# > (1, 2, 3)
MyClass.mymethod(*[1,2,3])
# > ---------------------------------------------------------------------------
# > TypeError Traceback (most recent call last)
# > <ipython-input-152-99447b4e3435> in <module>
# > ----> 1 MyClass.mymethod(*[1,2,3]) # [1,2,3]
# >
# > <ipython-input-147-39b9424a9215> in __get__(self, obj, objtype)
# > 23 def __get__(self,obj,objtype):
# > 24 if obj is None: #Call from class:
# > ---> 25 raise TypeError("Don't call from class Octopus")
# > 26
# > 27 else: #Call from instance
# >
# > TypeError:Don't call from class Octopus
I was angry safely.