En Python, les méthodes de classe et les méthodes statiques peuvent être définies à l'aide de décorateurs tels que @ classmethod
et @ staticmethod
.
Par contre, une méthode normale (méthode d'instance) peut être définie normalement, mais en fait, elle peut être appelée de deux manières:
class MyClass:
def mymethod(self,x):
print(x)
x = 1
myclass = MyClass()
myclass.mymethod(x) #Utilisation normale
MyClass(None,1) # !?!?
La deuxième utilisation consiste à utiliser la fonction définie telle quelle (le premier argument est «self», mais il n'est pas utilisé dans la fonction, donc «Aucun» convient).
Cependant, même s'il s'agit d'une méthode d'instance, si vous l'appelez par inadvertance comme une méthode de classe, cela provoquera une erreur déroutante.
Par exemple, lorsque vous prenez plusieurs arguments comme indiqué ci-dessous:
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]
Pour éviter cela, je veux être en colère quand je l'appelle quelque chose comme le second.
<détails>
Référence 1: stackoverflow- "Obtenir la classe de définition de l'objet méthode indépendant en Python 3" [Référence 2: Maîtriser Python-Qui convertit d'une méthode en une fonction? ](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)
Définissez un décorateur.
import functools
import inspect
# a.x -> type(a).__dict__['x'].__get__(a, type(a))
# A.x -> A.__dict__['x'].__get__(None, A)
#
# --> __get__Lorsque le premier argument de est None, lorsqu'il est appelé depuis la classe.
#Donc un.__dict__['x']À__get__Si vous laissez l'objet avec
#Vous pouvez le pirater gentiment. cependant,__get__(obe,objtype)Faites également attention à la valeur de retour de.
# a.Pour x, la valeur de retour doit être une méthode. En d'autres termes, celui avec le premier argument de la fonction fixe.
# A.Si c'est x, ne vous inquiétez pas (faites-en une erreur).
#def pure_instancemethod(func):
# functools.wraps(func)
# def wrapped_func(self,*args,**kwargs):
# if not isinstance(self,)
# raise TypeError("Pas une méthode de classe")
class PureInstanceMethod:
def __init__(self,func):
self.func = func
def __get__(self,obj,objtype):
if obj is None: #Appel de la classe:
raise TypeError("N'appelez pas de la classe Octopus")
else: #Appel depuis l'instance
def instancemethod(*args,**kwargs):
return self.func(obj,*args,**kwargs)
return instancemethod #Je retournerai la méthode
def __call__(self,*args,**kwargs):
return self.func(*args,**kwargs)
class MyClass:
@PureInstanceMethod
def mymethod(self,*x):
print(x)
# MyClass.__dict__["mymethod"] = pureinstancemethod(mymethod)Presque le même que.
#En d'autres termes, voici une instance de la méthode d'instance pure initialisée par 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: #Appel de la classe:
# > ---> 25 raise TypeError("N'appelez pas de la classe Octopus")
# > 26
# > 27 else: #Appel depuis l'instance
# >
# > TypeError:N'appelez pas de la classe Octopus
J'étais en colère en toute sécurité.