Wie kann eine Funktion Zugriff auf seine eigenen Attribute?
ist es möglich, den Zugriff auf die python-Funktion Objekt-Attribute in der Funktion Umfang?
z.B. wir haben
def f():
return SOMETHING
f._x = "foo"
f() # -> "foo"
nun, was hat sich ETWAS dabei zu sein, wenn wir wollen, um die _x-Attribut-Inhalt "foo" zurück? wenn es überhaupt möglich ist, (einfach)
Dank
UPDATE:
möchte ich die folgende Arbeit auch:
g = f
del f
g() # -> "foo"
UPDATE 2:
Aussage, dass es nicht möglich ist, (wenn es der Fall ist), und warum, ist befriedigender als die Bereitstellung einen Weg, wie man gefälschte es z.B. mit einem anderen Objekt als eine Funktion
- Was hindert Sie daran, einfach eine Funktion mit einem parameter?
- Space_C0wb0y: Parameter der Funktion sind off topic, das ist eine Frage, auf die Theorie, nicht die real-life-pragmatische Lösungen
- +1 für mich entdecken (und lernen), die Ecke von python Interna 😉
Du musst angemeldet sein, um einen Kommentar abzugeben.
Lösung
Machen von der Funktion default-Argumente, die eine Referenz auf die Funktion selbst.
Beispiel:
Erklärung
Den original-poster wollte eine Lösung, die nicht erfordert eine Globale name-lookup. Die einfache Lösung
führt eine Suche aus der globalen variable
f
bei jedem Aufruf, welche die Anforderungen nicht erfüllt. Wennf
gelöscht wird, dann schlägt die Funktion fehl. Je komplizierterinspect
Vorschlag scheitert in der gleichen Weise.Was wir wollen, ist die Durchführung die frühe Bindung und speichern die gebundene Referenz auf das Objekt selbst. Im folgenden wird konzeptionell das, was wir tun:
In der oben
self
ist eine lokale variable, so dass keine Globale Suche ausgeführt. Wir können jedoch nicht den code schreiben, wie es ist, weilf
ist noch nicht definiert, wenn wir versuchen, das binden der Standardwertself
zu. Stattdessen setzen wir den Standard-Wert nachf
definiert ist.Decorator
Hier ist eine einfache Dekorateur, um dies für Sie tun. Beachten Sie, dass die
self
argument kommen müssen, die letzten, im Gegensatz zu Methoden, bei denen dieself
kommt zuerst. Dies bedeutet auch, dass Sie müssen einen default-Wert, wenn alle Ihre anderen Argumente nehmen einen default-Wert.Beispiel:
f.func_defaults
umbenannt zuf.__defaults__
in Python 3 für die Konsistenz? Auch die Zweifel werden von anderen geteilt wirdself
als letztes argument. Denke, ich werde zu tun haben, die in der Regel wickeln, um einen anderen VerschlussKönnte man einfach eine Klasse verwenden, um dies zu tun
Gut, schauen wir uns an, was die Funktion ist:
Aha! Also das Attribut wurde Hinzugefügt, um die function-Objekt, aber es kann es nicht sehen, weil es ist auf der Suche nach globalen
x
statt.Können wir versuchen zu greifen, den Rahmen der Ausführung der Funktion, und versuchen zu schauen, was da ist (im Grunde das, was Anthony Kong vorgeschlagen, sondern w/o -
inspect
Modul):Aha! So können wir vielleicht den Namen der Funktion aus dem Namen der code-block und dann schauen Sie in die Runde-über den Weg für das Attribut? Sicher genug:
Das ist toll! Würde es aber stand die Umbenennung und Löschung der ursprünglichen Funktion?
Ah, sehr zweifelhaft. Die function-Objekt und den code-Objekt immer noch darauf bestehen, Sie heißen
foo
. Sicher genug, hier ist, wo es bricht:Dang! So im Allgemeinen ist es nicht getan werden kann durch Introspektion über die Ausführung frames. Die Probleme scheint zu sein, dass es einen Unterschied gibt zwischen Funktion Objekt und code-Objekt - code-Objekte sind das, was ausgeführt wird, und ist nur ein Attribut
func_code
von der Funktion-Objekt und als solches hat keinen Zugriff auf diefunc_dict
Attribut, wo unser Attributx
ist:Gibt es natürlich auch noch andere Schikanen, die Sie tun können, so dass es scheint, als Funktion, insbesondere der trick mit der definition der Klasse... aber das ist nicht eine Funktion per se. Es hängt alles davon ab, was Sie wirklich brauchen, zu tun.
Als workaround könntest du eine factory-Funktion zu beheben Ihr Aufgabenbereich:
Ich bezweifle, das ist die besten Weg, dies zu erreichen, aber Sie können den Zugriff auf die Attribute mithilfe der Methode name der Methode:
g = f; del f; print(g())
? 🙂x
Wert natürlich, dag
ist nur ein Verweis auf etwas, das ursprünglich referenzierte nur durchf
Hier ein decorator, der injiziert current_fun in die Funktionen globals vor Ausführung der Funktion. Es ist ganz der hack, aber auch sehr effektiv.
Hier ist ein Beispiel zur Verwendung
func_globals
muss ersetzt werden mit__globals__
. Ich erweiterte den Dekorateur, um zu bestätigen Sie den Namen für das Attribut:def introspective(f, attribute_name='self'):
und tatsächlich umbenannt zu@add_self
. Alle'current_fun'
vorkommen muss ersetzt werden mitattribute_name
. Standardmäßig ist der decorator wraps das Attributself
in der Funktion. Jetzt kann ich tunself.x
innerhalb von Funktionen und Klassen. Ich benutze es nie aber fürself.logger.info()
die jetzt schön Hinzugefügt, um alle Funktionen, Methoden und Klassen mit Dekorateure.Die Antwort ist ziemlich einfach. Verwenden Sie einfach die Tatsache Namen gesucht wird zum Zeitpunkt der Ausführung nicht kompiliert Zeit:
Wenn Sie möchten, es zu sein, völlig unabhängig von den Namen der Funktion, die Sie benötigen Rahmen-Magie. Zum Beispiel:
f3=f2; del f2; f3()
inspect
erfordert die Quell-Datei verfügbar sein?return f2._x
. Der code istco_name
ist der name der Funktion, wenn es definiert wurde, so wird die Funktion umbenannt, die Suche in der globalen Wörterbuch scheitern wird.Nutzt diese ein bisschen hackish Ansatz, aber es ist vielleicht die richtige, so weit gegeben, dass es funktioniert mit der
g()
Anruf auch. Es funktioniert, weil es sich auf was auch immer-bytecode-Prüfung durchgeführt wird, durch die dis Modul, wie eine Verknüpfung.Sieht es mehr hackish, als es wirklich ist zum Teil, weil die
dis.disassemble()
call-prints auf stdout, also ich umleiten, die in einem StringIO. Ich benutzedisassemble()
für die Funktion der Hervorhebung der Letzte Befehl (fügen Sie eineprint text
line in dort zu sehen, wie es aussieht) und dass macht es leichter zu greifen, die bisherigenLOAD_NAME
und die variable verwendet.Wäre es möglich, verwenden Sie einen Reiniger bytecode-Inspektions-Bibliothek, dies zu tun, ohne mit der
dis
Modul, aber das beweist, dass es möglich ist. Dies möglicherweise nicht die am meisten robuste Methode, aber dann wieder vielleicht wird es in den meisten Fällen funktionieren. Ich habe nicht lange genug stochert in Python-Interna oder bytecode zu wissen, ob die meistenCALL_FUNCTION
bytecodes werden eingeleitet sofort von Anweisungen, die der regex-trick würde herausgreifen.Dieser erzeugt die folgende Ausgabe:
Wie etwa die Verwendung einer Klasse statt einer Funktion und missbraucht die
__new__
Methode, um die Klasse callable als eine Funktion? Da die__new__
Methode bekommt den Namen der Klasse als ersten parameter, es ist der Zugriff auf alle Attribute der Klassewie in
dies funktioniert wie in
dann können Sie
Das Problem ist, dass selbst wenn das Objekt verhält sich wie eine Funktion, ist es nicht. Daher IDEs nicht in der Lage, Sie mit der Signatur.
Einen anderen Weg, dies zu erreichen, definieren Sie die Funktion innerhalb einer anderen Funktion und die äußere Funktion der inneren. Dann die innere Funktion zugreifen können sich über eine Schließung. Hier ein einfaches Beispiel:
Dann:
Wenn es nur eine Methode benötigt, aber Sie wollen eine Licht-Gewicht-Klasse mit gemeinsamen Klasse Zustand sowie einzelne Instanz Staat, könnten Sie versuchen, die Schließung Muster wie dieses:
Hier ist eine Strategie, ist wahrscheinlich schlimmer als die
func_defaults
Idee, aber ist trotzdem interessant. Es ist hacky, aber ich kann nicht an nichts denken praktisch falsch mit ihm.Können wir implementieren eine Funktion, die das verweisen auf sich selbst als eine Klasse mit einem einzigen
__new__
- Methode (der Methode, die normalerweise erzeugt ein neues Objekt der Klasse).Vielleicht diese Muster könnten nützlich sein, für eine logging-Funktion...
Einfach definieren Ihrer Funktion innerhalb einer closure:
Ich mag diese eine Menge.