Подтвердить что ты не робот

Преобразование имени переменной в строку?

Я хотел бы преобразовать имя переменной python в эквивалент строки, как показано. Любые идеи как?

var = {}
print ???  # Would like to see 'var'
something_else = 3
print ???  # Would print 'something_else'
4b9b3361

Ответ 1

Существует сценарий использования, где это может понадобиться. Я не подразумеваю, что нет лучших способов или достижения той же функциональности.

Это было бы полезно для того, чтобы "сбрасывать" произвольный список словарей в случае ошибки, в режимах отладки и в других подобных ситуациях.

Что потребуется, это обратная сторона функции 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' для:

  • служит как "имя идентификатора" (для отображения, записи, разделения строк /concat, независимо)
  • передайте функцию 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) )
    ######

В заключение:

  • Python передает только адреса памяти в качестве аргументов функций.
  • Строки, представляющие имя идентификатора, могут быть возвращены только к фактическому идентификатору с помощью функции eval(), если идентификатор имени доступен в текущем пространстве имен.
  • Гипотетический реверс функции eval() не будет полезен в тех случаях, когда имя идентификатора не "видно" непосредственно вызывающим кодом. Например. внутри любой вызываемой функции.
  • В настоящее время нужно перейти к функции:
    • строка, представляющая имя идентификатора
    • фактический идентификатор (адрес памяти)

Это может быть достигнуто путем одновременного передачи как 'string', так и eval('string') вызываемой функции. Я думаю, что это самый "общий" способ решения этой проблемы с куриными яйцами в произвольных функциях, модулях, пространствах имен, без использования решений с угловым корпусом. Единственным недостатком является использование функции eval(), которая может легко привести к незащищенному коду. Необходимо следить за тем, чтобы функция eval() не загружала ничего, особенно нефильтрованные внешние входные данные.

Ответ 2

Это невозможно.

В 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.

Ответ 3

Технически информация доступна вам, но, как спросили другие, как бы вы ее использовали разумным способом?

>>> 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.

Но, может быть, это для вас полезное начало. Если вы сообщите нам, что вы хотите использовать эту возможность, более полезная информация может быть предоставлена.

Ответ 4

Я искал этот вопрос, потому что хотел, чтобы программа 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']

Ответ 5

пока это переменная, а не второй класс, это работает для меня:

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

Итак, для классов это дает вам имя И свойства

Ответ 6

Вам как-то придется ссылаться на переменную, которую вы хотите напечатать. Таким образом, это будет выглядеть так:

print varname(something_else)

Нет такой функции, но если бы это было, то было бы бессмысленно. Вы должны ввести something_else, чтобы вы могли просто напечатать кавычки слева и справа от него, чтобы напечатать имя в виде строки:

print "something_else"

Ответ 7

Чего вы пытаетесь достичь? Нет абсолютно никаких оснований когда-либо делать то, что вы описываете, и, вероятно, гораздо лучшее решение проблемы, которую вы пытаетесь решить.

Наиболее очевидной альтернативой тому, что вы запрашиваете, является словарь. Например:

>>> 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

Ответ 9

Я думаю, что это крутое решение, и я полагаю, что все, что вы можете получить. Но видите ли вы какой-либо способ справиться с неоднозначными результатами, ваша функция может вернуться? Поскольку "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, но это не будет надежным результатом.

Ответ 10

Вот краткий вариант, который позволяет указать любую директорию. Проблема с использованием каталогов для поиска чего-либо состоит в том, что несколько переменных могут иметь одинаковое значение. Таким образом, этот код возвращает список возможных переменных.

def varname( var, dir=locals()):
  return [ key for key, val in dir.items() if id( val) == id( var)]

Ответ 11

print "var"
print "something_else"

Или вы имели в виду something_else?

Ответ 12

Это будет работать для простых типов данных (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!']