Простіший спосіб створити словник окремих змінних?


220

Я хотів би отримати можливість назви змінної у вигляді рядка, але я не знаю, чи має 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(), так що я думаю, є спосіб.


31
Оскільки люди, мабуть, плутаються з приводу того, що запитують, я переставлю його тут, бо це цікаве питання. Враховуючи масив [foo, bar, baz], ви хочете словник на зразок {'foo': foo, 'bar': bar, 'baz': baz}, і ви не знаєте, які змінні є в масиві. тож запитуючий запитує, як ви отримаєте ім'я змінної як рядка в python. Тепер, сподіваємось, люди зможуть орієнтуватися на жахливі відповіді, щоб знайти кілька місць, де ви дізнаєтесь, чому це насправді не найкраща ідея в python.
Джессі Шерлок

3
Можливий дублікат: stackoverflow.com/questions/544919/…
Anderson Green

2
Одним із способів використання техніки є упорядкування викликів форматування рядків: "{var} {foo} {bar}". Формат (** найменування (var, foo, bar)), де "name" - функція, яка повертає дікт ( 'var': var), як описано.
Гордон Бін

4
Я думаю, що це насправді поганий питання, оскільки імена відображаються на об’єктах, ви можете мати кілька імен, що вказують на один і той же об'єкт, і я ніколи не бачив жодної потреби досягти мети перевернути це відображення. Тож той факт, що тут прийнята неправильна відповідь, є безглуздим - якщо пошук у Google привів вас сюди, ви, очевидно, задаєте неправильне запитання.
Аарон Холл

1
Це відмінна ідея для налагодження!
John ktejik

Відповіді:


48

Ви намагаєтесь це зробити?

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}

1
rlotun ближче до його початкового "духу", оскільки він дозволяє виявити ім'я. Я можу використати обидва ваші відповіді. А може просто використовувати мою прокляту руку для набору. Деякі речі просто не зроблені настільки автоматизованими ...
e-satis

7
@ e-satis: Щоб @ rlotun's працював, ви повинні надати список змінних. Якщо у вас є список змінних, який сенс "відкривати" їх назви?
С.Лотт

4
Чому eval замість явного використання місцевих та глобальних?

1
@Roger Pate: Тому що я не міг зрозуміти, в чому суть усієї вправи.
S.Lott

242
Ця відповідь не відповідає на поставлене запитання. Якщо у вас є список змінних, який сенс "відкривати" їх назви? Щоб уникнути дублювання, щоб замість print('x: ' + x)одного можна було писати magic_print(x)і мати один і той же вихід без написання імені змінної двічі.
Пьотр Доброгост

130

Як було сказано, це дійсно не те, що ви робите в 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'

14
Ця ідея має заслугу, але зауважте, що якщо два імені змінних посилаються на одне значення (наприклад True), то може бути повернуто ненавмисне ім'я змінної.
unutbu

14
Чому id(v) == id(a)замістьv is a ? Це не вдасться для об'єктів, пов'язаних з кількома змінними, такими як ints, string та будь-які подібні реалізовані типи, визначені користувачем.

Так, v is aбув би кращий вибір. І так, безумовно, небезпечно, враховуючи всі можливі підводні камені! ;-)
rlotun

16
@ e-satis Я здивований, що ви не позначили цю відповідь як відповідь, оскільки я згоден з вашим коментарем rlotun ближче до початкового "духу", оскільки він дозволяє виявити ім'я . Крім того, відповідь С.Лотта взагалі не відповідає на ваше запитання ...
Пьотр Доброгост

2
"надмірне та небезпечне" ... а використання eval чи не так?
помилка

63

Я хотів зробити це досить багато. Цей хак дуже схожий на пропозицію 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]

3
@keflavich мені дуже сподобався такий підхід і час від часу його використовую. Однак я не можу змусити його працювати всередині функцій. Я думаю, є "кращі" способи зробити це, але жоден не такий приємний, як просто Nbubis. Ви змогли використовувати його у функціях кефлавича? Тут я задаю питання з цього приводу.
Лев

10
Зауважимо, що в Python 3 iteritems()замінено наitems()
Джонатан Вілер

Це ненадійно: spam = 1; blah = 1; blah_name = [ k for k,v in locals().items() if v is blah][0]; print(blah_name)Виходиspam
andreasdr

1
@andreasdr це тому spam = 1, blah = 1; assert spam is blah. Рішення розривається при порівнянні примітивних типів даних.
JYun

17

Це злом. Він не працюватиме на всіх дистрибутивах реалізації 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 лінії) не працюватиме.

Замість того, щоб намагатися генерувати дикт із значень, foo і barPythonic було б набагато більше, щоб генерувати дикт із імен змінних рядків 'foo'і 'bar':

