Динамически устанавливаемая локальная переменная [дубликат]



этот вопрос уже есть ответ здесь:



Как вы динамически Настроить локальную переменную в Python?



(где имя переменной-это динамическая)



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

579   7  

7 ответов:

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

>>> def foo():
    lcl = locals()
    lcl['xyz'] = 42
    print(xyz)


>>> foo()

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    foo()
  File "<pyshell#5>", line 4, in foo
    print(xyz)
NameError: global name 'xyz' is not defined

модификации locals() неопределено. Вне функции, когда locals() и globals() то же самое он будет работать; внутри функции он будет обычно не работает.

используйте словарь или установите атрибут для объекта:

d = {}
d['xyz'] = 42
print(d['xyz'])

или если вы предпочитаете, использовать класс:

class C: pass

obj = C()
setattr(obj, 'xyz', 42)
print(obj.xyz)

Edit: Доступ для переменных в пространствах имен, которые не являются функциями (поэтому модули, определения классов, экземпляры) обычно выполняются поисками по словарю (как указывает Свен в комментариях, есть исключения, например классы, которые определяют __slots__). Функция locals может быть оптимизирована для скорости, потому что компилятор (обычно) знает все имена заранее, поэтому нет словаря, пока вы не вызовете locals().

в реализации C Python locals() (вызывается изнутри функции) создает обычный словарь, инициализированный из текущих значений локальных переменных. Внутри каждой функции любое количество вызовов locals() вернет тот же словарь, но каждый вызов locals() обновит его с текущими значениями локальных переменных. Это может создать впечатление, что присвоение элементов словаря игнорируется (я изначально писал, что это так). Изменения существующих ключей в словаре, возвращенные из locals() поэтому только последний до следующего звоните в locals() в том же объеме.

в IronPython все работает немного по-другому. Любая функция, которая вызывает locals() внутри он использует словарь для своих локальных переменных, поэтому назначения локальным переменным изменяют словарь, а назначения словарю изменяют переменные но это только если вы явно вызываете locals() под этим именем. Если вы привязываете другое имя к locals функция в IronPython затем вызывая его дает вам локальные переменные для область, в которой имя было привязано, и через нее невозможно получить доступ к локальным функциям:

>>> def foo():
...     abc = 123
...     lcl = zzz()
...     lcl['abc'] = 456
...     deF = 789
...     print(abc)
...     print(zzz())
...     print(lcl)
...
>>> zzz =locals
>>> foo()
123
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
>>>

все это может измениться в любой момент. Единственное, что гарантировано, это то, что вы не можете зависеть от результатов присвоения словарю, возвращаемого locals().

другие предложили назначить locals(). Это не будет работать внутри функции, где местные жители доступны с помощью LOAD_FAST код операции,если у вас exec заявление где-то в функции. Для поддержки этого оператора, который может создавать новые переменные, которые неизвестны во время компиляции, Python затем вынужден обращаться к локальным переменным по имени внутри функции, поэтому запись в locals() строительство. Элемент exec можно из кода, который выполненный.

def func(varname):
    locals()[varname] = 42
    return answer           # only works if we passed in "answer" for varname
    exec ""                 # never executed

func("answer")
>>> 42

Примечание: это работает только в Python 2.x. они покончили с этой глупостью в Python 3 и других реализациях (Jython, IronPython и т. д.) может и не поддерживать его.

это плохая идея, хотя. Как вы получите доступ к переменным, если вы не знаете их имени? На locals()[xxx] наверное. Так почему бы просто не использовать свой собственный словарь, а не загрязнение locals() (и рискуя перезаписать переменную, которая действительно нужна вашей функции)?

(просто быстрая заметка для других googlin')

ок, так что изменение locals()это не тот путь ( при изменении globals()должно работать). В то же время, execможет быть, но это мучительно медленно, так что, как и с регулярными выражениями, мы можем захотеть compile() это первый:

# var0 = 0; var1 = 1; var2 = 2
code_text = '\n'.join( "var%d = %d" % (n, n) for n in xrange(3) )

filename = ''
code_chunk = compile( code_text, filename, 'exec' )

# now later we can use exec:
exec code_chunk # executes in the current context

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

common_data = ...stuff...
def process(record):
    ...logic...

def op():
    for fing in op.func_dict: # Key line number 1
        exec(fing + " = op.func_dict[fing]") # Key line number 2

    while common_data.still_recieving:
        with common_data._lock:
            if common_data.record_available:
                process(common_data.oldest_record)
        time.sleep(1.0)

op.func_dict.update(locals()) # Key line number 3
threading.Thread(target = op).start()

...

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

вы можете изменить locals() напрямую:

locals()['foo'] = 'bar'

Но лучшим способом было бы иметь некоторый dict, который содержит все ваши имена динамических переменных в качестве ключей словаря:

d = {}
for some in thing:
    d[some] = 'whatever'

вы можете использовать локальный словарь и поместить все динамические привязки как элементы в словарь. Затем, зная имя такой "динамической переменной", вы можете использовать это имя в качестве ключа для получения ее значения.

допустим, у нас есть словарь ниже:

DictionaryA = {'No Rating': ['Hobbit', 'Movie C', 'Movie G'],
               'Forget It': ['Avenger', 'Movie B'], 
               'Must See': ['Children of Men', 'Skyfall', 'Movie F'], 
               '3': ['X-Men', 'Movie D'],
               '2': ['Captain America', 'Movie E'], 
               '4': ['Transformers', 'Movie A']} 

Я хочу создать новые словари, как показано ниже:

NewDictionary1 = {'No Rating': ['Hobbit', 'Movie C', 'Movie G']} 
NewDictionary2 = {'Forget It': ['Avenger', 'Movie B']} 
NewDictionary3 = {'Must See': ['Children of Men', 'Skyfall', 'Movie F']}

a oneliner:

dics = [{k:v} for k,v in DictionaryA.iteritems()]

выводится в:

[{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}, {'Forget It': ['Avenger', 'Movie B']}, {'No Rating': ['Hobbit', 'Movie C', 'Movie G']}, {'3': ['X-Men', 'Movie D']}, {'2': ['Captain America', 'Movie E']}, {'4': ['Transformers', 'Movie A']}]

но для точного объявления переменных мы могли бы пойти с:

>>> i=0
>>> lcl = locals()
>>> for key,val in DictionaryA.iteritems():
        lcl["Dict" + str(i)] = {key:val}
        i += 1

как видно первые 3 Dict переменные:

>>> Dict0
{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}
>>> Dict1
{'Forget It': ['Avenger', 'Movie B']}
>>> Dict2
{'No Rating': ['Hobbit', 'Movie C', 'Movie G']}

как упоминалось другими, если вы хотите поместить его в функцию, вы должны добавить его в globals():

>>> glb = globals()
>>> for key,val in DictionaryA.iteritems():
        glb["Dict" + str(i)] = {key:val}
        i += 1

Comments

    Ничего не найдено.