2012-05-29 3 views
7

Disclaimer Dies ist nur eine Übung in Meta-Programmierung, es hat keine praktische Zweck.Die Definition von __getattr__ und __getitem__ für eine Funktion hat keine Auswirkungen

ich zugewiesen habe __getitem__ und __getattr__ Methoden auf einem Funktionsobjekt, aber es keine Wirkung ...

def foo(): 
    print "foo!" 

foo.__getitem__ = lambda name: name 
foo.__getattr__ = lambda name: name 
foo.baz = 'baz' 

Sanity prüfen, ob wir können Eigenschaften zuweisen zu einer Funktion:

>>> foo.baz 
'baz' 

Ordentlich. Wie wäre es mit den "Magischen Gettern"?

>>> foo.bar 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'function' object has no attribute 'bar' 

>>> foo['foo'] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'function' object is not subscriptable 

>>> getattr(foo, 'bar') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'function' object has no attribute 'bar' 

Ist es möglich, ein "Magic Getter" auf einem Funktionsobjekt zu haben?

Antwort

6

Nein! Zuweisen von __getitem__ zu einer Instanz nicht auf funktioniert jede Objekttyp:

>>> class A(object): 
... pass 
... 
>>> a = A() 
>>> a.__getattr__ = lambda name: name 
>>> a.foo 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'A' object has no attribute 'foo' 

Und Sie nicht __getattr__ auf der integrierten Funktion Typ definieren:

>>> import types 
>>> types.FunctionType.__getitem__ = lambda name: name 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can't set attributes of built-in/extension type 'function' 

Und können Sie keine Unterklasse types.FunctionType:

>>> import types 
>>> class F(types.FunctionType): 
... pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Error when calling the metaclass bases 
type 'function' is not an acceptable base type 
+2

@kindall weist darauf hin, aber ich werde es hier erwähnen, so bleibt es bei der Antwort. New-Style-Klassen verwenden nicht die "normale" Methodenauflösung mit '__getattr__' und seinen Freunden. 'a.foo' wird intern in' type (a) .__ getattr __ ('foo') 'übersetzt. Daher wird die Eigenschaft '__getattr__', die in' a .__ dict__' gespeichert ist, nicht gefunden. Hoffe das macht Sinn ...: -/ – colinta

1

AHHA! Verwenden Sie __call__, und wickeln Sie die Funktion in F()

class F(object): 
    def __init__(self, fn): 
     self.__dict__['fn'] = fn 

    def __call__(self, *args, **kwargs): 
     return self.fn(*args, **kwargs) 

    def __getitem__(self, name): 
     return name 

    def __getattr__(self, name): 
     return name 

>>> foo = F(foo) 
>>> f.bar 
'bar' 
>>> f['foo'] 
'foo' 
>>> foo() 
foo! 
+2

Grundsätzlich beschreibst du deine Dekorateure :) –

+1

Yup, und ich habe damit als Dekorateur gespielt, aber interessante Sachen kaputt ... wenn ich eine Methode mit einer Klasse dekoriere, beim Aufruf der Methode es wird keine gebundene Methode. Ein "Klasse-als-Dekorateur" scheint also nicht das "Gleiche" zu sein wie eine "Funktion als Dekorateur". Wir werden sehen, ich werde meine Ergebnisse hier veröffentlichen. – colinta

+0

Sie sind beide identisch in dem, was sie bieten, beide liefern ein "Callable" -Objekt zurück. Es ist nur diese Klasse wie Dekorateure sind sauberer und sauberer –

2

Mindestens auf neue Stil-Klassen (die die einzige Art in Python 3 und die Art sind, sollten Sie in Python 2 verwendet werden), Python sucht nur nach magischen Methoden auf der Klasse (und ihren Vorfahren), niemals auf der Instanz. Docs here.

Und natürlich können Sie den Funktionstyp nicht ändern oder davon ableiten. Wie Sie jedoch herausgefunden haben, macht jede Klasse mit einer __call__() Methode aufrufbare Instanzen, also ist dies der richtige Weg.

+0

Alles stimmt - ich wollte ein bisschen mehr von der ganzen Geschichte teilen, so dass jeder, der hier stolperte, nicht in der Dokumentation stöbern müsste, um dieses Zeug zu finden. aber ja, New-Style-Klassen rufen 'type (obj) .__ getattr__' auf. Was ist dokumentiert, sicher, aber nicht intuitiv für mich ... warum nicht einfach die normale Methode Auflösung verwenden? – colinta

+0

"Das Grundprinzip hinter diesem Verhalten liegt in einer Reihe spezieller Methoden wie' __hash __() 'und' __repr __() ', die von allen Objekten implementiert werden, einschließlich Typobjekten. Wenn die implizite Suche dieser Methoden den konventionellen Lookupprozess verwendet würden sie fehlschlagen, wenn sie für das Typobjekt selbst aufgerufen würden. " – kindall

Verwandte Themen