dict([(name,locals()[name]) for name in ('foo','bar')])

1
+1 для смарт-хака. Звичайно, зворотний слід дуже повільний, тому його може бути млявим.
e-satis

1
+1111111 !!!! Так, це повільно, але коли ви використовуєте для заміни того, print("a_very_long_name: {}'.format(a_very_long_name))хто хвилює!
frnhr

14

Це неможливо в Python, який насправді не має "змінних". У Python є імена, і для одного об’єкта може бути більше одного імені.


так, я знаю, я зробив це питання простим, але я очікував більше щось на кшталт "get_var_tags (var) [0]".
e-satis

10

Я думаю, що моя проблема допоможе проілюструвати, чому це питання корисне, і воно може дати трохи більше розуміння того, як на нього відповісти. Я написав невелику функцію, щоб зробити швидку вбудовану перевірку голови різних змінних у своєму коді. В основному в ньому перераховано ім'я змінної, тип даних, розмір та інші атрибути, тож я можу швидко зафіксувати будь-які помилки. Код простий:

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

Я не впевнений, чи поставлю це в потрібне місце, але я подумав, що це може допомогти. Я сподіваюся, що так і є.


Отже, за допомогою головної перевірки, чи враховується той факт, що змінні / імена можуть вказувати на різні речі в різний час у коді? Наприклад, myconnectionможна вказувати на булеве значення в одній точці, ціле число в інший час та з'єднання сокета в іншій точці виконання коду ??

9

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

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

6

Я вважаю, що якщо у вас вже є певний список значень, це спосіб, описаний @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}

6

У python 3 це легко

myVariable = 5
for v in locals():
  if id(v) == id("myVariable"):
    print(v, locals()[v])

це надрукує:

myVariable 5


Це схоже на підхід rlotun, але трохи простіше
офіційний

10
-1. Відкрийте нове вікно перекладача та спробуйте for v in locals().
Повітря

Я не зовсім впевнений, що ти маєш на увазі?
Офіційний сайт від

4
Це призведе до помилки: RuntimeError: словник змінив розмір під час ітерації ...
Nizar B.

2
проте ви можете зробитиfor v in list(locals()):
Філліда

5

Python3. Використовуйте Inspect для захоплення місцевого простору імен, що викликає, а потім використовуйте представлені тут ідеї. Може повернути більше однієї відповіді, як було зазначено.

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

