In Python2 und Python3 wird im Stack-Trace der __name__
einer Funktion nicht verwendet, stattdessen wird der ursprüngliche Name (der nach def
angegeben wird) verwendet.
Betrachten Sie das Beispiel:
%Vor%Die Ausgabe ist:
%Vor% Warum? Wie ändere ich den Namen, der im Stack-Trace verwendet wird? Wo wird dann das Attribut __name__
verwendet?
Grundsätzlich hat also jede Funktion drei Dinge, die als Name der Funktion betrachtet werden können:
Es ist in f.__code__.co_name
gespeichert (wobei f
das Funktionsobjekt ist). Wenn Sie def orig_name
zum Erstellen einer Funktion verwenden, ist orig_name
der Name. Für Lambas ist es <lambda>
.
Dieses Attribut ist schreibgeschützt und kann nicht geändert werden. Die einzige Möglichkeit, eine Funktion mit dem benutzerdefinierten Namen in Runtime zu erstellen, die mir bekannt ist, ist exec
:
(Es gibt auch mehr Low-Level Möglichkeit, dies zu tun das wurde in einem Kommentar zu der Frage erwähnt.)
Die Unveränderbarkeit von co_name
macht eigentlich Sinn: Damit können Sie sicher sein, dass der Name, den Sie im Debugger (oder nur Stack-Trace) sehen, genau dem im Quellcode entspricht (zusammen mit dem Dateinamen und der Zeile) Nummer).
__name__
des Funktionsobjekts Es ist auch ein Alias für func_name
.
Sie können es ändern ( orig_name.__name__ = 'updated name'
) und Sie tun dies auf jeden Fall täglich: @functools.wraps
kopiert die __name__
der dekorierten Funktion in die neue.
__name__
wird von Tools wie pydoc
verwendet, deshalb benötigen Sie @functools.wraps
: Sie sehen also nicht die technischen Details jedes Decorators in Ihrer Dokumentation. Schauen Sie sich das Beispiel an:
Hier ist die pydoc
Ausgabe:
Mit wraps
gibt es kein Zeichen von decorated
in der Dokumentation.
Eine weitere Sache, die Funktionsname genannt werden kann (obwohl es kaum ist), ist der Name einer Variablen oder eines Attributs, in dem die Referenz auf diese Funktion gespeichert ist.
Wenn Sie eine Funktion mit def name
erstellen, wird das Attribut name
zum aktuellen Bereich hinzugefügt. Im Fall von lambda
sollten Sie das Ergebnis einer Variablen zuweisen: name = lambda: None
.
Offensichtlich können Sie mehr als einen Verweis auf die gleiche Funktion erstellen und alle Referenzen können unterschiedliche Namen haben.
Die einzige Möglichkeit, all diese drei Dinge miteinander zu verbinden, ist die def foo
-Anweisung, die das Funktionsobjekt mit __name__
und __code__.co_name
gleich foo
erstellt und sie dem foo
-Attribut des aktueller Umfang. Sie sind jedoch in keiner Weise gebunden und können sich voneinander unterscheiden:
Ausgabe:
%Vor%Pydoc:
%Vor%Ich danke anderen Menschen für Kommentare und Antworten, sie haben mir geholfen, meine Gedanken und mein Wissen zu organisieren .
Versucht, die CPython Implementierung zu erkunden, definitiv kein Experte. Wie in den Kommentaren erwähnt, wird beim Drucken des Stapeleintrags von f das Attribut f.__code__.co_name
wird verwendet . Außerdem wird f.__name__
anfänglich auf f.__code__.co_name
, aber wenn Sie ersteres ändern, wird letzteres nicht entsprechend geändert.
Deshalb habe ich versucht, das direkt zu ändern, aber es ist nicht möglich:
%Vor% Warum gibt es zwei Möglichkeiten, den Namen einer Funktion zu sagen? Nun, laut der Dokumentation ist __name__
definiert für "class, function, Methode, Deskriptor oder Generatorinstanz ", so wird sie im Fall von Funktionen diesem Attribut zugeordnet, für andere Objekte wird sie auf etwas anderes abgebildet.
Tags und Links python metaprogramming