Как я могу получить имя объекта в Python?
Есть ли способ получить имя объекта в 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
Таким образом, мне нужно только один раз написать имена функций.
Ответы
Ответ 1
Объекты не обязательно имеют имена в python, поэтому вы не можете получить имя. Для объектов весьма __name__
иметь атрибут __name__
в тех случаях, когда они имеют имя, но это не является частью стандартного python, и большинство встроенных типов не имеют его.
Когда вы создаете переменную, такую как x, y, z выше, эти имена просто действуют как "указатели" или "ссылки" на объекты. Сам объект не знает, какое имя вы используете для него, и вы не можете легко (если вообще) получить имена всех ссылок на этот объект.
Обновление: Однако функции имеют __name__
(если они не являются лямбдами), поэтому в этом случае вы можете сделать:
dict([(t.__name__, t) for t in fun_list])
Ответ 2
Это не реально, так как могут быть несколько переменных, имеющих одно и то же значение, или значение не может иметь никакой переменной, или значение может иметь одно и то же значение как переменная только случайно.
Если вы действительно этого хотите, вы можете использовать
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
Ответ 3
Если вы хотите получить имена функций или лямбда или другие функциональноподобные объекты, которые определены в интерпретаторе, вы можете использовать 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'
Ответ 4
Этот однострочный файл работает для всех типов объектов, если они находятся в 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
Ответ 5
Вот еще один способ подумать об этом. Предположим, что существует функция name()
, которая возвращает имя своего аргумента. Учитывая следующий код:
def f(a):
return a
b = "x"
c = b
d = f(c)
e = [f(b), f(c), f(d)]
Что должно вернуть name(e[2])
и почему?
Ответ 6
Как уже упоминалось, это очень сложный вопрос. Решения для этого не "подходят для всех", даже не отдаленно. Трудность (или легкость) действительно будет зависеть от вашей ситуации.
Я несколько раз сталкивался с этой проблемой, но совсем недавно при создании функции отладки. Я хотел, чтобы функция принимала некоторые неизвестные объекты в качестве аргументов и печатала их объявленные имена и содержимое. Получить содержимое легко, конечно, но объявленное имя - это еще одна история.
Далее следует то, что я придумал.
Имя функции возврата
Определение имени функции очень просто, так как оно содержит атрибут __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.
Вернуть первое совпадающее имя объекта
-
Проверьте, имеет ли объект атрибут __name__ и возвращает его, если это так (только объявленные функции). Обратите внимание, что этот тест можно удалить, так как имя все равно будет находиться в globals()
.
-
Сравните значение 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()
и сохраните имена в списке. Обратите внимание, что я отфильтровываю имена, начинающиеся с '_'.
Результат будет состоять из списка (для нескольких совпадений), строки (для одного совпадения), иначе None. Конечно, вы должны отрегулировать это поведение по мере необходимости.
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
Ответ 7
Обратите внимание, что пока, как отмечено, объекты вообще не знают и не могут знать, какие переменные связаны с ними, функции, определенные с помощью 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
Ответ 8
И причина, по которой я хочу иметь имя функции, заключается в том, что я хочу создать fun_dict
, не записывая имена функций дважды, поскольку это похоже на хороший способ создания ошибок.
Для этого у вас есть замечательная функция getattr
, которая позволяет вам получить объект по известному имени. Таким образом, вы можете сделать, например:
funcs.py:
def func1(): pass
def func2(): pass
main.py:
import funcs
option = command_line_option()
getattr(funcs, option)()
Ответ 9
Используйте обратный dict.
fun_dict = {'fun1': fun1,
'fun2': fun2,
'fun3': fun3}
r_dict = dict(zip(fun_dict.values(), fun_dict.keys()))
Обратный dict отобразит каждую функциональную ссылку на точное имя, которое вы дали ему в fun_dict, которое может быть или не быть именем, которое вы использовали при определении функции. И этот метод обобщается на другие объекты, включая целые числа.
Для дополнительного удовольствия и безумия вы можете сохранить прямые и обратные значения в одном и том же dict. Я бы не сделал этого, если бы вы отображали строки в строках, но если вы делаете что-то вроде ссылок на функции и строк, это не слишком сумасшествие.
Ответ 10
Имена переменных можно найти в файлах globals() и locals(). Но они не дадут вам то, что вы ищете выше. "bla" будет содержать значение каждого элемента my_list, а не переменной.
Ответ 11
Обычно, когда вы хотите сделать что-то подобное, вы создаете класс для хранения всех этих функций и назовите их с помощью некоторого ясного префикса cmd_
или тому подобного. Затем вы берете строку из этой команды и пытаетесь получить этот атрибут из класса с префиксом cmd_
с ним. Теперь вам нужно только добавить новый класс/метод в класс, и он доступен для ваших абонентов. И вы можете использовать строки документа для автоматического создания текста справки.
Как описано в других ответах, вы можете сделать тот же подход с globals()
и регулярными функциями в вашем модуле, чтобы более точно соответствовать тому, что вы просили.
Что-то вроде этого:
class Tasks:
def cmd_doit(self):
# do it here
func_name = parse_commandline()
try:
func = getattr('cmd_' + func_name, Tasks())
except AttributeError:
# bad command: exit or whatever
func()
Ответ 12
Я столкнулся с этой страницей, задаваясь тем же вопросом.
Как отмечали другие, достаточно просто взять атрибут __name__
из функции, чтобы определить имя функции. Это немного сложнее с объектами, которые не имеют разумного способа определить __name__
, т.е. Базовые/примитивные объекты, такие как экземпляры basestring, ints, longs и т.д.
Короче говоря, вы, вероятно, могли бы использовать модуль проверки, чтобы получить обоснованное предположение о том, какой он есть, но вам, вероятно, нужно будет знать, какой кадр вы работаете/переходите по стеку, чтобы найти правильный. Но мне не хотелось бы представлять себе, насколько весело это будет пытаться разобраться с кодом eval/exec'.
% python2 whats_my_name_again.py
needle => ''b''
['a', 'b']
[]
needle => '<function foo at 0x289d08ec>'
['c']
['foo']
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
needle => '<__main__.a_class instance at 0x289d3aac>'
['e', 'd']
[]
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
%
whats_my_name_again.py:
#!/usr/bin/env python
import inspect
class a_class:
def __init__(self):
pass
def foo():
def bar():
pass
a = 'b'
b = 'b'
c = foo
d = a_class()
e = d
f = bar
#print('globals', inspect.stack()[0][0].f_globals)
#print('locals', inspect.stack()[0][0].f_locals)
assert(inspect.stack()[0][0].f_globals == globals())
assert(inspect.stack()[0][0].f_locals == locals())
in_a_haystack = lambda: value == needle and key != 'needle'
for needle in (a, foo, bar, d, f, ):
print("needle => '%r'" % (needle, ))
print([key for key, value in locals().iteritems() if in_a_haystack()])
print([key for key, value in globals().iteritems() if in_a_haystack()])
foo()
Ответ 13
Вы определяете class
и добавляете частную функцию Unicode, вставляете class
, как
class example:
def __init__(self, name):
self.name = name
def __unicode__(self):
return self.name
Конечно, вам нужно добавить дополнительную переменную self.name
, которая является именем объекта.
Ответ 14
Вот мой ответ, я также использую globals(). items()
def get_name_of_obj(obj, except_word = ""):
for name, item in globals().items():
if item == obj and name != except_word:
return name
Я добавил except_word, потому что хочу отфильтровать некоторое слово, используемое в цикле for.
Если вы его не добавили, ключевое слово in for loop может смутить эту функцию, иногда ключевое слово типа "each_item" в следующем случае может отображаться в результате функции, зависит от того, что вы сделали с вашим циклом.
например.
for each_item in [objA, objB, objC]:
get_name_of_obj(obj, "each_item")
например.
>>> objA = [1, 2, 3]
>>> objB = ('a', {'b':'thi is B'}, 'c')
>>> for each_item in [objA, objB]:
... get_name_of_obj(each_item)
...
'objA'
'objB'
>>>
>>>
>>> for each_item in [objA, objB]:
... get_name_of_obj(each_item)
...
'objA'
'objB'
>>>
>>>
>>> objC = [{'a1':'a2'}]
>>>
>>> for item in [objA, objB, objC]:
... get_name_of_obj(item)
...
'objA'
'item' <<<<<<<<<< --------- this is no good
'item'
>>> for item in [objA, objB]:
... get_name_of_obj(item)
...
'objA'
'item' <<<<<<<<--------this is no good
>>>
>>> for item in [objA, objB, objC]:
... get_name_of_obj(item, "item")
...
'objA'
'objB' <<<<<<<<<<--------- now it ok
'objC'
>>>
Надеюсь, это поможет.
Ответ 15
У 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
, который вы хотите искать имена, которые указывают на данный объект. Очевидно, что этот поиск может быть медленным для очень больших пространств имен, потому что они должны быть пройдены полностью.