Простой способ создания словаря отдельных переменных?
Я хотел бы иметь возможность получить имя переменной в виде строки, но я не знаю, обладает ли Python такими возможностями самоанализа. Что-то вроде:
>>> print(my_var.__name__)
'my_var'
Я хочу сделать это, потому что у меня есть куча переменных, которые я хотел бы превратить в словарь, например:
bar = True
foo = False
>>> my_dict = dict(bar=bar, foo=foo)
>>> print my_dict
{'foo': False, 'bar': True}
Но я бы хотел что-то более автоматическое, чем это.
В Python есть locals()
и vars()
, так что я думаю, что есть способ.
Ответы
Ответ 1
Вы пытаетесь это сделать?
dict( (name,eval(name)) for name in ['some','list','of','vars'] )
Пример
>>> some= 1
>>> list= 2
>>> of= 3
>>> vars= 4
>>> dict( (name,eval(name)) for name in ['some','list','of','vars'] )
{'list': 2, 'some': 1, 'vars': 4, 'of': 3}
Ответ 2
Как говорится, это не то, что вы делаете в Python - переменные на самом деле являются сопоставлениями имен для объектов.
Однако, здесь один из способов попробовать и сделать это:
>>> a = 1
>>> for k, v in list(locals().iteritems()):
if v is a:
a_as_str = k
>>> a_as_str
a
>>> type(a_as_str)
'str'
Ответ 3
Я хотел сделать это довольно много. Этот хак очень похож на предложение rlotun, но это однострочный, что важно для меня:
blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]
Python 3+
blah = 1
blah_name = [ k for k,v in locals().items() if v is blah][0]
Ответ 4
Это взломать. Он не будет работать во всех дистрибутивах реализации Python (в частности, те, у которых нет traceback.extract_stack
.)
import traceback
def make_dict(*expr):
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
begin=text.find('make_dict(')+len('make_dict(')
end=text.find(')',begin)
text=[name.strip() for name in text[begin:end].split(',')]
return dict(zip(text,expr))
bar=True
foo=False
print(make_dict(bar,foo))
# {'foo': False, 'bar': True}
Обратите внимание, что этот хак хрупкий:
make_dict(bar,
foo)
(вызов make_dict на 2 строках) не будет работать.
Вместо того, чтобы пытаться генерировать dict из значений foo
и bar
,
было бы намного больше Pythonic генерировать dict из строки имена переменных 'foo'
и 'bar'
:
dict([(name,locals()[name]) for name in ('foo','bar')])
Ответ 5
Это невозможно в Python, который на самом деле не имеет "переменных". У Python есть имена, и для одного и того же объекта может быть несколько имен.
Ответ 6
Я думаю, что моя проблема поможет проиллюстрировать, почему этот вопрос полезен, и он может дать немного больше информации о том, как ответить на него. Я написал небольшую функцию, чтобы выполнить быструю встроенную проверку головы на различные переменные в моем коде. По сути, в нем перечислены имя переменной, тип данных, размер и другие атрибуты, поэтому я могу быстро поймать любые ошибки, которые я сделал. Код прост:
def details(val):
vn = val.__name__ # If such a thing existed
vs = str(val)
print("The Value of "+ str(vn) + " is " + vs)
print("The data type of " + vn + " is " + str(type(val)))
Итак, если у вас есть сложная ситуация с словарем/списком/кортежем, было бы очень полезно, если интерпретатор вернет имя переменной, которое вы назначили. Например, вот странный словарь:
m = 'abracadabra'
mm=[]
for n in m:
mm.append(n)
mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)}
details(mydic)
The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
The data type of mydic is <type 'dict'>
details(mydic['first'])
The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic['first'] is <type 'list'>
details(mydic.keys())
The Value of mydic.keys() is ['second', 'third', 'first']
The data type of mydic.keys() is <type 'tuple'>
details(mydic['second'][0])
The Value of mydic['second'][0] is a
The data type of mydic['second'][0] is <type 'str'>
Я не уверен, поставил ли я это в нужное место, но я подумал, что это может помочь. Надеюсь, это так.
Ответ 7
Я написал аккуратную полезную функцию, основанную на ответе на этот вопрос. Я делаю это здесь, если это полезно.
def what(obj, callingLocals=locals()):
"""
quick function to print name of input and value.
If not for the default-Valued callingLocals, the function would always
get the name as "obj", which is not what I want.
"""
for k, v in list(callingLocals.items()):
if v is obj:
name = k
print(name, "=", obj)
использование:
>> a = 4
>> what(a)
a = 4
>>|
Ответ 8
Я нахожу, что если у вас уже есть определенный список значений, то способ, описанный @S. Лотты - лучшие; однако способ, описанный ниже, хорошо работает, чтобы получить все переменные и классы, добавленные во всем коде БЕЗ, чтобы указать имя переменной, хотя вы можете указать их, если хотите. Код может быть расширен для исключения классов.
import types
import math # mainly showing that you could import what you will before d
# Everything after this counts
d = dict(globals())
def kv_test(k,v):
return (k not in d and
k not in ['d','args'] and
type(v) is not types.FunctionType)
def magic_print(*args):
if len(args) == 0:
return {k:v for k,v in globals().iteritems() if kv_test(k,v)}
else:
return {k:v for k,v in magic_print().iteritems() if k in args}
if __name__ == '__main__':
foo = 1
bar = 2
baz = 3
print magic_print()
print magic_print('foo')
print magic_print('foo','bar')
Вывод:
{'baz': 3, 'foo': 1, 'bar': 2}
{'foo': 1}
{'foo': 1, 'bar': 2}
Ответ 9
В python 3 это легко
myVariable = 5
for v in locals():
if id(v) == id("myVariable"):
print(v, locals()[v])
это напечатает:
myVariable 5
Ответ 10
Python3. Используйте инспектор для захвата вызывающего локального пространства имен, а затем используйте идеи, представленные здесь. Можно вернуть более одного ответа, как было указано.
def varname(var):
import inspect
frame = inspect.currentframe()
var_id = id(var)
for name in frame.f_back.f_locals.keys():
try:
if id(eval(name)) == var_id:
return(name)
except:
pass
Ответ 11
Здесь функция, которую я создал для чтения имен переменных. Он более общий и может использоваться в различных приложениях:
def get_variable_name(*variable):
'''gets string of variable name
inputs
variable (str)
returns
string
'''
if len(variable) != 1:
raise Exception('len of variables inputed must be 1')
try:
return [k for k, v in locals().items() if v is variable[0]][0]
except:
return [k for k, v in globals().items() if v is variable[0]][0]
Чтобы использовать его в заданном вопросе:
>>> foo = False
>>> bar = True
>>> my_dict = {get_variable_name(foo):foo,
get_variable_name(bar):bar}
>>> my_dict
{'bar': True, 'foo': False}
Ответ 12
Прочитав нить, я увидел очень много трений. Это достаточно легко дать
плохой ответ, то пусть кто-то даст правильный ответ. Во всяком случае, вот что я нашел.
От: [effbot.org] (http://effbot.org/zone/python-objects.htm#names)
<я > Имена немного разные - они не являются действительно свойствами объекта, а сам объект не знает, как его назвать.
Объект может иметь любое количество имен или вообще не указывать имя.
Имена, находящиеся в пространствах имен (например, пространство имен модулей, пространство имен экземпляров, локальное пространство имен функций).
Обратите внимание: что он говорит сам объект не знает, что его назвал, так что это было ключом. Объекты Python не являются самореферентными. Затем он говорит: Имена живут в пространствах имен. Мы имеем это в TCL/TK. Поэтому, возможно, мой ответ поможет (но это действительно помогло мне).
jj = 123
print eval("'" + str(id(jj)) + "'")
print dir()
166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
Итак, в конце списка есть "jj".
Перепишите код как:
jj = 123
print eval("'" + str(id(jj)) + "'")
for x in dir():
print id(eval(x))
161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920
Этот отвратительный бит кода id - имя переменной/объекта/независимо от того, что вы-педантич-call-it.
Итак, вот оно. Адрес памяти "jj" одинаковый, когда мы ищем его напрямую, так же как мы ищем словарь в глобальном пространстве имен. Я уверен, что вы можете сделать функцию для этого. Просто запомните, в каком пространстве имен находится ваша переменная/объект/wypci.
QED.
Ответ 13
Только для справки, вот ответ с использованием ключевых слов:
Соберите аргументы, используя спецификатор ** в списке параметров функций; это дает вам аргументы ключевых слов в качестве словаря.
источник
Решение:
>>> def get_var_name(**kwargs): return kwargs.keys()[0]
используется как:
>>> var = 'this is variable'
>>> get_var_name(var=var)
'var'
оригинальный ответ: fooobar.com/questions/37737/...
Ответ 14
import re
import traceback
pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)')
def get_variable_name(x):
return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1)
a = 1
b = a
c = b
print get_variable_name(a)
print get_variable_name(b)
print get_variable_name(c)
Ответ 15
Я загрузил решение для pypi. Это модуль определения эквивалента # C nameof
функции.
Он выполняет итерацию с помощью инструкций байт-кода для входящего в него фрейма, получая имена переменных/атрибутов, переданных ему. Имена найдены в .argrepr
инструкций LOAD
следующих за именем функции.
Ответ 16
Я написал волшебство пакета, чтобы сделать эту магию надежно. Ты можешь написать:
from sorcery import dict_of
my_dict = dict_of(foo, bar)
Ответ 17
Большинство объектов не имеют атрибута __name__. (Классы, функции и модули делают, больше встроенных типов, которые имеют один?)
Что еще вы ожидаете от print(my_var.__name__)
кроме print("my_var")
? Вы можете просто использовать строку напрямую?
Вы можете "нарезать" dict:
def dict_slice(D, keys, default=None):
return dict((k, D.get(k, default)) for k in keys)
print dict_slice(locals(), ["foo", "bar"])
# or use set literal syntax if you have a recent enough version:
print dict_slice(locals(), {"foo", "bar"})
В качестве альтернативы:
throw = object() # sentinel
def dict_slice(D, keys, default=throw):
def get(k):
v = D.get(k, throw)
if v is not throw:
return v
if default is throw:
raise KeyError(k)
return default
return dict((k, get(k)) for k in keys)
Ответ 18
Хорошо, я столкнулся с той же самой необходимостью несколько дней назад и должен был получить имя переменной, которое указывало на объект.
И почему это было необходимо?
Короче, я создал плагин для Maya. Основной плагин был построен с использованием С++, но графический интерфейс рисован через Python (как не интенсивный процессор). Поскольку я пока не знаю, как return
несколько значений из подключаемого модуля, кроме значения по умолчанию MStatus
, поэтому для обновления словаря в Python мне пришлось передать имя переменной, указав на объект, реализующий GUI и содержащий сам словарь, к подключаемому модулю, а затем используйте MGlobal::executePythonCommand()
для обновления словаря из глобальной области майя.
Чтобы сделать это, я сделал что-то вроде:
import time
class foo(bar):
def __init__(self):
super(foo, self).__init__()
self.time = time.time() #almost guaranteed to be unique on a single computer
def name(self):
g = globals()
for x in g:
if isinstance(g[x], type(self)):
if g[x].time == self.time:
return x
#or you could:
#return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))])
#and return all keys pointing to object itself
Я знаю, что это не идеальное решение в globals
, которое многие клавиши могут указывать на один и тот же объект, например:
a = foo()
b = a
b.name()
>>>b
or
>>>a
и что подход не является потокобезопасным. Исправьте меня, если я ошибаюсь.
По крайней мере, этот подход решил мою проблему, получив имя любой переменной в глобальной области действия, которая указывала на сам объект и передала его плагину в качестве аргумента для его внутреннего использования.
Я пробовал это на int
(примитивный целочисленный класс), но проблема в том, что эти примитивные классы не обойтись (пожалуйста, исправьте техническую терминологию, используемую, если это неправильно). Вы можете повторно реализовать int
, а затем сделать int = foo
, но a = 3
никогда не будет объектом foo
, а примитива. Чтобы преодолеть это, вам нужно a = foo(3)
получить a.name()
для работы.
Ответ 19
С python 2.7 и новее есть также понимание словаря, которое делает его немного короче. Если возможно, я бы использовал getattr вместо eval (eval is evil), как в верхнем ответе. Self может быть любым объектом, который имеет контекст, на который вы смотрите. Это может быть объект или locals = locals() и т.д.
{name: getattr(self, name) for name in ['some', 'vars', 'here]}
Ответ 20
Возможно, я переусердствовал, но...
str_l = next((k for k,v in locals().items() if id(l) == id(v)))
>>> bar = True
>>> foo = False
>>> my_dict=dict(bar=bar, foo=foo)
>>> next((k for k,v in locals().items() if id(bar) == id(v)))
'bar'
>>> next((k for k,v in locals().items() if id(foo) == id(v)))
'foo'
>>> next((k for k,v in locals().items() if id(my_dict) == id(v)))
'my_dict'
Ответ 21
Я работал над подобной проблемой. @S.Lott сказал: "Если у вас есть список переменных, какой смысл" обнаруживать "их имена?" И мой ответ - просто посмотреть, можно ли это сделать, и если по какой-то причине вы хотите отсортировать переменные по типу в списках. Так или иначе, в моих исследованиях я пришел к этой теме, и мое решение немного расширено и основано на решении @rlotun. Еще одна вещь, @unutbu сказал: "Эта идея имеет смысл, но обратите внимание, что если два имени переменной ссылаются на одно и то же значение (например, True), тогда может быть возвращено имя непредвиденной переменной". В этом упражнении это было так, поэтому я справился с этим, используя для каждой возможности сходство с списком: isClass = [i for i in isClass if i != 'item']
. Без этого в каждом списке будет отображаться "элемент".
__metaclass__ = type
from types import *
class Class_1: pass
class Class_2: pass
list_1 = [1, 2, 3]
list_2 = ['dog', 'cat', 'bird']
tuple_1 = ('one', 'two', 'three')
tuple_2 = (1000, 2000, 3000)
dict_1 = {'one': 1, 'two': 2, 'three': 3}
dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'}
x = 23
y = 29
pie = 3.14159
eee = 2.71828
house = 'single story'
cabin = 'cozy'
isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = []
mixedDataTypes = [Class_1, list_1, tuple_1, dict_1, x, pie, house, Class_2, list_2, tuple_2, dict_2, y, eee, cabin]
print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes)
for item in mixedDataTypes:
try:
# if isinstance(item, ClassType): # use this for old class types (before 3.0)
if isinstance(item, type):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isClass.append(mapping_as_str)
isClass = [i for i in isClass if i != 'item']
elif isinstance(item, ListType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isList.append(mapping_as_str)
isList = [i for i in isList if i != 'item']
elif isinstance(item, TupleType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isTuple.append(mapping_as_str)
isTuple = [i for i in isTuple if i != 'item']
elif isinstance(item, DictType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isDict.append(mapping_as_str)
isDict = [i for i in isDict if i != 'item']
elif isinstance(item, IntType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isInt.append(mapping_as_str)
isInt = [i for i in isInt if i != 'item']
elif isinstance(item, FloatType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isFloat.append(mapping_as_str)
isFloat = [i for i in isFloat if i != 'item']
elif isinstance(item, StringType):
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
isString.append(mapping_as_str)
isString = [i for i in isString if i != 'item']
else:
for k, v in list(locals().iteritems()):
if v is item:
mapping_as_str = k
other.append(mapping_as_str)
other = [i for i in other if i != 'item']
except (TypeError, AttributeError), e:
print e
print '\n isClass:', len(isClass), isClass
print ' isList:', len(isList), isList
print ' isTuple:', len(isTuple), isTuple
print ' isDict:', len(isDict), isDict
print ' isInt:', len(isInt), isInt
print ' isFloat:', len(isFloat), isFloat
print 'isString:', len(isString), isString
print ' other:', len(other), other
# my output and the output I wanted
'''
MIXED_DATA_TYPES total count: 14
isClass: 2 ['Class_1', 'Class_2']
isList: 2 ['list_1', 'list_2']
isTuple: 2 ['tuple_1', 'tuple_2']
isDict: 2 ['dict_1', 'dict_2']
isInt: 2 ['x', 'y']
isFloat: 2 ['pie', 'eee']
isString: 2 ['house', 'cabin']
other: 0 []
'''
Ответ 22
вы можете использовать easydict
>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1
>>> d = edict(foo=3)
>>> d.foo
3
другой пример:
>>> d = EasyDict(log=False)
>>> d.debug = True
>>> d.items()
[('debug', True), ('log', False)]
Ответ 23
В python3 эта функция получит внешнее большинство имен в стеке:
import inspect
def retrieve_name(var):
"""
Gets the name of var. Does it from the out most frame inner-wards.
:param var: variable to get name from.
:return: string
"""
for fi in reversed(inspect.stack()):
names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
if len(names) > 0:
return names[0]
Это полезно в любом месте кода. Перемещает обратную стек, ищущую первое совпадение.
Ответ 24
Хотя это, вероятно, ужасная идея, она идет в том же направлении, что и ответ rlotun, но он вернет правильный результат чаще.
import inspect
def getVarName(getvar):
frame = inspect.currentframe()
callerLocals = frame.f_back.f_locals
for k, v in list(callerLocals.items()):
if v is getvar():
callerLocals.pop(k)
try:
getvar()
callerLocals[k] = v
except NameError:
callerLocals[k] = v
del frame
return k
del frame
Вы называете это следующим образом:
bar = True
foo = False
bean = False
fooName = getVarName(lambda: foo)
print(fooName) # prints "foo"
Ответ 25
должен получить список, затем вернуть
def get_var_name(**kwargs):
"""get variable name
get_var_name(var = var)
Returns:
[str] -- var name
"""
return list(kwargs.keys())[0]
Ответ 26
>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True
таким образом получите varname для, возможно, 'a' или 'b'.