Я хотел бы преобразовать имя переменной python в строковый эквивалент, как показано. Есть идеи как?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
Я хотел бы преобразовать имя переменной python в строковый эквивалент, как показано. Есть идеи как?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
Существует сценарий использования, в котором вам это может понадобиться. Я не имею в виду, что нет лучших способов или достижения той же функциональности.
Это было бы полезно для того, чтобы "сбрасывать" произвольный список словарей в случае ошибки, в режимах отладки и других подобных ситуациях.
Что было бы необходимо, так это обратная функция eval()
:
get_indentifier_name_missing_function()
который принимает имя идентификатора («переменная», «словарь» и т. д.) в качестве аргумента и возвращает строку, содержащую имя идентификатора.
Рассмотрим следующее текущее положение дел:
random_function(argument_data)
Если кто-то передает имя идентификатора («функция», «переменная», «словарь» и т. д.) argument_data
в random_function()
(другое имя идентификатора), он фактически передает идентификатор (например: <argument_data object at 0xb1ce10>
) другому идентификатору (например: <function random_function at 0xafff78>
) :
<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)
Насколько я понимаю, в функцию передается только адрес памяти:
<function at 0xafff78>(<object at 0xb1ce10>)
Следовательно, нужно было бы передать строку в качестве аргумента random_function()
, чтобы эта функция имела имя идентификатора аргумента:
random_function('argument_data')
Внутри random_function()
def random_function(first_argument):
, можно было бы использовать уже предоставленную строку 'argument_data'
для:
служить «имя идентификатора» (для отображения, регистрации, разделения/объединения строк и т. д.)
передать функцию eval()
, чтобы получить ссылку на фактический идентификатор и, следовательно, ссылку на реальные данные:
print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))
К сожалению, это работает не во всех случаях. Это работает только в том случае, если random_function()
может преобразовать строку 'argument_data'
в фактический идентификатор. т.е. Если имя идентификатора argument_data
доступно в пространстве имен random_function()
.
Это не всегда так:
# 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))
######
Ожидаемые результаты:
Currently working on: argument_data
here comes the data: my data
Поскольку имя идентификатора argument_data
недоступно в пространстве имен random_function()
, вместо этого будет получено:
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
Теперь рассмотрим гипотетическое использование get_indentifier_name_missing_function()
, которое будет вести себя, как описано выше.
Вот фиктивный код Python 3.0: .
# 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) )
######
Ожидаемые результаты:
some_dictionary_1 definition_1 = text_1
some_dictionary_1 definition_2 = text_2
some_dictionary_1 etc = etc.
some_other_dictionary_2 key_3 = value_3
some_other_dictionary_2 key_4 = value_4
some_other_dictionary_2 etc = etc.
......
......
......
some_other_dictionary_n random_n = random_n
some_other_dictionary_n etc = etc.
К сожалению, get_indentifier_name_missing_function()
не увидит "исходные" имена идентификаторов (some_dictionary_
,some_other_dictionary_2
,some_other_dictionary_n
). Он увидит только имя идентификатора a_dictionary_object
.
Поэтому реальный результат скорее будет таким:
a_dictionary_object definition_1 = text_1
a_dictionary_object definition_2 = text_2
a_dictionary_object etc = etc.
a_dictionary_object key_3 = value_3
a_dictionary_object key_4 = value_4
a_dictionary_object etc = etc.
......
......
......
a_dictionary_object random_n = random_n
a_dictionary_object etc = etc.
Таким образом, обратная функция eval()
в этом случае не будет так полезна.
В настоящее время нужно было бы сделать это:
# 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) )
######
eval()
только в том случае, если идентификатор имени доступен в текущем пространстве имен.eval()
не будет полезна в случаях, когда имя идентификатора не "видится" непосредственно вызывающим кодом. Например. внутри любой вызываемой функции.Этого можно добиться путем одновременной передачи 'string'
и eval('string')
в вызываемую функцию. Я думаю, что это самый «общий» способ решения этой проблемы с яйцом и курицей для произвольных функций, модулей, пространств имен, без использования краеугольных решений. Единственным недостатком является использование функции eval()
, которая может легко привести к незащищенному коду. Необходимо соблюдать осторожность, чтобы не передавать в функцию eval()
что угодно, особенно нефильтрованные внешние входные данные.
varname
ниже, которая фактически отвечает на вопрос. imo: это недостающая функция в python. я объяснил почему. этот принятый ответ вводит в заблуждение.
- person Erik Aronesty; 14.01.2021
Я искал этот вопрос, потому что хотел, чтобы программа Python печатала операторы присваивания для некоторых переменных в программе. Например, он может напечатать «foo = 3, bar = 21, baz = 432». Функции печати потребуются имена переменных в строковой форме. Я мог бы снабдить свой код строками "foo", "bar" и "baz", но это было похоже на повторение самого себя. Прочитав предыдущие ответы, я разработал решение ниже.
Функция globals() ведет себя как словарь с именами переменных (в виде строк) в качестве ключей. Я хотел получить из globals() ключ, соответствующий значению каждой переменной. Метод globals().items() возвращает список кортежей; в каждом кортеже первый элемент — это имя переменной (в виде строки), а второй — значение переменной. Моя функция variablename() просматривает этот список, чтобы найти имена переменных, которые соответствуют значению переменной, имя которой мне нужно в строковой форме.
Функция itertools.ifilter() выполняет поиск, проверяя каждый кортеж в списке globals().items() с помощью функции lambda x: var is globals()[x[0]]
. В этой функции x — проверяемый кортеж; x[0] — это имя переменной (в виде строки), а x[1] — это значение. Лямбда-функция проверяет, совпадает ли значение проверяемой переменной со значением переменной, переданной в variablename(). Фактически, используя оператор is
, лямбда-функция проверяет, связано ли имя тестируемой переменной с тем же самым объектом, что и переменная, переданная в variablename(). Если это так, кортеж проходит проверку и возвращается функцией ifilter().
Функция itertools.ifilter() фактически возвращает итератор, который не возвращает никаких результатов до тех пор, пока не будет вызван должным образом. Чтобы вызвать его правильно, я поместил его в понимание списка [tpl[0] for tpl ... globals().items())]
. Понимание списка сохраняет только имя переменной tpl[0]
, игнорируя значение переменной. Создаваемый список содержит одно или несколько имен (в виде строк), связанных со значением переменной, переданной в функцию variablename().
В показанных ниже примерах использования variablename() требуемая строка возвращается как элемент списка. Во многих случаях это будет единственный элемент в списке. Однако, если другому имени переменной будет присвоено такое же значение, список будет длиннее.
>>> 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']
пока это переменная, а не второй класс, у меня это работает:
def print_var_name(variable):
for name in globals():
if eval(name) == variable:
print name
foo = 123
print_var_name(foo)
>>>foo
это происходит для членов класса:
class xyz:
def __init__(self):
pass
member = xyz()
print_var_name(member)
>>>member
и это для классов (например):
abc = xyz
print_var_name(abc)
>>>abc
>>>xyz
Итак, для классов он дает вам имя И свойства
is variable
, а не == variable
... безопаснее
- person Erik Aronesty; 14.01.2021
print name
на print(name)
вполне очевидна, но все равно выдает ошибку. Исправление @Erik Aronesty заставляет его работать, но проблема, на которую указывает @steveha, все еще остается.
- person JC_CL; 20.05.2021
Технически информация доступна для вас, но, как спрашивали другие, как бы вы использовали ее разумным образом?
>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__',
'x': 52, '__doc__': None, '__package__': None}
Это показывает, что имя переменной представлено в виде строки в словаре globals().
>>> globals().keys()[2]
'x'
В данном случае это третий ключ, но нет надежного способа узнать, где окажется заданное имя переменной.
>>> for k in globals().keys():
... if not k.startswith("_"):
... print k
...
x
>>>
Вы можете отфильтровать системные переменные таким образом, но вы все равно получите все свои собственные элементы. Просто запустив этот код выше, вы создали еще одну переменную «k», которая изменила положение «x» в словаре.
Но, возможно, это полезное начало для вас. Если вы сообщите нам, для чего вам нужна эта возможность, возможно, будет предоставлена более полезная информация.
Это невозможно.
В Python действительно нет такой вещи, как «переменная». На самом деле у Python есть «имена», к которым могут быть привязаны объекты. Для объекта не имеет значения, с какими именами он может быть связан. Он может быть связан с десятками разных имен или ни с одним.
Рассмотрим этот пример:
foo = 1
bar = 1
baz = 1
Теперь предположим, что у вас есть целочисленный объект со значением 1, и вы хотите работать в обратном направлении и найти его имя. Что бы вы напечатали? Этот объект связан с тремя разными именами, и все они одинаково допустимы.
В Python имя — это способ доступа к объекту, поэтому напрямую работать с именами невозможно. Может быть какой-то умный способ взломать байт-коды Python или что-то еще, чтобы получить значение имени, но это в лучшем случае салонный трюк.
Если вы знаете, что хотите, чтобы print foo
напечатало "foo"
, вы могли бы просто выполнить print "foo"
в первую очередь.
РЕДАКТИРОВАТЬ: я немного изменил формулировку, чтобы сделать ее более понятной. Кроме того, вот еще лучший пример:
foo = 1
bar = foo
baz = foo
На практике Python повторно использует один и тот же объект для целых чисел с общими значениями, такими как 0 или 1, поэтому первый пример должен привязать один и тот же объект ко всем трем именам. Но этот пример кристально ясен: один и тот же объект привязан к foo, bar и baz.
foo
bar
и baz
к 1
. Тогда как зовут 1
? Если вы просмотрите все глобальные переменные, вы можете вернуть список имен переменных: ['foo', 'bar', 'baz']
(в произвольном порядке). Хорошо. Какая польза от этого списка? Является ли одно из имен настоящим именем 1
? (Нет.) Те из нас, кто говорит, что это невозможно, все согласны с тем, что вы можете просмотреть глобальные переменные и найти все имена; мы просто не думаем, что это полезно. Как я уже сказал, объект может быть связан с десятками разных имен или ни с одним.
- person steveha; 11.11.2020
var1=10 ==> result1 = some_processing(var1) ==> out_file_1 = 'some_result_using_var1.png'
. Конечно, вы можете сделать это со словарем, например: var1 = {"var1" : 10}
и, возможно, это более питонический способ сделать это.
- person Robyc; 11.11.2020
Вот краткий вариант, который позволяет указать любой каталог. Проблема с использованием каталогов для поиска чего-либо заключается в том, что несколько переменных могут иметь одно и то же значение. Итак, этот код возвращает список возможных переменных.
def varname( var, dir=locals()):
return [ key for key, val in dir.items() if id( val) == id( var)]
Вы каким-то образом должны ссылаться на переменную, имя которой хотите напечатать. Так это будет выглядеть так:
print varname(something_else)
Такой функции нет, а если бы и была, то было бы как-то бессмысленно. Вы должны ввести something_else
, поэтому вы можете просто ввести кавычки слева и справа от него, чтобы напечатать имя в виде строки:
print "something_else"
varname
ниже. работает и для методов.
- person Erik Aronesty; 14.01.2021
Чего вы пытаетесь достичь? Нет абсолютно никаких причин делать то, что вы описываете, и, вероятно, есть гораздо лучшее решение проблемы, которую вы пытаетесь решить.
Наиболее очевидная альтернатива тому, что вы запрашиваете, — это словарь. Например:
>>> my_data = {'var': 'something'}
>>> my_data['something_else'] = 'something'
>>> print my_data.keys()
['var', 'something_else']
>>> print my_data['var']
something
В основном как ... вызов, я реализовал желаемый результат. Не используйте этот код, пожалуйста!
#!/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
Разве Django не делает этого при создании имен полей?
http://docs.djangoproject.com/en/dev//topics/db/models/#verbose-field-names
Мне кажется разумным.
Я думаю, что это классное решение, и я полагаю, лучшее, что вы можете получить. Но видите ли вы какой-либо способ справиться с неоднозначными результатами, которые может вернуть ваша функция? Как показывает оператор is ведет себя неожиданно с целыми числами, низкие целые числа и строки одно и то же значение кэшируется python, так что ваша функция имени переменной может с высокой вероятностью получить неоднозначные результаты. В моем случае я хотел бы создать декоратор, который добавляет новую переменную в класс по имени переменной, которое я передаю:
def inject(klass, dependency):
klass.__dict__["__"+variablename(dependency)]=dependency
Но если ваш метод возвращает неоднозначные результаты, как я могу узнать имя добавленной переменной?
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...
Возможно, если я также проверю локальный список, я мог бы, по крайней мере, удалить переменную «зависимость» из списка, но это не будет надежным результатом.
Используя оператор распаковки:
>>> def tostr(**kwargs):
return kwargs
>>> var = {}
>>> something_else = 3
>>> tostr(var = var,something_else=something_else)
{'var' = {},'something_else'=3}
Вполне возможно с пакетом python-varname (python3):
from varname import nameof
s = 'Hey!'
print (nameof(s))
Вывод:
s
Получить пакет здесь:
https://github.com/pwwang/python-varname
Это будет работать для простых типов данных (str, int, float, list и т. д.).
>>> def my_print(var_str) : print var_str+':', globals()[var_str] >>> a = 5 >>> b = ['hello', ',world!'] >>> my_print('a') a: 5 >>> my_print('b') b: ['hello', ',world!']
Это не очень Pythonesque, но мне было любопытно, и я нашел это решение. Вам нужно продублировать словарь globals, так как его размер изменится, как только вы определите новую переменную.
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)}")
который возвращает:
test = 3
variable name: test
globals
. Именно это было сделано в предыдущем ответе без создания дополнительных переменных и использования itertools
. Хотя ответ хороший, я думаю, что, поскольку было предоставлено аналогичное решение, вы должны проголосовать за него и избежать повторения.
- person razdi; 12.09.2019
Не знаю правильно это или нет, но мне помогло
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]
Чтобы получить имя переменной var
в виде строки:
var = 1000
var_name = [k for k,v in locals().items() if v == var][0]
print(var_name) # ---> outputs 'var'
Я хотел бы указать на вариант использования для этого, который не является анти-шаблоном, и нет лучшего способа сделать это.
Кажется, это отсутствующая функция в python.
Существует ряд функций, таких как patch.object
, которые принимают имя метода или свойства для исправления или доступа.
Учти это:
patch.object(obj, "method_name", new_reg)
Это потенциально может привести к ложному успеху при изменении имени метода. IE: вы можете отправить ошибку, вы думали, что тестируете.... просто из-за плохого рефакторинга имени метода.
Теперь рассмотрим: varname
. Это может быть эффективная встроенная функция. Но пока он может работать, итерируя объект или фрейм вызывающего объекта:
Теперь ваш звонок может быть:
patch.member(obj, obj.method_name, new_reg)
И функция исправления может вызвать:
varname(var, obj=obj)
Это будет: утверждать, что переменная связана с объектом, и возвращать имя члена. Или, если объект не указан, используйте кадр стека вызывающих абонентов для его получения и т. д.
В какой-то момент его можно было бы сделать эффективным встроенным, но вот определение, которое работает. Я намеренно не поддерживал встроенные, которые легко добавить:
Не стесняйтесь вставлять это в пакет с именем varname.py
и использовать его в ваших вызовах patch.object:
patch.object(obj, varname(obj, obj.method_name), new_reg)
Примечание: это было написано для Python 3.
import inspect
def _varname_dict(var, dct):
key_name = None
for key, val in dct.items():
if val is var:
if key_name is not None:
raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
key_name = key
return key_name
def _varname_obj(var, obj):
key_name = None
for key in dir(obj):
val = getattr(obj, key)
equal = val is var
if equal:
if key_name is not None:
raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
key_name = key
return key_name
def varname(var, obj=None):
if obj is None:
if hasattr(var, "__self__"):
return var.__name__
caller_frame = inspect.currentframe().f_back
try:
ret = _varname_dict(var, caller_frame.f_locals)
except NameError:
ret = _varname_dict(var, caller_frame.f_globals)
else:
ret = _varname_obj(var, obj)
if ret is None:
raise NameError("Name not found. (Note: builtins not supported)")
return ret
Этот модуль работает для преобразования имен переменных в строку: https://pypi.org/project/varname/ а>
Используйте это так:
из varname импортировать nameof
переменная=0
имя = имя (переменная)
печать (имя)
// вывод: переменная
Установите его:
pip установить имя_переменной
print "var"
print "something_else"
Или вы имели в виду что-то_еще?
def to_R( py_var ): r.assign( 'py_var', py_var )
чтобы присвоить данные в (Py) py_var среде R и иметь то же имя. Вместо этого мне было бы полезно сделатьr.assign( py_var.stringof, py_var )
а-ля D, так как имя переменной передается моему fnto_r
не обязательноpy_var
. - person Matthew Turner   schedule 26.01.2013