Как я могу получить имя объекта в Python? - PullRequest
26 голосов
/ 08 октября 2009

Есть ли способ получить имя объекта в Python? Например:

my_list = [x, y, z] # x, y, z have been previously defined

for bla in my_list:
    print "handling object ", name(bla) # <--- what would go instead of `name`?
    # do something to bla

Редактировать: Некоторый контекст:

На самом деле я создаю список функций, которые я могу указать в командной строке.

У меня есть:

def fun1:
    pass
def fun2
    pass
def fun3:
    pass

fun_dict = {'fun1': fun1,
            'fun2': fun2,
            'fun3': fun3}

Я получаю имя функции из командной строки и хочу вызвать соответствующую функцию:

func_name = parse_commandline()

fun_dict[func_name]()

И причина, по которой я хочу иметь имя функции, заключается в том, что я хочу создать fun_dict без записи имен функций дважды, поскольку это кажется хорошим способом создания ошибок. Что я хочу сделать, это:

fun_list = [fun1, fun2, fun3] # and I'll add more as the need arises

fun_dict = {}
[fun_dict[name(t) = t for t in fun_list] # <-- this is where I need the name function

Таким образом, мне нужно написать имена функций только один раз.

Ответы [ 15 ]

28 голосов
/ 08 октября 2009

Объекты не обязательно имеют имена в python, поэтому вы не можете получить имя. Для объектов весьма обычно иметь атрибут __name__ в тех случаях, когда у них есть имя, но это не является частью стандартного python, и большинство встроенных типов не имеют его.

Когда вы создаете переменную, такую ​​как x, y, z выше, эти имена просто действуют как «указатели» или «ссылки» на объекты. Сам объект не знает, какое имя вы используете для него, и вы не можете легко (если вообще) получить имена всех ссылок на этот объект.

Обновление: однако функции имеют __name__ (если они не являются лямбдами), поэтому в этом случае вы можете сделать:

dict([(t.__name__, t) for t in fun_list])
11 голосов
/ 08 октября 2009

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

Если вы действительно хотите это сделать, вы можете использовать

def variable_for_value(value):
    for n,v in globals().items():
        if v == value:
            return n
    return None

Однако было бы лучше, если бы вы сначала перебирали имена:

my_list = ["x", "y", "z"] # x, y, z have been previously defined

for name in my_list:
    print "handling variable ", name
    bla = globals()[name]
    # do something to bla

6 голосов
/ 24 января 2014

Если вы хотите получить имена функций, лямбда-выражений или других функционально-подобных объектов, определенных в интерпретаторе, вы можете использовать dill.source.getname из dill. Он в значительной степени ищет метод __name__, но в некоторых случаях он знает другую магию о том, как найти имя ... или имя для объекта. Я не хочу вступать в спор о поиске единственного истинного имени для объекта python, что бы это ни значило.

>>> from dill.source import getname
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getname(add)
'add'
>>> print getname(squared)
'squared'
>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getname(f.bar)
'bar'
>>> 
>>> woohoo = squared
>>> plus = add
>>> getname(woohoo)
'squared'
>>> getname(plus)
'add'
6 голосов
/ 22 апреля 2013

Этот однострочник работает для всех типов объектов, если они находятся в globals() dict, которым они должны быть:

def name_of_global_obj(xx):
    return [objname for objname, oid in globals().items()
            if id(oid)==id(xx)][0]

или, что эквивалентно:

def name_of_global_obj(xx):
    for objname, oid in globals().items():
        if oid is xx:
            return objname
2 голосов
/ 04 мая 2015

Как уже упоминали другие, это действительно сложный вопрос. Решения для этого не «один размер подходит всем», даже удаленно. Трудность (или легкость) действительно будет зависеть от вашей ситуации.

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

Ниже следует кое-что из того, что я придумал.

Возвращаемое имя функции

Определить имя функции очень просто, поскольку она имеет атрибут __ name __ , содержащий объявленное имя функции.

name_of_function = lambda x : x.__name__

def name_of_function(arg):
    try:
        return arg.__name__
    except AttributeError:
        pass`

В качестве примера, если вы создадите функцию def test_function(): pass, затем copy_function = test_function, а затем name_of_function(copy_function), она вернет test_function .

Возвращает первое совпадающее имя объекта

  1. Проверьте, имеет ли объект атрибут __name __ и верните его, если так (только объявленные функции). Обратите внимание, что вы можете удалить этот тест, так как имя все еще будет в globals().

  2. Сравните значение arg со значениями элементов в globals() и верните имя первого совпадения. Обратите внимание, что я отфильтровываю имена, начинающиеся с '_'.

Результат будет состоять из имени первого соответствующего объекта, в противном случае None.

def name_of_object(arg):
    # check __name__ attribute (functions)
    try:
        return arg.__name__
    except AttributeError:
        pass

    for name, value in globals().items():
        if value is arg and not name.startswith('_'):
            return name

Вернуть все соответствующие имена объектов

  • Сравните значение arg со значениями элементов в globals() и сохраните имена в списке. Обратите внимание, что я отфильтровываю имена, начинающиеся с '_'.

Результат будет состоять из списка (для нескольких совпадений), строки (для одного совпадения), в противном случае - Нет. Конечно, вы должны настроить это поведение по мере необходимости.

def names_of_object(arg):
    results = [n for n, v in globals().items() if v is arg and not n.startswith('_')]
    return results[0] if len(results) is 1 else results if results else None
2 голосов
/ 08 октября 2009

Вот еще один способ думать об этом. Предположим, что существует функция name(), которая возвращает имя своего аргумента. Учитывая следующий код:

def f(a):
    return a

b = "x"
c = b
d = f(c)

e = [f(b), f(c), f(d)]

Что должно name(e[2]) вернуть и почему?

1 голос
/ 08 октября 2009

Используйте обратный диктант.

fun_dict = {'fun1': fun1,
            'fun2': fun2,
            'fun3': fun3}

r_dict = dict(zip(fun_dict.values(), fun_dict.keys()))

Обратный dict сопоставит каждую ссылку на функцию с точным именем, которое вы дали ей в fun_dict, которое может быть или не быть именем, которое вы использовали при определении функции. И эта техника обобщает на другие объекты, включая целые числа.

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

1 голос
/ 08 октября 2009

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

Для этого у вас есть замечательная функция getattr, которая позволяет вам получить объект по известному имени. Так что вы могли бы сделать, например:

funcs.py:

def func1(): pass
def func2(): pass

main.py:

import funcs
option = command_line_option()
getattr(funcs, option)()
1 голос
/ 08 октября 2009

Обратите внимание, что, как уже отмечалось, объекты в целом не знают и не могут знать, какие переменные связаны с ними, функции, определенные с помощью def, имеют имена в атрибуте __name__ (имя используется в def). Также, если функции определены в том же модуле (как в вашем примере), тогда globals() будет содержать расширенный набор нужного словаря.

def fun1:
  pass
def fun2:
  pass
def fun3:
  pass

fun_dict = {}
for f in [fun1, fun2, fun3]:
  fun_dict[f.__name__] = f
0 голосов
/ 24 января 2019

В Python есть имена, которые отображаются на объекты в хэш-карте, называемой пространством имен. В любой момент времени имя всегда ссылается только на один объект, но на один объект может ссылаться любое произвольное количество имен. Учитывая имя, для хэш-карты очень эффективно искать единственный объект, к которому относится это имя. Однако, учитывая объект , который, как уже упоминалось, может упоминаться несколькими именами, не существует эффективного способа поиска имен, которые к нему относятся. Что вам нужно сделать, это перебрать все имена в пространстве имен и проверить каждое из них в отдельности и посмотреть, соответствует ли оно вашему заданному объекту. Это легко сделать с помощью понимания списка:

[k for k,v in locals().items() if v is myobj]

В результате будет получен список строк, содержащих имена всех локальных «переменных», которые в настоящее время сопоставлены с объектом myobj.

>>> a = 1
>>> this_is_also_a = a
>>> this_is_a = a
>>> b = "ligma"
>>> c = [2,3, 534]
>>> [k for k,v in locals().items() if v is a]

['a', 'this_is_also_a', 'this_is_a']

Конечно, locals() можно заменить любым dict, в котором вы хотите искать имена, которые указывают на данный объект. Очевидно, что этот поиск может быть медленным для очень больших пространств имен, потому что они должны быть пройдены полностью.

...