Хороший відповідь, але для мене це краще: ... ID (Eval (ім'я, None, frame.f_back.f_locals)) == ...
Еммануель DUMAS

5

Ось функція, яку я створив для читання імен змінних. Він більш загальний і може використовуватися в різних програмах:

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}

4

Читаючи нитку, я побачив надзвичайно багато тертя. Досить просто дати погану відповідь, тоді нехай хтось дасть правильну відповідь. У всякому разі, ось що я знайшов.

Від: [effbot.org] ( http://effbot.org/zone/python-objects.htm#names )

Назви дещо відрізняються - вони насправді не властивості об'єкта, а сам об’єкт не знає, як його називати.

Об'єкт може мати будь-яку кількість імен або взагалі немає імені.

Імена живуть у просторах імен (наприклад, простір імен модулів, простір імен екземплярів, локальний простір імен).

Зауважте: що він каже, що сам об'єкт не знає, як його називати , тому це було підказкою. Об'єкти Python не є самореференційними. Потім він говорить: Імена живуть у просторах імен . Ми маємо це в TCL / TK. Тож, можливо, моя відповідь допоможе (але це допомогло мені)

    jj = 123
    print eval ("'" + str (id (jj)) + "'")
    друкувати реж ()

166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

Отже, в кінці списку є 'jj'.

Перепишіть код як:

    jj = 123
    print eval ("'" + str (id (jj)) + "'")
    для x in dir ():
        друк ідентифікатор (eval (x))

161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920

Цей неприємний біт ідентифікатора коду - це назва змінної / об'єкта / що-небудь-ви-педантика-call-it.

Отже, ось воно. Адреса пам'яті 'jj' така ж, коли ми шукаємо її безпосередньо, як і коли словник шукаємо в глобальному просторі імен. Я впевнений, що ви можете зробити функцію для цього. Просто пам’ятайте, в якому просторі імен знаходиться ваша змінна / об'єкт / wypci.

QED.


6
Тут у вас є два шалені використання eval. Перший такий самий , як: print id(jj). Другий просто шукає назву, і це можна зробити легше vars().
Нед Батчелдер

2

Можливо, я це переосмислюю, але ..

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'

Чудово! Це те, що я шукав. Спасибі @ rh0dium ... \ nvariable = 1 \n [k for k,v in locals().items() if id(variable) == id(v)] \n Out[14]: ['variable']
Майді

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

2

Я завантажив рішення на pypi . Це модуль, що визначає еквівалент функції C # nameof.

Він повторює інструкції байт-коду для фрейму, на який він викликається, отримуючи імена змінних / атрибутів, переданих йому. Імена знаходяться в .argreprв LOADінструкції наступного імені функції.



1

Більшість об’єктів не мають атрибута __name__ . (Класи, функції та модулі роблять; будь-які вбудовані типи, у яких є такий?)

Чого б ви ще очікували, print(my_var.__name__)крім іншого print("my_var")? Чи можете ви просто використовувати рядок безпосередньо?

Ви можете "нарізати" диктант:

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)

2
+1, але я знаю, що цього імені не існує, чому всі беруть це "щось на кшталт"? Ваше рішення не вирішує проблему, оскільки я не хочу вводити кодове ім'я, я б також вирішив рішення, яке я вже дав у питанні.
e-satis

3
@ e-satis: Якщо просто використання всього місцевого жителя () вирішує вашу проблему, я не маю поняття, про що ви питаєте. Я здогадуюсь, що ви добре з викликом some_func(var), тому я спробував вказати, що це не дуже далеко some_func("var"), оскільки dictslice дозволяє вам отримати відображення імен-значення одночасно для кількох змінних.

1

Ну, я стикався з такою самою потребою кілька днів тому, і мені довелося отримати ім’я змінної, яка вказувала на об'єкт сам .

І чому це було так потрібно?

Коротше кажучи, я будував плагін для Майї . Основний плагін був побудований за допомогою C ++, але графічний інтерфейс малюється через Python (як і не процесорний). Оскільки я, до сих пір, не знаю, як returnмножити значення з плагіна, за винятком типових MStatus, тому для оновлення словника в Python мені довелося передати ім’я змінної, вказуючи на об'єкт, що реалізує графічний інтерфейс і який містив сам словник до плагіна, а потім використовував 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()до роботи.


1

З python 2.7 і новішими є також розуміння словника, що робить його трохи коротшим. Якщо можливо, я б використав getattr замість eval (eval - зло), як у верхній відповіді. "Я" може бути будь-яким об'єктом, який має контекст, на який ви дивитесь. Це може бути об’єкт або місцеві жителі = locals () тощо.

{name: getattr(self, name) for name in ['some', 'vars', 'here]}

1

Я працював над подібною проблемою. @ 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 []
'''

Проблема, яку я брав би з цим, полягає в тому, що назви не є властивостями об'єктів. Один об’єкт може мати кілька імен або взагалі немає імені. Наприклад, ви додали pi = pieдо свого коду, ви отримаєте додатковий запис у своєму isFloatсписку. Якщо ви додали tuple_1[0]до свого mixedDataTypesсписку, його ім’я не буде знайдено, незважаючи на те, що "один" у вашому коді двічі (хоча завдяки строковому інтернування, вони обидва будуть посиланнями на один і той же об'єкт).
Blckknght

1
@Blckknght --- я згоден. Це просто ще один спосіб зробити щось, чого насправді не було зроблено. Я не сказав, що це дає унікальні результати або що це непогрішні. Роблячи це, я з’ясував, що використання piі eяк змінні викликало небажаний вихід, і це тому, що обидва є частиною mathбібліотеки. Для мене це була лише вправа, щоб зрозуміти, чи можна це зробити, хоча кінцевий результат не є ідеальним. У моєму вивченні цієї мови переходити до книжок лише так далеко. На мою думку, якщо ви дійсно хочете вивчити мову, то вам доведеться пограти "що якщо" і подивитися, що ви придумали.
Michael Swartz

1

Ви можете скористатися простим рішенням

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

1

На 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]

Це корисно в будь-якому місці коду. Перетинає перевернутий стек, шукаючи перший матч.


0

Хоча це, мабуть, жахлива ідея, вона йде в тій самій лінії, що і у відповіді 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"

0

Потрібно отримати список, а потім повернутись

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]

0

Він не поверне ім'я змінної, але ви можете легко створити словник із глобальної змінної.

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

0

З цим python-varnameви можете легко зробити це:

pip install python-varname

from varname import Wrapper

foo = Wrapper(True)
bar = Wrapper(False)

your_dict = {val.name: val.value for val in (foo, bar)}

print(your_dict)

# {'foo': True, 'bar': False}

Відмова: Я є автором цієї бібліотеки python-varname.


-1
>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True

таким чином отримайте varname для можливо 'a' або 'b'.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.