Я хотел бы преобразовать имя переменной 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)
Если передать имя идентификатора ('function', 'variable', 'dictionary' и т.д.) 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'
фактическому идентификатору. То есть Если в пространстве имен random_function()
доступно имя идентификатора argument_data
.
Это не всегда так:
# 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
Теперь рассмотрим гипототическое использование a 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()
не загружала ничего, особенно нефильтрованные внешние входные данные.
Это невозможно.
В Python действительно нет такой вещи, как "переменная". У Python действительно есть "имена", которые могут иметь связанные с ними объекты. Для объекта не имеет значения, какие имена, если таковые имеются, могут быть связаны. Это может быть связано с десятками разных имен или нет.
Рассмотрим следующий пример:
foo = 1
bar = 1
baz = 1
Теперь предположим, что у вас есть целочисленный объект со значением 1, и вы хотите работать назад и найти его имя. Что бы вы напечатали? Три разных имени имеют связанный с ними объект, и все они одинаково действительны.
В Python имя - это способ доступа к объекту, поэтому нет возможности напрямую работать с именами. Может быть какой-то умный способ взломать байт-коды Python или что-то, чтобы получить значение имени, но это в лучшем случае трюк в гостиной.
Если вы знаете, что хотите print foo
распечатать "foo"
, вы можете просто выполнить print "foo"
в первую очередь.
EDIT: Я немного изменил формулировку, чтобы сделать это более понятным. Кроме того, вот еще лучший пример:
foo = 1
bar = foo
baz = foo
На практике Python повторно использует один и тот же объект для целых чисел с общими значениями, такими как 0 или 1, поэтому первый пример должен связывать один и тот же объект со всеми тремя именами. Но этот пример кристально чист: тот же объект связан с foo, bar и baz.
Технически информация доступна вам, но, как спросили другие, как бы вы ее использовали разумным способом?
>>> 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" в dict.
Но, может быть, это для вас полезное начало. Если вы сообщите нам, что вы хотите использовать эту возможность, более полезная информация может быть предоставлена.
Я искал этот вопрос, потому что хотел, чтобы программа Python печатала инструкции присваивания для некоторых переменных в программе. Например, он может печатать "foo = 3, bar = 21, baz = 432". Для функции печати нужны имена переменных в строковой форме. Я мог бы снабдить свой код строками "foo", "bar" и "baz", но мне хотелось повториться. Прочитав предыдущие ответы, я разработал решение ниже.
Функция globals() ведет себя как dict с именами переменных (в виде строк) в качестве ключей. Я хотел получить из 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
ans this для классов (в качестве примера):
abc = xyz
print_var_name(abc)
>>>abc
>>>xyz
Итак, для классов это дает вам имя И свойства
Вам как-то придется ссылаться на переменную, которую вы хотите напечатать. Таким образом, это будет выглядеть так:
print varname(something_else)
Нет такой функции, но если бы это было, то было бы бессмысленно. Вы должны ввести something_else
, чтобы вы могли просто напечатать кавычки слева и справа от него, чтобы напечатать имя в виде строки:
print "something_else"
Чего вы пытаетесь достичь? Нет абсолютно никаких оснований когда-либо делать то, что вы описываете, и, вероятно, гораздо лучшее решение проблемы, которую вы пытаетесь решить.
Наиболее очевидной альтернативой тому, что вы запрашиваете, является словарь. Например:
>>> 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, так что ваша функция variablename может с высокой вероятностью получить однозначные результаты. В моем случае я хотел бы создать декоратор, который добавляет новую переменную в класс через varialbename, которую я передаю:
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...
Возможно, если я также проверю локальный список, я мог бы хотя бы удалить из списка "зависимость" -Variable, но это не будет надежным результатом.
Вот краткий вариант, который позволяет указать любую директорию. Проблема с использованием каталогов для поиска чего-либо состоит в том, что несколько переменных могут иметь одинаковое значение. Таким образом, этот код возвращает список возможных переменных.
def varname( var, dir=locals()):
return [ key for key, val in dir.items() if id( val) == id( var)]
print "var"
print "something_else"
Или вы имели в виду something_else?
Это будет работать для простых типов данных (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!']