2016-05-27 3 views
2

Ich möchte fragen, was ist der Zweck der einfachen Funktion und warum, wenn sich als Deskriptorklasse anders verhält?Zweck von __get__ einer einfachen Funktion

Meine Untersuchung:

import inspect 

def a(x, y): 
    return x + y 

def wr(f): 
    def wrapper(*args, **kwargs): 
     print f.__name__, 'called with', args, kwargs 
     return f(*args, **kwargs) 
    return wrapper 

print inspect.getsource(a) 
# def a(x, y): 
#  return x + y 

print inspect.getsource(a.__get__) # we cannot inspect it because it is a method-wrapper 
# Traceback (most recent call last): 
# ... 
#  'function, traceback, frame, or code object'.format(object)) 
# TypeError: <method-wrapper '__get__' of function object at 0x7fd43591e140> is not a module, class, method, function, traceback, frame, or code object 

a.__get__ = wr(a.__get__) # replace with function that delegates work and prints passed arguments 
a2 = a.__get__(2) # we can use __get__ for functools.partial purposes 
# __get__ called with (2,) {} 

print a.__class__, a2.__class__ # it looks like a is a normal function and a2 is a bound function, but there is no instance 
# <type 'function'> <type 'instancemethod'> 

print 'a2 result:', a2(3) 
# a2 result: 5 

print inspect.getsource(a2) # source the same as function a 
# def a(x, y): 
#  return x + y 

Wir wissen Descriptor Klasse __get__ Methodensignatur object.__get__(self, instance, owner) und es sieht so aus, dass es nicht funktioniert überein a.__get__ Signatur.

Antwort

1

Python-Funktionen sind Deskriptoren. So werden Methodenobjekte erstellt. Wenn Sie obj.method tun, wird das Deskriptor-Protokoll aktiviert, und die -Methode der Funktion wird aufgerufen. Dies gibt eine gebundene Methode zurück.

Deshalb sehen Sie a2 als ein instancemethod. Wenn Sie a.__get__(2) tun, übergeben Sie 2 als "Instanz" -Argument an . Wenn Sie print(a2) tun, sehen Sie <bound method ?.a of 2>, was darauf hinweist, dass Python a2 eine gebundene Methode des Objekts 2 ist.

Das Argument owner ist optional im Deskriptor-Protokoll (oder zumindest in der Implementierung der Funktionen), weshalb Sie mit nur einem Argument aufrufen können. Sie können Anruf a.__get__(2, 1) und erhalten Sie ein ähnliches Objekt zurück.

+0

Wenn wir rufen '__get __ (self, beispielsweise Eigentümer)' auf Funktion als Argumente übergeben werden : 'self' ist eine Funktion selbst, die Instanz ist' 2' und der Besitzer ist 'None', da es optional ist. Funktionen '__get__'-Methode erwartet, dass die Funktion selbst als erstes Argument eine Instanz (' self') erwartet, daher gibt sie eine gebundene Methode zurück, die immer eine übergebene Instanz als erstes Argument erhält. Da wir an Stelle der Instanz '2' übergeben, erhalten wir '2' als erstes Argument in unserer 'a2'-Funktion. Hab ich recht? –

+0

@ user1915011: Ich bin mir nicht sicher, ob ich dich verstehe. 'a .__ get__' interessiert nicht, welche Argumente' a' akzeptiert. Das "self", das an "a .__ get__" übergeben wird, ist, wie Sie sagen, die Funktion "a" selbst. 'a .__ get__' überprüft nicht, welche Argumente' a' akzeptiert. Wenn 'a' eine Funktion ist, gibt 'a .__ get__' * always * ein gebundenes Methodenobjekt zurück, es sei denn, Sie übergeben' None' als Argument "instance" (in diesem Fall gibt es eine ungebundene Methode zurück). – BrenBarn

1

Dieser ist ein Standarddeskriptor . Das Datenmodell spiegelt dies nicht wider, aber das owner-Argument zu wird häufig als optional angegeben, da es keine zusätzlichen Informationen für ein NoneNone10 liefert. Dies verletzt nicht das Deskriptorprotokoll.

A __get__ die Funktion in der Regel ist der normale Weg Descriptor __get__ Methoden aufgerufen als Teil Attribut Zugriff aufgerufen,:

class Foo(object): 
    def bar(self): 
     return 3 

foo = Foo() 

# The following attribute access calls bar.__get__(foo, Foo) to create a method object. 
bar_method = foo.bar 
Verwandte Themen