Ich habe diese Frage überprüft, weil ich mit RPy2 eine Python-Variable mit einem gleichnamigen R-Namen übergeben möchte. Ein nutzloses Beispiel (aber in der Nähe meiner Anwendung): def to_R( py_var ): r.assign( 'py_var', py_var )Die Daten in (Py) py_var der R-Umgebung zuweisen und denselben Namen haben. Es wäre nützlich für mich, stattdessen r.assign( py_var.stringof, py_var )a la D zu tun, da der an mein fn übergebene Variablenname to_rnicht unbedingt ist py_var.
Matthew Turner
4
Eine Möglichkeit, dies zu nutzen, besteht darin, dass eine Assert-Anweisung fehlschlägt. Sie können dem Benutzer den genauen fraglichen Variablennamen mitteilen, während Sie Ihren Code generisch halten, z. B. AssertionError: 'Something_else' muss eine Zahl größer als 5 sein. Anschließend können Sie jede Variable testen, die größer als 5 sein muss, und den Variablennamen abrufen in der AssertionError-Nachricht.
Nu Everest
Antworten:
50
TL; DR: Nicht möglich. Siehe 'Schlussfolgerung' am Ende.
Es gibt ein Verwendungsszenario, in dem Sie dies möglicherweise benötigen. Ich impliziere nicht, dass es keine besseren Möglichkeiten gibt oder die gleiche Funktionalität erreicht.
Dies wäre nützlich, um im Fehlerfall, in Debug-Modi und ähnlichen Situationen eine beliebige Liste von Wörterbüchern zu "sichern".
Was benötigt würde, ist die Umkehrung der eval()Funktion:
get_indentifier_name_missing_function()
Dies würde einen Bezeichnernamen ('Variable', 'Wörterbuch' usw.) als Argument verwenden und eine Zeichenfolge zurückgeben, die den Namen des Bezeichners enthält.
Betrachten Sie den folgenden aktuellen Stand der Dinge:
random_function(argument_data)
Wenn man einen Bezeichnernamen ('Funktion', 'Variable', 'Wörterbuch' usw.) argument_dataan einen random_function()(anderen Bezeichnernamen) übergibt, übergibt man tatsächlich einen Bezeichner (zB :) an einen <argument_data object at 0xb1ce10>anderen Bezeichner (zB :) <function random_function at 0xafff78>):
<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)
Nach meinem Verständnis wird nur die Speicheradresse an die Funktion übergeben:
<function at 0xafff78>(<object at 0xb1ce10>)
Daher müsste eine Zeichenfolge als Argument übergeben werden, random_function()damit diese Funktion den Bezeichnernamen des Arguments hat:
random_function('argument_data')
Innerhalb der random_function ()
defrandom_function(first_argument):
würde man den bereits gelieferten String verwenden, 'argument_data'um:
dienen als 'Bezeichnername' (zum Anzeigen, Protokollieren, Teilen / Concat von Zeichenfolgen, was auch immer)
Geben Sie die eval()Funktion ein, um einen Verweis auf die tatsächliche Kennung und damit einen Verweis auf die realen Daten zu erhalten:
print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))
Dies funktioniert leider nicht in allen Fällen. Es funktioniert nur , wenn die random_function()das lösen kann 'argument_data'Zeichenfolge auf eine tatsächliche Kennung. Dh wenn argument_datader Bezeichnername im random_function()Namespace des ' verfügbar ist .
Dies ist nicht immer der Fall:
# main1.pyimport some_module1
argument_data = 'my data'
some_module1.random_function('argument_data')
# some_module1.pydefrandom_function(first_argument):
print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))
######
Erwartete Ergebnisse wären:
Currently working on: argument_data
here comes the data: my data
Da argument_datader Bezeichnername im random_function()Namespace des ' nicht verfügbar ist , würde dies stattdessen Folgendes ergeben:
Currently working on argument_data
Traceback (most recent call last):
File "~/main1.py", line 6, in <module>
some_module1.random_function('argument_data')
File "~/some_module1.py", line 4, in random_function
some_internal_var = eval(first_argument)
File "<string>", line 1, in <module>
NameError: name 'argument_data'isnot defined
Betrachten Sie nun die hypotetische Verwendung von a, get_indentifier_name_missing_function()die sich wie oben beschrieben verhalten würde.
Leider get_indentifier_name_missing_function()nicht sehen würde das ‚Original‘ Bezeichnernamen ( some_dictionary_, some_other_dictionary_2, some_other_dictionary_n). Es würde nur den a_dictionary_objectBezeichnernamen sehen.
Die Umkehrung der eval()Funktion ist in diesem Fall also nicht so nützlich.
Derzeit müsste man dies tun:
# main2.py same as above, except:for each_one_of_my_dictionaries_names in ( 'some_dictionary_1',
'some_other_dictionary_2',
'...',
'some_other_dictionary_n' ):
some_module2.some_function( { each_one_of_my_dictionaries_names :
eval(each_one_of_my_dictionaries_names) } )
# some_module2.pydefsome_function(a_dictionary_name_object_container):for _dictionary_name, _dictionary_object in a_dictionary_name_object_container.items():
for _key, _value in _dictionary_object.items():
print( str(_dictionary_name) +
" " +
str(_key) +
" = " +
str(_value) )
######
Abschließend:
Python übergibt nur Speicheradressen als Argumente an Funktionen.
Zeichenfolgen, die den Namen eines Bezeichners darstellen, können von der eval()Funktion nur dann auf den tatsächlichen Bezeichner zurückgeführt werden , wenn der Namensbezeichner im aktuellen Namespace verfügbar ist.
Eine hypothetische Umkehrung der eval()Funktion wäre in Fällen nicht sinnvoll, in denen der Bezeichnername vom aufrufenden Code nicht direkt "gesehen" wird. ZB innerhalb einer aufgerufenen Funktion.
Derzeit muss man an eine Funktion übergeben:
Die Zeichenfolge, die den Bezeichnernamen darstellt
die tatsächliche Kennung (Speicheradresse)
Dies kann erreicht werden, indem sowohl die 'string'als eval('string')auch die aufgerufene Funktion gleichzeitig übergeben werden. Ich denke, dies ist die allgemeinste Methode, um dieses Ei-Huhn-Problem über beliebige Funktionen, Module und Namespaces hinweg zu lösen, ohne Eckfalllösungen zu verwenden. Der einzige Nachteil ist die Verwendung der eval()Funktion, die leicht zu ungesichertem Code führen kann. Es muss darauf geachtet werden, die eval()Funktion nicht mit so gut wie allem zu versorgen, insbesondere nicht ungefilterten externen Eingabedaten.
Dies ist eine hervorragende Zusammenfassung und die Art von qualitativ hochwertigen Inhalten, für die ich hierher komme.
Brendan
4
In Python stimmt etwas nicht, wenn wir zum Erhalten des Namens eines Objekts eine 5-seitige Antwort auf StackOverflow benötigen. : /
Seymour
1
Ein tl; dr wäre nett.
Nimitz14
@ Nimitz14 Enthalten TL; DR. Fühlen Sie sich frei, Änderungen und Korrekturen vorzuschlagen.
Petru Zaharia
Das TLDR gibt an, dass es nicht möglich ist, das zu erreichen, was vom OP gefordert wurde. Die Antwort von @Alice und andere ähnliche Antworten, bei denen die Verwendung von Einheimischen () oder Globalen () vorgeschlagen wird, erreichen genau das. Diese TLDR ist also irreführend und sollte nicht die akzeptierte Antwort sein.
Robyc
13
Ich habe nach dieser Frage gesucht, weil ich wollte, dass ein Python-Programm Zuweisungsanweisungen für einige der Variablen im Programm druckt. Beispielsweise könnte "foo = 3, bar = 21, baz = 432" gedruckt werden. Die Druckfunktion würde die Variablennamen in Zeichenfolgenform benötigen. Ich hätte meinen Code mit den Zeichenfolgen "foo", "bar" und "baz" versehen können, aber das fühlte sich an, als würde ich mich wiederholen. Nachdem ich die vorherigen Antworten gelesen hatte, entwickelte ich die folgende Lösung.
Die Funktion globals () verhält sich wie ein Diktat mit Variablennamen (in Form von Zeichenfolgen) als Schlüssel. Ich wollte von globals () den Schlüssel abrufen, der dem Wert jeder Variablen entspricht. Die Methode globals (). Items () gibt eine Liste von Tupeln zurück. In jedem Tupel ist das erste Element der Variablenname (als Zeichenfolge) und das zweite der Variablenwert. Meine Funktion variablename () durchsucht diese Liste nach den Variablennamen, die dem Wert der Variablen entsprechen, deren Namen ich in Zeichenfolgenform benötige.
Die Funktion itertools.ifilter () führt die Suche durch, indem sie jedes Tupel in der Liste globals (). Items () mit der Funktion testet lambda x: var is globals()[x[0]]. In dieser Funktion ist x das zu testende Tupel; x [0] ist der Variablenname (als Zeichenfolge) und x [1] ist der Wert. Die Lambda-Funktion prüft, ob der Wert der getesteten Variablen mit dem Wert der an Variablenname () übergebenen Variablen übereinstimmt. Tatsächlich istestet die Lambda-Funktion mithilfe des Operators, ob der Name der getesteten Variablen an genau dasselbe Objekt gebunden ist wie die an variablename () übergebene Variable. In diesem Fall besteht das Tupel den Test und wird von ifilter () zurückgegeben.
Die Funktion itertools.ifilter () gibt tatsächlich einen Iterator zurück, der keine Ergebnisse zurückgibt, bis er ordnungsgemäß aufgerufen wird. Um es richtig aufzurufen, habe ich es in ein Listenverständnis eingefügt [tpl[0] for tpl ... globals().items())]. Das Listenverständnis speichert nur den Variablennamen tpl[0]und ignoriert den Variablenwert. Die erstellte Liste enthält einen oder mehrere Namen (als Zeichenfolgen), die an den Wert der an variablename () übergebenen Variablen gebunden sind.
Bei den unten gezeigten Verwendungen von Variablenname () wird die gewünschte Zeichenfolge als Element in einer Liste zurückgegeben. In vielen Fällen ist dies das einzige Element in der Liste. Wenn jedoch einem anderen Variablennamen der gleiche Wert zugewiesen wird, ist die Liste länger.
>>> defvariablename(var):... import itertools
... return [tpl[0] for tpl in... itertools.ifilter(lambda x: var is x[1], globals().items())]
... >>> var = {}
>>> variablename(var)
['var']
>>> something_else = 3>>> variablename(something_else)
['something_else']
>>> yet_another = 3>>> variablename(something_else)
['yet_another', 'something_else']
Bitte bearbeiten Sie Ihren Beitrag für Formatierungsprobleme. Es ist schwer zu verstehen, was Sie sagen.
Yhw42
5
Es ist eine wahre Freude, einen Beitrag zu lesen, der die Frage beantwortet, ohne darüber zu schimpfen, warum die Frage gestellt wird.
user5920660
1
Beachten Sie, dass derselbe Wert an mehrere Namen gebunden werden kann. In diesem Fall gibt der obige Code mehrere Namen aus. Es gibt keine Möglichkeit zu wissen, welcher Name der "richtige" ist.
Steveha
7
Technisch gesehen stehen Ihnen die Informationen zur Verfügung, aber wie andere gefragt haben, wie würden Sie sie sinnvoll nutzen?
Dies zeigt, dass der Variablenname im globals () -Wörterbuch als Zeichenfolge vorhanden ist.
>>> globals().keys()[2]
'x'
In diesem Fall ist es der dritte Schlüssel, aber es gibt keine zuverlässige Möglichkeit zu wissen, wo ein bestimmter Variablenname landen wird
>>> for k inglobals().keys():
... ifnot k.startswith("_"):
... print k
...
x
>>>
Sie könnten Systemvariablen wie diese herausfiltern, aber Sie werden trotzdem alle Ihre eigenen Elemente erhalten. Durch einfaches Ausführen des obigen Codes wurde eine weitere Variable "k" erstellt, die die Position von "x" im Diktat geändert hat.
Aber vielleicht ist dies ein nützlicher Anfang für Sie. Wenn Sie uns mitteilen, wofür Sie diese Funktion wünschen, können möglicherweise hilfreichere Informationen bereitgestellt werden.
Chris, dein Kommentar scheint sich nicht auf meine Antwort oder die ursprüngliche Frage zu beziehen. Wen schaltest du und warum? Sie wissen nicht, ob er Produktionscode schreibt oder nur mit Sprachfunktionen für seine eigene Ausbildung experimentiert.
Todd
7
Das ist nicht möglich.
In Python gibt es wirklich keine "Variable". Was Python wirklich hat, sind "Namen", an die Objekte gebunden sein können. Für das Objekt spielt es keine Rolle, an welche Namen es gegebenenfalls gebunden sein könnte. Es könnte an Dutzende verschiedener Namen gebunden sein oder an keinen.
Betrachten Sie dieses Beispiel:
foo = 1
bar = 1
baz = 1
Angenommen, Sie haben das Integer-Objekt mit dem Wert 1 und möchten rückwärts arbeiten und seinen Namen finden. Was würden Sie drucken? An drei verschiedene Namen ist dieses Objekt gebunden, und alle sind gleichermaßen gültig.
In Python ist ein Name eine Möglichkeit, auf ein Objekt zuzugreifen. Es gibt also keine Möglichkeit, direkt mit Namen zu arbeiten. Es gibt vielleicht eine clevere Möglichkeit, die Python-Bytecodes zu hacken oder etwas, um den Wert des Namens zu ermitteln, aber das ist bestenfalls ein Salon-Trick.
Wenn Sie wissen, dass Sie print foodrucken möchten "foo", können Sie dies auch gleich ausführen print "foo".
EDIT: Ich habe den Wortlaut leicht geändert, um dies klarer zu machen. Auch hier ist ein noch besseres Beispiel:
foo = 1
bar = foo
baz = foo
In der Praxis verwendet Python dasselbe Objekt für Ganzzahlen mit gemeinsamen Werten wie 0 oder 1, sodass das erste Beispiel dasselbe Objekt an alle drei Namen binden sollte. Dieses Beispiel ist jedoch glasklar: Das gleiche Objekt ist an foo, bar und baz gebunden.
Es gibt eine Möglichkeit, mit diesen Namen zu arbeiten, die globals () vorschreiben, aber es ist nicht klar, wie man damit das macht, was das OP verlangt.
Todd
natürlich ist es möglich . und das ist ziemlich trivial (es löst sowieso das Problem des OP). Es ist nur etwas, was niemand tun sollte.
SilentGhost
Sie sagen, es ist nicht möglich. Ist aber möglich. Siehe andere Antworten. @ SilentGhost: Kannst du klarstellen, warum "niemand es tun möchte"? Ich denke, es hängt von der Anwendung ab. Was ist dein Argument?
Robyc
@Robyc Du sagst "Noch ist möglich." Okay. Ich gab Beispiele verbindlich foobarund bazalles zu 1. Wie heißt dann " 1?" Wenn Sie alle Globals durchsehen, können Sie eine Liste mit Variablennamen zurückgeben: ['foo', 'bar', 'baz'](in zufälliger Reihenfolge). Okay. Was ist die Verwendung dieser Liste? Ist einer der Namen der "wahre" Name von 1? (Nein.) Diejenigen von uns, die "es" sagen, sind sich nicht alle einig, dass Sie durch Globale schauen und alle Namen finden könnten; Wir glauben einfach nicht, dass dies eine nützliche Sache ist. Wie gesagt: Ein Objekt "könnte an Dutzende verschiedener Namen gebunden sein oder an keinen."
Steveha
3
Hier ist eine kurze Variante, mit der Sie ein beliebiges Verzeichnis angeben können. Das Problem bei der Verwendung von Verzeichnissen zum Auffinden von Daten besteht darin, dass mehrere Variablen denselben Wert haben können. Dieser Code gibt also eine Liste möglicher Variablen zurück.
defvarname( var, dir=locals()):return [ key for key, val indir.items() ifid( val) == id( var)]
Sie müssen sich irgendwie auf die Variable beziehen, deren Namen Sie drucken möchten. So würde es aussehen:
print varname(something_else)
Es gibt keine solche Funktion, aber wenn es sie gäbe, wäre sie irgendwie sinnlos. Sie müssen eingeben something_else, also können Sie auch links und rechts davon Anführungszeichen eingeben, um den Namen als Zeichenfolge zu drucken:
Was versuchst du zu erreichen? Es gibt absolut keinen Grund, jemals das zu tun, was Sie beschreiben, und es gibt wahrscheinlich eine viel bessere Lösung für das Problem, das Sie lösen möchten.
Die naheliegendste Alternative zu Ihrer Anfrage ist ein Wörterbuch. Zum Beispiel:
Das ist ziemlich cool, aber so automatisch, wie ich es gerne hätte. Danke für den Tipp =]
Brandon Pelfrey
"Es gibt absolut keinen Grund, jemals das zu tun, was Sie beschreiben" - Wir haben hier eine lokale allwissende Einheit. Es gibt tatsächlich einige gute Anwendungsfälle dafür.
MatrixTheatrics
2
Tut Django dies nicht beim Generieren von Feldnamen?
Ich denke, in Django-Modellen sind Felder Attribute einer Klasse oder Instanz. Das Abrufen von Attributnamen ist nicht dasselbe wie das Konvertieren von Variablennamen in Zeichenfolgen.
WeizhongTu
2
Ich denke, das ist eine coole Lösung und ich nehme an, das Beste, was Sie bekommen können. Aber sehen Sie eine Möglichkeit, mit den mehrdeutigen Ergebnissen umzugehen, und Ihre Funktion kann zurückkehren? Da sich der Operator "is" bei Ganzzahl- Shows unerwartet verhält , werden niedrige Ganzzahlen und Zeichenfolgen mit demselben Wert von Python zwischengespeichert, sodass Ihre Variablennamenfunktion mit hoher Wahrscheinlichkeit mehrdeutige Ergebnisse liefern kann. In meinem Fall möchte ich einen Dekorateur erstellen, der einer Klasse eine neue Variable mit dem Varialbenamen hinzufügt, den ich übergebe:
Aber wenn Ihre Methode mehrdeutige Ergebnisse zurückgibt, wie kann ich den Namen der Variablen kennen, die ich hinzugefügt habe?
var any_var="myvarcontent"
var myvar="myvarcontent"@inject(myvar)classmyclasss():defmyclass_method(self):print self.__myvar #I can not be sure, that this variable will be set...
Wenn ich auch die lokale Liste überprüfen würde, könnte ich vielleicht zumindest die "Abhängigkeit" -Variable aus der Liste entfernen, aber dies ist kein verlässliches Ergebnis.
Es ist nicht sehr pythonesk, aber ich war neugierig und habe diese Lösung gefunden. Sie müssen das globale Wörterbuch duplizieren, da sich seine Größe ändert, sobald Sie eine neue Variable definieren.
defvar_to_name(var):# noinspection PyTypeChecker
dict_vars = dict(globals().items())
var_string = Nonefor name in dict_vars.keys():
if dict_vars[name] is var:
var_string = name
breakreturn var_string
if __name__ == "__main__":
test = 3
print(f"test = {test}")
print(f"variable name: {var_to_name(test)}")
Sie suchen nach dem globalsDiktat. Genau das wurde in einer früheren Antwort getan, ohne zusätzliche Variablen zu erstellen und zu verwenden itertools. Obwohl die Antwort gut ist, denke ich, da eine ähnliche Lösung bereitgestellt wurde, sollten Sie dies unterstützen und Wiederholungen vermeiden.
def to_R( py_var ): r.assign( 'py_var', py_var )
Die Daten in (Py) py_var der R-Umgebung zuweisen und denselben Namen haben. Es wäre nützlich für mich, stattdessenr.assign( py_var.stringof, py_var )
a la D zu tun, da der an mein fn übergebene Variablennameto_r
nicht unbedingt istpy_var
.Antworten:
TL; DR: Nicht möglich. Siehe 'Schlussfolgerung' am Ende.
Es gibt ein Verwendungsszenario, in dem Sie dies möglicherweise benötigen. Ich impliziere nicht, dass es keine besseren Möglichkeiten gibt oder die gleiche Funktionalität erreicht.
Dies wäre nützlich, um im Fehlerfall, in Debug-Modi und ähnlichen Situationen eine beliebige Liste von Wörterbüchern zu "sichern".
Was benötigt würde, ist die Umkehrung der
eval()
Funktion:Dies würde einen Bezeichnernamen ('Variable', 'Wörterbuch' usw.) als Argument verwenden und eine Zeichenfolge zurückgeben, die den Namen des Bezeichners enthält.
Betrachten Sie den folgenden aktuellen Stand der Dinge:
Wenn man einen Bezeichnernamen ('Funktion', 'Variable', 'Wörterbuch' usw.)
argument_data
an einenrandom_function()
(anderen Bezeichnernamen) übergibt, übergibt man tatsächlich einen Bezeichner (zB :) an einen<argument_data object at 0xb1ce10>
anderen Bezeichner (zB :)<function random_function at 0xafff78>
):<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)
Nach meinem Verständnis wird nur die Speicheradresse an die Funktion übergeben:
<function at 0xafff78>(<object at 0xb1ce10>)
Daher müsste eine Zeichenfolge als Argument übergeben werden,
random_function()
damit diese Funktion den Bezeichnernamen des Arguments hat:random_function('argument_data')
Innerhalb der random_function ()
def random_function(first_argument):
würde man den bereits gelieferten String verwenden,
'argument_data'
um:dienen als 'Bezeichnername' (zum Anzeigen, Protokollieren, Teilen / Concat von Zeichenfolgen, was auch immer)
Geben Sie die
eval()
Funktion ein, um einen Verweis auf die tatsächliche Kennung und damit einen Verweis auf die realen Daten zu erhalten:print("Currently working on", first_argument) some_internal_var = eval(first_argument) print("here comes the data: " + str(some_internal_var))
Dies funktioniert leider nicht in allen Fällen. Es funktioniert nur , wenn die
random_function()
das lösen kann'argument_data'
Zeichenfolge auf eine tatsächliche Kennung. Dh wennargument_data
der Bezeichnername imrandom_function()
Namespace des ' verfügbar ist .Dies ist nicht immer der Fall:
# main1.py import some_module1 argument_data = 'my data' some_module1.random_function('argument_data') # some_module1.py def random_function(first_argument): print("Currently working on", first_argument) some_internal_var = eval(first_argument) print("here comes the data: " + str(some_internal_var)) ######
Erwartete Ergebnisse wären:
Da
argument_data
der Bezeichnername imrandom_function()
Namespace des ' nicht verfügbar ist , würde dies stattdessen Folgendes ergeben:Currently working on argument_data Traceback (most recent call last): File "~/main1.py", line 6, in <module> some_module1.random_function('argument_data') File "~/some_module1.py", line 4, in random_function some_internal_var = eval(first_argument) File "<string>", line 1, in <module> NameError: name 'argument_data' is not defined
Betrachten Sie nun die hypotetische Verwendung von a,
get_indentifier_name_missing_function()
die sich wie oben beschrieben verhalten würde.Hier ist ein Dummy-Python 3.0-Code :.
# main2.py import some_module2 some_dictionary_1 = { 'definition_1':'text_1', 'definition_2':'text_2', 'etc':'etc.' } some_other_dictionary_2 = { 'key_3':'value_3', 'key_4':'value_4', 'etc':'etc.' } # # more such stuff # some_other_dictionary_n = { 'random_n':'random_n', 'etc':'etc.' } for each_one_of_my_dictionaries in ( some_dictionary_1, some_other_dictionary_2, ..., some_other_dictionary_n ): some_module2.some_function(each_one_of_my_dictionaries) # some_module2.py def some_function(a_dictionary_object): for _key, _value in a_dictionary_object.items(): print( get_indentifier_name_missing_function(a_dictionary_object) + " " + str(_key) + " = " + str(_value) ) ######
Erwartete Ergebnisse wären:
Leider
get_indentifier_name_missing_function()
nicht sehen würde das ‚Original‘ Bezeichnernamen (some_dictionary_
,some_other_dictionary_2
,some_other_dictionary_n
). Es würde nur dena_dictionary_object
Bezeichnernamen sehen.Daher wäre das eigentliche Ergebnis eher:
Die Umkehrung der
eval()
Funktion ist in diesem Fall also nicht so nützlich.Derzeit müsste man dies tun:
# main2.py same as above, except: for each_one_of_my_dictionaries_names in ( 'some_dictionary_1', 'some_other_dictionary_2', '...', 'some_other_dictionary_n' ): some_module2.some_function( { each_one_of_my_dictionaries_names : eval(each_one_of_my_dictionaries_names) } ) # some_module2.py def some_function(a_dictionary_name_object_container): for _dictionary_name, _dictionary_object in a_dictionary_name_object_container.items(): for _key, _value in _dictionary_object.items(): print( str(_dictionary_name) + " " + str(_key) + " = " + str(_value) ) ######
Abschließend:
eval()
Funktion nur dann auf den tatsächlichen Bezeichner zurückgeführt werden , wenn der Namensbezeichner im aktuellen Namespace verfügbar ist.eval()
Funktion wäre in Fällen nicht sinnvoll, in denen der Bezeichnername vom aufrufenden Code nicht direkt "gesehen" wird. ZB innerhalb einer aufgerufenen Funktion.Dies kann erreicht werden, indem sowohl die
'string'
alseval('string')
auch die aufgerufene Funktion gleichzeitig übergeben werden. Ich denke, dies ist die allgemeinste Methode, um dieses Ei-Huhn-Problem über beliebige Funktionen, Module und Namespaces hinweg zu lösen, ohne Eckfalllösungen zu verwenden. Der einzige Nachteil ist die Verwendung dereval()
Funktion, die leicht zu ungesichertem Code führen kann. Es muss darauf geachtet werden, dieeval()
Funktion nicht mit so gut wie allem zu versorgen, insbesondere nicht ungefilterten externen Eingabedaten.quelle
Ich habe nach dieser Frage gesucht, weil ich wollte, dass ein Python-Programm Zuweisungsanweisungen für einige der Variablen im Programm druckt. Beispielsweise könnte "foo = 3, bar = 21, baz = 432" gedruckt werden. Die Druckfunktion würde die Variablennamen in Zeichenfolgenform benötigen. Ich hätte meinen Code mit den Zeichenfolgen "foo", "bar" und "baz" versehen können, aber das fühlte sich an, als würde ich mich wiederholen. Nachdem ich die vorherigen Antworten gelesen hatte, entwickelte ich die folgende Lösung.
Die Funktion globals () verhält sich wie ein Diktat mit Variablennamen (in Form von Zeichenfolgen) als Schlüssel. Ich wollte von globals () den Schlüssel abrufen, der dem Wert jeder Variablen entspricht. Die Methode globals (). Items () gibt eine Liste von Tupeln zurück. In jedem Tupel ist das erste Element der Variablenname (als Zeichenfolge) und das zweite der Variablenwert. Meine Funktion variablename () durchsucht diese Liste nach den Variablennamen, die dem Wert der Variablen entsprechen, deren Namen ich in Zeichenfolgenform benötige.
Die Funktion itertools.ifilter () führt die Suche durch, indem sie jedes Tupel in der Liste globals (). Items () mit der Funktion testet
lambda x: var is globals()[x[0]]
. In dieser Funktion ist x das zu testende Tupel; x [0] ist der Variablenname (als Zeichenfolge) und x [1] ist der Wert. Die Lambda-Funktion prüft, ob der Wert der getesteten Variablen mit dem Wert der an Variablenname () übergebenen Variablen übereinstimmt. Tatsächlichis
testet die Lambda-Funktion mithilfe des Operators, ob der Name der getesteten Variablen an genau dasselbe Objekt gebunden ist wie die an variablename () übergebene Variable. In diesem Fall besteht das Tupel den Test und wird von ifilter () zurückgegeben.Die Funktion itertools.ifilter () gibt tatsächlich einen Iterator zurück, der keine Ergebnisse zurückgibt, bis er ordnungsgemäß aufgerufen wird. Um es richtig aufzurufen, habe ich es in ein Listenverständnis eingefügt
[tpl[0] for tpl ... globals().items())]
. Das Listenverständnis speichert nur den Variablennamentpl[0]
und ignoriert den Variablenwert. Die erstellte Liste enthält einen oder mehrere Namen (als Zeichenfolgen), die an den Wert der an variablename () übergebenen Variablen gebunden sind.Bei den unten gezeigten Verwendungen von Variablenname () wird die gewünschte Zeichenfolge als Element in einer Liste zurückgegeben. In vielen Fällen ist dies das einzige Element in der Liste. Wenn jedoch einem anderen Variablennamen der gleiche Wert zugewiesen wird, ist die Liste länger.
>>> def variablename(var): ... import itertools ... return [tpl[0] for tpl in ... itertools.ifilter(lambda x: var is x[1], globals().items())] ... >>> var = {} >>> variablename(var) ['var'] >>> something_else = 3 >>> variablename(something_else) ['something_else'] >>> yet_another = 3 >>> variablename(something_else) ['yet_another', 'something_else']
quelle
Solange es eine Variable und keine zweite Klasse ist, funktioniert dies hier für mich:
def print_var_name(variable): for name in globals(): if eval(name) == variable: print name foo = 123 print_var_name(foo) >>>foo
Dies geschieht für Klassenmitglieder:
class xyz: def __init__(self): pass member = xyz() print_var_name(member) >>>member
ans dies für Klassen (als Beispiel):
Für Klassen gibt es also den Namen UND die Eigenschaften
quelle
Technisch gesehen stehen Ihnen die Informationen zur Verfügung, aber wie andere gefragt haben, wie würden Sie sie sinnvoll nutzen?
>>> x = 52 >>> globals() {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 'x': 52, '__doc__': None, '__package__': None}
Dies zeigt, dass der Variablenname im globals () -Wörterbuch als Zeichenfolge vorhanden ist.
>>> globals().keys()[2] 'x'
In diesem Fall ist es der dritte Schlüssel, aber es gibt keine zuverlässige Möglichkeit zu wissen, wo ein bestimmter Variablenname landen wird
>>> for k in globals().keys(): ... if not k.startswith("_"): ... print k ... x >>>
Sie könnten Systemvariablen wie diese herausfiltern, aber Sie werden trotzdem alle Ihre eigenen Elemente erhalten. Durch einfaches Ausführen des obigen Codes wurde eine weitere Variable "k" erstellt, die die Position von "x" im Diktat geändert hat.
Aber vielleicht ist dies ein nützlicher Anfang für Sie. Wenn Sie uns mitteilen, wofür Sie diese Funktion wünschen, können möglicherweise hilfreichere Informationen bereitgestellt werden.
quelle
Das ist nicht möglich.
In Python gibt es wirklich keine "Variable". Was Python wirklich hat, sind "Namen", an die Objekte gebunden sein können. Für das Objekt spielt es keine Rolle, an welche Namen es gegebenenfalls gebunden sein könnte. Es könnte an Dutzende verschiedener Namen gebunden sein oder an keinen.
Betrachten Sie dieses Beispiel:
foo = 1 bar = 1 baz = 1
Angenommen, Sie haben das Integer-Objekt mit dem Wert 1 und möchten rückwärts arbeiten und seinen Namen finden. Was würden Sie drucken? An drei verschiedene Namen ist dieses Objekt gebunden, und alle sind gleichermaßen gültig.
In Python ist ein Name eine Möglichkeit, auf ein Objekt zuzugreifen. Es gibt also keine Möglichkeit, direkt mit Namen zu arbeiten. Es gibt vielleicht eine clevere Möglichkeit, die Python-Bytecodes zu hacken oder etwas, um den Wert des Namens zu ermitteln, aber das ist bestenfalls ein Salon-Trick.
Wenn Sie wissen, dass Sie
print foo
drucken möchten"foo"
, können Sie dies auch gleich ausführenprint "foo"
.EDIT: Ich habe den Wortlaut leicht geändert, um dies klarer zu machen. Auch hier ist ein noch besseres Beispiel:
foo = 1 bar = foo baz = foo
In der Praxis verwendet Python dasselbe Objekt für Ganzzahlen mit gemeinsamen Werten wie 0 oder 1, sodass das erste Beispiel dasselbe Objekt an alle drei Namen binden sollte. Dieses Beispiel ist jedoch glasklar: Das gleiche Objekt ist an foo, bar und baz gebunden.
quelle
foo
bar
undbaz
alles zu1
. Wie heißt dann "1
?" Wenn Sie alle Globals durchsehen, können Sie eine Liste mit Variablennamen zurückgeben:['foo', 'bar', 'baz']
(in zufälliger Reihenfolge). Okay. Was ist die Verwendung dieser Liste? Ist einer der Namen der "wahre" Name von1
? (Nein.) Diejenigen von uns, die "es" sagen, sind sich nicht alle einig, dass Sie durch Globale schauen und alle Namen finden könnten; Wir glauben einfach nicht, dass dies eine nützliche Sache ist. Wie gesagt: Ein Objekt "könnte an Dutzende verschiedener Namen gebunden sein oder an keinen."Hier ist eine kurze Variante, mit der Sie ein beliebiges Verzeichnis angeben können. Das Problem bei der Verwendung von Verzeichnissen zum Auffinden von Daten besteht darin, dass mehrere Variablen denselben Wert haben können. Dieser Code gibt also eine Liste möglicher Variablen zurück.
def varname( var, dir=locals()): return [ key for key, val in dir.items() if id( val) == id( var)]
quelle
Sie müssen sich irgendwie auf die Variable beziehen, deren Namen Sie drucken möchten. So würde es aussehen:
print varname(something_else)
Es gibt keine solche Funktion, aber wenn es sie gäbe, wäre sie irgendwie sinnlos. Sie müssen eingeben
something_else
, also können Sie auch links und rechts davon Anführungszeichen eingeben, um den Namen als Zeichenfolge zu drucken:print "something_else"
quelle
Was versuchst du zu erreichen? Es gibt absolut keinen Grund, jemals das zu tun, was Sie beschreiben, und es gibt wahrscheinlich eine viel bessere Lösung für das Problem, das Sie lösen möchten.
Die naheliegendste Alternative zu Ihrer Anfrage ist ein Wörterbuch. Zum Beispiel:
>>> my_data = {'var': 'something'} >>> my_data['something_else'] = 'something' >>> print my_data.keys() ['var', 'something_else'] >>> print my_data['var'] something
Meistens als .. Herausforderung habe ich Ihre gewünschte Ausgabe implementiert. Verwenden Sie diesen Code bitte nicht!
#!/usr/bin/env python2.6 class NewLocals: """Please don't ever use this code..""" def __init__(self, initial_locals): self.prev_locals = list(initial_locals.keys()) def show_new(self, new_locals): output = ", ".join(list(set(new_locals) - set(self.prev_locals))) self.prev_locals = list(new_locals.keys()) return output # Set up eww = None eww = NewLocals(locals()) # "Working" requested code var = {} print eww.show_new(locals()) # Outputs: var something_else = 3 print eww.show_new(locals()) # Outputs: something_else # Further testing another_variable = 4 and_a_final_one = 5 print eww.show_new(locals()) # Outputs: another_variable, and_a_final_one
quelle
Tut Django dies nicht beim Generieren von Feldnamen?
http://docs.djangoproject.com/de/dev//topics/db/models/#verbose-field-names
Scheint mir vernünftig.
quelle
Ich denke, das ist eine coole Lösung und ich nehme an, das Beste, was Sie bekommen können. Aber sehen Sie eine Möglichkeit, mit den mehrdeutigen Ergebnissen umzugehen, und Ihre Funktion kann zurückkehren? Da sich der Operator "is" bei Ganzzahl- Shows unerwartet verhält , werden niedrige Ganzzahlen und Zeichenfolgen mit demselben Wert von Python zwischengespeichert, sodass Ihre Variablennamenfunktion mit hoher Wahrscheinlichkeit mehrdeutige Ergebnisse liefern kann. In meinem Fall möchte ich einen Dekorateur erstellen, der einer Klasse eine neue Variable mit dem Varialbenamen hinzufügt, den ich übergebe:
def inject(klass, dependency): klass.__dict__["__"+variablename(dependency)]=dependency
Aber wenn Ihre Methode mehrdeutige Ergebnisse zurückgibt, wie kann ich den Namen der Variablen kennen, die ich hinzugefügt habe?
var any_var="myvarcontent" var myvar="myvarcontent" @inject(myvar) class myclasss(): def myclass_method(self): print self.__myvar #I can not be sure, that this variable will be set...
Wenn ich auch die lokale Liste überprüfen würde, könnte ich vielleicht zumindest die "Abhängigkeit" -Variable aus der Liste entfernen, aber dies ist kein verlässliches Ergebnis.
quelle
Dies funktioniert für einfache Datentypen (str, int, float, list usw.).
quelle
Es ist nicht sehr pythonesk, aber ich war neugierig und habe diese Lösung gefunden. Sie müssen das globale Wörterbuch duplizieren, da sich seine Größe ändert, sobald Sie eine neue Variable definieren.
def var_to_name(var): # noinspection PyTypeChecker dict_vars = dict(globals().items()) var_string = None for name in dict_vars.keys(): if dict_vars[name] is var: var_string = name break return var_string if __name__ == "__main__": test = 3 print(f"test = {test}") print(f"variable name: {var_to_name(test)}")
was zurückgibt:
test = 3 variable name: test
quelle
globals
Diktat. Genau das wurde in einer früheren Antwort getan, ohne zusätzliche Variablen zu erstellen und zu verwendenitertools
. Obwohl die Antwort gut ist, denke ich, da eine ähnliche Lösung bereitgestellt wurde, sollten Sie dies unterstützen und Wiederholungen vermeiden.Mit dem Auspack-Operator :
>>> def tostr(**kwargs): return kwargs >>> var = {} >>> something_else = 3 >>> tostr(var = var,something_else=something_else) {'var' = {},'something_else'=3}
quelle
Ich weiß nicht, ob es richtig ist oder nicht, aber es hat bei mir funktioniert
def varname(variable): names = [] for name in list(globals().keys()): string = f'id({name})' if id(variable) == eval(string): names.append(name) return names[0]
quelle
So erhalten Sie den Variablennamen
var
als Zeichenfolge:var = 1000 var_name = [k for k,v in locals().items() if v == var][0] print(var_name) # ---> outputs 'var'
quelle
print "var" print "something_else"
Oder meintest du etwas anderes?
quelle