Динамически устанавливаемая локальная переменная [дубликат]
этот вопрос уже есть ответ здесь:
Как вы динамически Настроить локальную переменную в Python?
(где имя переменной-это динамическая)
обновление: я знаю, что это не хорошо практика, и замечания являются законными, но это не делает его плохим вопросом, просто более теоретическим - я не понимаю, почему это оправдывает downvotes.
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