[PYTHON] Decorator (@pureinstansemethod), der eine reine Instanzmethode definiert

Vorwort

In Python können Klassenmethoden und statische Methoden mithilfe von Dekoratoren wie "@ classmethod" und "@ staticmethod" definiert werden. Auf der anderen Seite kann eine normale Methode (Instanzmethode) normal definiert werden, aber tatsächlich kann sie auf zwei Arten aufgerufen werden:

class MyClass:
    def mymethod(self,x):
        print(x)

x = 1
myclass = MyClass()

myclass.mymethod(x)  #Normaler Gebrauch
MyClass(None,1)  # !?!?

Die zweite Verwendung besteht darin, die definierte Funktion so zu verwenden, wie sie ist (das erste Argument ist "self", aber da es in der Funktion nicht verwendet wird, ist "None" in Ordnung).

Obwohl es sich um eine Instanzmethode handelt, führt dies zu einem verwirrenden Fehler, wenn Sie sie versehentlich wie eine Klassenmethode aufrufen.

Zum Beispiel, wenn Sie mehrere Argumente wie unten gezeigt verwenden:

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]

Um dies zu vermeiden, möchte ich wütend sein, wenn ich es so etwas wie das zweite nenne.

Supplement
In Python2 hat "myclass.mymethod" eine gebundene Methode und "MyClass.mymethod" eine ungebundene Methode zurückgegeben. Die (gebundene / ungebundene) Methode gilt für das erste Argument (auf self festgelegt / gibt einen Fehler zurück, wenn Sie eine Nicht-MyClass-Instanz verwenden). Mit anderen Worten, der Zweck dieser Zeit ist es, die Unbound-Methode der Python2-Ära wiederzubeleben.

](https://stackoverflow.com/questions/3589311/get-defining-class-of-unbound-method-object-in-python-3)

import functools
import inspect

# a.x -> type(a).__dict__['x'].__get__(a, type(a))
# A.x -> A.__dict__['x'].__get__(None, A)
#
# --> __get__
#.__dict__['x'][Referenz 1: stackoverflow- "Definieren der Klasse eines ungebundenen Methodenobjekts in Python 3" [Referenz 2: Beherrschen von Python - Wer konvertiert von einer Methode in eine Funktion? ](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) Definieren Sie einen Dekorateur. Wenn das erste Argument von None ist, wenn es von der Klasse aufgerufen wird. Also zu A.__get__Wenn Sie das Objekt mit verlassen
#Sie können es gut hacken. Jedoch,__get__(obe,objtype)Achten Sie auch auf den Rückgabewert von.
# a.Für x muss der Rückgabewert eine Methode sein. Mit anderen Worten, das mit dem ersten Argument der Funktion festgelegt.
# A.Wenn es x ist, mach dir keine Sorgen (mach es zu einem Fehler).

#def pure_instancemethod(func):
#    functools.wraps(func)
#    def wrapped_func(self,*args,**kwargs):
#        if not isinstance(self,)
#            raise TypeError("Keine Klassenmethode")

class PureInstanceMethod:
    def __init__(self,func):
        self.func = func
    
    def __get__(self,obj,objtype):
        if obj is None:  #Anruf aus der Klasse:
            raise TypeError("Rufen Sie nicht aus der Klasse Octopus an")
            
        else: #Aufruf von der Instanz
            def instancemethod(*args,**kwargs):
                return self.func(obj,*args,**kwargs)
            return instancemethod #Ich werde die Methode zurückgeben
        
    def __call__(self,*args,**kwargs):
        return self.func(*args,**kwargs)
            
class MyClass:
    
    @PureInstanceMethod
    def mymethod(self,*x):
        print(x)
    
    # MyClass.__dict__["mymethod"] = pureinstancemethod(mymethod)Fast das gleiche wie.
    #Mit anderen Worten, hier ist eine Instanz der von mymethod initialisierten reinen Instanzmethode.

Wie benutzt man

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:  #Anruf aus der Klasse:
# > ---> 25             raise TypeError("Rufen Sie nicht aus der Klasse Octopus an")
# >    26 
# >    27         else: #Aufruf von der Instanz
# > 
# > TypeError:Rufen Sie nicht aus der Klasse Octopus an

Ich war sicher wütend.

Recommended Posts

Decorator (@pureinstansemethod), der eine reine Instanzmethode definiert
Erstellen Sie eine gefälschte Klasse, die auch betrügt, ist Instanz
Erstellen Sie in Python einen Dekorator, der Argumente dynamisch akzeptiert. Erstellen Sie einen Dekorator