Zusammenfassung
Verwenden Sie den Wrapper
-Helfer von python-varname
:
from varname.helpers import Wrapper
foo = Wrapper(dict())
# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2
Für den Teil der List Comprehension können Sie folgendes tun:
n_jobs = Wrapper()
users = Wrapper()
queues = Wrapper()
priorities = Wrapper()
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [d.name for d in list_of_dicts]
# ['n_jobs', 'users', 'queues', 'priorities']
# BITTE BEACHTEN Sie, dass Sie auf den durch d.value zugreifen müssen
Ich bin der Autor des python-varname
Pakets. Lassen Sie mich wissen, wenn Sie Fragen haben oder Probleme auf Github melden können.
Die ausführliche Antwort
Ist es überhaupt möglich?
Ja und Nein.
Wir rufen die Variablennamen zur Laufzeit ab, daher benötigen wir eine Funktion, die aufgerufen werden muss, um uns den Zugriff auf die vorherigen Frames zu ermöglichen, um die Variablennamen abzurufen. Deshalb benötigen wir dort einen Wrapper
. In dieser Funktion parsen wir zur Laufzeit den Quellcode/AST-Knoten in den vorherigen Frames, um den genauen Variablennamen zu erhalten.
Allerdings sind die Quellcode/AST-Knoten in den vorherigen Frames nicht immer verfügbar, oder sie könnten von anderen Umgebungen modifiziert werden (z.B.: mit der assert
-Anweisung von pytest
). Ein einfaches Beispiel ist, dass der Code über exec()
ausgeführt wird. Obwohl wir immer noch einige Informationen aus dem Bytecode abrufen können, erfordert dies zu viel Aufwand und ist auch fehleranfällig.
Wie kann man es machen?
Zunächst müssen wir identifizieren, in welchem Frame die Variable gegeben ist. Es ist nicht immer einfach der direkte vorherige Frame. Zum Beispiel können wir einen anderen Wrapper für die Funktion haben:
from varname import varname
def func():
return varname()
def wrapped():
return func()
x = wrapped()
In obigem Beispiel müssen wir den Frame im Inneren von wrapped
überspringen, um zum richtigen Frame x = wrapped()
zu gelangen, um das x
zu lokalisieren. Die Argumente frame
und ignore
von varname
ermöglichen es uns, einige dieser Zwischenframes zu überspringen. Weitere Details finden Sie in der README-Datei und der API-Dokumentation des Pakets.
Dann müssen wir den AST-Knoten parsen, um zu lokalisieren, wo der Variablen ein Wert zugewiesen wird (Funktionsaufruf). Es ist nicht immer nur eine einfache Zuweisung. Manchmal können komplexe AST-Knoten vorhanden sein, zum Beispiel x = [wrapped()]
. Wir müssen durch den AST-Baum navigieren, um die richtige Zuweisung zu identifizieren.
Wie zuverlässig ist es?
Sobald wir den Zuweisungsknoten identifiziert haben, ist es zuverlässig.
varname
hängt alles vom executing
Paket ab, um den Knoten zu finden. Der von executing erkannte Knoten ist garantiert der richtige (siehe auch dies).
Es funktioniert teilweise in Umgebungen, in denen andere AST-Tricks angewendet werden, einschließlich pytest, ipython, macropy, birdseye, reticulate mit R, etc. Weder executing noch varname funktionieren zu 100% mit diesen Umgebungen.
Brauchen wir ein Paket dafür?
Nun, wieder ja und nein.
Wenn Ihr Szenario einfach ist, ist der von @juan Isaza oder @scohe001 bereitgestellte Code wahrscheinlich ausreichend, um mit dem Fall umzugehen, in dem eine Variable im direkten vorherigen Frame definiert ist und der AST-Knoten eine einfache Zuweisung ist. Sie müssen einfach einen Frame zurückgehen und die Informationen dort abrufen.
Wenn das Szenario jedoch komplizierter wird oder wir verschiedene Anwendungsszenarien anpassen müssen, benötigen Sie wahrscheinlich ein Paket wie python-varname
, um damit umzugehen. Diese Szenarien könnten folgendes umfassen:
- freundlichere Meldungen präsentieren, wenn der Quellcode nicht verfügbar ist oder AST-Knoten nicht zugänglich sind
- Zwischenframes überspringen (ermöglicht es, dass die Funktion in anderen Zwischenframes gewickelt oder aufgerufen wird)
- Aufrufe von built-in Funktionen oder Bibliotheken automatisch ignorieren. Zum Beispiel:
x = str(func())
- mehrere Variablennamen auf der linken Seite der Zuweisung abrufen
- usw.
Was ist mit dem f-string
?
Wie die Antwort von @Aivar Paalberg zeigt. Es ist definitiv schnell und zuverlässig. Es wird jedoch nicht zur Laufzeit ausgeführt, das bedeutet, dass Sie wissen müssen, dass es sich um foo
handelt, bevor Sie den Namen ausgeben. Mit varname
müssen Sie jedoch nicht wissen, welcher Variablenname kommt:
from varname import varname
def func():
return varname()
# In externen Verwendungen
x = func() # 'x'
y = func() # 'y'
Zum Abschluss
python-varname
kann nicht nur den Variablennamen aus einer Zuweisung erkennen, sondern auch:
- Variablennamen direkt abrufen, mit
nameof
- das nächste sofortige Attribut finden, mit
will
- Argumentnamen/Quellen, die an eine Funktion übergeben wurden, mit
argname
Lesen Sie mehr in der Dokumentation.
Allerdings möchte ich abschließend sagen, versuchen Sie, es zu vermeiden, es zu verwenden, wann immer Sie können.
Denn Sie können nicht sicher sein, dass der Client-Code in einer Umgebung ausgeführt wird, in der der Quellknoten verfügbar ist oder der AST-Knoten zugänglich ist. Und natürlich kostet es Ressourcen, den Quellcode zu parsen, die Umgebung zu identifizieren, die AST-Knoten abzurufen und sie bei Bedarf auszuwerten.