Как выполнить переменные переменные в Python?
Вот описательная ручная запись, например: Переменные переменные
Я слышал, что это вообще плохая идея, и это дыра в безопасности на Python. Это правда?
Как выполнить переменные переменные в Python?
Вот описательная ручная запись, например: Переменные переменные
Я слышал, что это вообще плохая идея, и это дыра в безопасности на Python. Это правда?
Вы можете использовать словари для этого. Словари - это хранилища ключей и значений.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2
Вы можете использовать имена ключей переменных для достижения эффекта переменных переменных без риска для безопасности.
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
Для случаев, когда вы думаете о чем-то вроде
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
список может быть более подходящим, чем диктат. Список представляет упорядоченную последовательность объектов с целочисленными индексами:
l = ['foo', 'bar', 'baz']
print(l[1]) # prints bar, because indices start at 0
l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes']
Для упорядоченных последовательностей списки удобнее, чем диктовки с целочисленными ключами, потому что списки поддерживают итерацию в порядке индекса, нарезку, append
и другие операции, которые требуют неуклюжего управления ключами с помощью dict.
Используйте встроенную функцию getattr
, чтобы получить атрибут объекта по имени. Измените имя по мере необходимости.
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
Это не очень хорошая идея. Если вы обращаетесь к глобальной переменной, вы можете использовать globals()
.
>>> a = 10
>>> globals()['a']
10
Если вы хотите получить доступ к переменной в локальной области, вы можете использовать locals()
, но вы не можете присвоить значения возвращаемому dict.
Лучшее решение - использовать getattr
или сохранить ваши переменные в словаре, а затем получить к ним доступ по имени.
Всякий раз, когда вы хотите использовать переменные переменные, вероятно, лучше использовать словарь. Поэтому вместо написания
$foo = "bar"
$$foo = "baz"
вы пишете
mydict = {}
foo = "bar"
mydict[foo] = "baz"
Таким образом, вы не будете случайно перезаписывать ранее существовавшие переменные (это аспект безопасности), и вы можете иметь разные "пространства имен".
Новые кодеры иногда пишут такой код:
my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...
Затем кодер оставлен с кучей именованных переменных с усилием кодирования O (m * n), где m - количество именованных переменных, а n - количество раз, к которому должна быть доступна группа переменных (включая создание). Более проницательный новичок отмечает, что единственная разница в каждой из этих строк - это число, которое изменяется на основе правила и решает использовать цикл. Однако они зацикливаются на том, как динамически создавать эти имена переменных, и могут попробовать что-то вроде этого:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Вскоре они обнаруживают, что это не работает.
Если программе требуются произвольные переменные "имена", лучшим вариантом является словарь, как объясняется в других ответах. Однако, если вы просто пытаетесь создать много переменных, и вы не против ссылаться на них с помощью последовательности целых чисел, вы, вероятно, ищете list
. Это особенно актуально, если ваши данные однородны, например, ежедневные показания температуры, еженедельные оценки викторины или сетка графических виджетов.
Это можно собрать следующим образом:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Этот list
также может быть создан в одной строке с пониманием:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Результат в любом случае - это заполненный list
, с первым элементом, к которому обращается my_calculator.buttons[0]
, а затем с my_calculator.buttons[1]
и т.д. Имя переменной "base" становится именем list
, и для доступа к нему используется различный идентификатор.
Наконец, не забудьте другие структуры данных, такие как set
- это похоже на словарь, за исключением того, что каждое "имя" не имеет привязанного к нему значения. Если вам просто нужна "сумка" объектов, это может быть отличным выбором. Вместо этого:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
У вас будет следующее:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Используйте list
для последовательности похожих объектов, a set
для произвольно упорядоченного пакета объектов или dict
для мешка с именами со связанными значениями.
Вместо словаря вы также можете использовать namedtuple
из модуля коллекций, что облегчает доступ.
Например:
# using dictionary
variables = {}
variables["first"] = 34
variables["second"] = 45
print(variables["first"], variables["second"])
# using namedtuple
Variables = namedtuple('Variables', ['first', 'second'])
vars = Variables(34, 45)
print(vars.first, vars.second)
Класс SimpleNamespace
можно использовать для создания новых атрибутов с помощью setattr
или подкласса SimpleNamespace
и создания собственной функции для добавления новых имен атрибутов (переменных).
from types import SimpleNamespace
variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
Если вы не хотите использовать какой-либо объект, вы можете использовать setattr()
внутри своего текущего модуля:
import sys
current_module = module = sys.modules[__name__] # i.e the "file" where your code is written
setattr(current_module, 'variable_name', 15) # 15 is the value you assign to the var
print(variable_name) # >>> 15, created from a string
Для достижения этого поведения вы должны использовать globals()
встроенный метод:
def var_of_var(k, v):
globals()[k] = v
print variable_name # NameError: name 'variable_name' is not defined
some_name = 'variable_name'
globals()[some_name] = 123
print variable_name # 123
some_name = 'variable_name2'
var_of_var(some_name, 456)
print variable_name2 # 456
Я отвечаю на вопрос: Как получить значение переменной, учитывая ее имя в строке? который закрыт как дубликат со ссылкой на этот вопрос.
Если переменные, о которых идет речь, являются частью объекта (например, части класса), то некоторые полезные функции для достижения точности - это hasattr
, getattr
и setattr
.
Так, например, вы можете иметь:
class Variables(object):
def __init__(self):
self.foo = "initial_variable"
def create_new_var(self,name,value):
setattr(self,name,value)
def get_var(self,name):
if hasattr(self,name):
return getattr(self,name)
else:
raise("Class does not have a variable named: "+name)
Затем вы можете сделать:
v = Variables()
v.get_var("foo")
"initial_variable"
v.create_new_var(v.foo,"is actually not initial")
v.initial_variable
"на самом деле не является начальным"
Используйте globals()
На самом деле вы можете назначить переменные в глобальной области видимости динамически, например, если вы хотите 10 переменных, которые могут быть доступны в международном масштабе i_1
, i_2
... i_10
:
for i in range(10):
globals()['i_{}'.format(i)] = 'a'
Это назначит 'a' всем этим 10 переменным, конечно, вы можете также динамически изменять значение. Все эти переменные теперь доступны, как и другие глобально объявленные переменные:
>>> i_5
'a'
Консенсус заключается в том, чтобы использовать словарь для этого - см. другие ответы. Это хорошая идея для большинства случаев, однако из-за этого возникает много аспектов:
Тем не менее, я реализовал менеджер переменных переменных, который предоставляет некоторые из вышеперечисленных идей. Он работает для python 2 и 3.
Вы бы использовали класс следующим образом:
from variableVariablesManager import VariableVariablesManager
myVars = VariableVariablesManager()
myVars['test'] = 25
print(myVars['test'])
# define a const variable
myVars.defineConstVariable('myconst', 13)
try:
myVars['myconst'] = 14 # <- this raises an error, since 'myconst' must not be changed
print("not allowed")
except AttributeError as e:
pass
# rename a variable
myVars.renameVariable('myconst', 'myconstOther')
# preserve locality
def testLocalVar():
myVars = VariableVariablesManager()
myVars['test'] = 13
print("inside function myVars['test']:", myVars['test'])
testLocalVar()
print("outside function myVars['test']:", myVars['test'])
# define a global variable
myVars.defineGlobalVariable('globalVar', 12)
def testGlobalVar():
myVars = VariableVariablesManager()
print("inside function myVars['globalVar']:", myVars['globalVar'])
myVars['globalVar'] = 13
print("inside function myVars['globalVar'] (having been changed):", myVars['globalVar'])
testGlobalVar()
print("outside function myVars['globalVar']:", myVars['globalVar'])
Если вы хотите разрешить переписывание переменных только одного типа:
myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
Пожалуйста, обратитесь к следующему примеру для создания переменных во время выполнения. Вы можете использовать globals()
.
for i in range(3):
globals() ['variable_'+str(i)] = i
В приведенном выше примере я хочу создать три переменные: variable_0
, variable_1
и variable_2
во время выполнения со значениями 0,1 и 2 соответственно.
variable_0
[Output]:0
variable_1
[Output]:1
variable_2
[Output]:2
Чтобы получить доступ к значению переменных, созданных во время выполнения, вы можете использовать метод eval()
следующим образом:
for i in range(3):
globals() ['variable_'+str(i)] = i
print('Variable Value:',eval('variable_'+str(i)))
[Output]:
Variable Value: 0
Variable Value: 1
Variable Value: 2
Известен способ эмуляции контейнера для переменных, который поддерживает оба метода доступа: по имени переменной и строковому ключу.
class Vars:
def __init__(self, **kw):
self.__dict__.update(kw)
def __getitem__(self, key):
return self.__dict__[key]
def __setitem__(self, key, val):
self.__dict__[key] = val
def __contains__(self, name):
return name in self.__dict__
def __nonzero__(self):
return bool(self.__dict__)
def __iter__(self):
return iter(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __copy__(self):
return self.__class__(**self.__dict__)
def __repr__(self):
return 'Vars(' + ', '.join('%s=%r' % (k,v) for k,v in self.__dict__.items()) + ')'
>>> vars = Vars()
>>> vars.a = 1
>>> vars['b'] = 2
>>> print(vars)
Vars(a=1, b=2)
>>> print(vars['a'], vars.b)
1 2
>>> print(tuple(vars))
('a', 'b')
Любой набор переменных также может быть завершен в классе. Переменные "Variable" могут быть добавлены к экземпляру класса во время выполнения, напрямую обращаясь к встроенному словарю через атрибут __dict__.
Следующий код определяет класс Variables, который добавляет переменные (в этом случае атрибуты) к своему экземпляру во время построения. Имена переменных берутся из указанного списка (который, например, мог быть сгенерирован программным кодом):
# some list of variable names
L = ['a', 'b', 'c']
class Variables:
def __init__(self, L):
for item in L:
self.__dict__[item] = 100
v = Variables(L)
print(v.a, v.b, v.c)
#will produce 100 100 100
Вы можете использовать встроенную функцию vars()
>>> foo = 'bar'
>>> vars()[foo] = 'something'
>>> bar
'something'
a = 'hi'
# the expression below is a dynamic way of saying: b = 'by'
locals()['b'] = 'by'
print(a)
# 'hi'
print(b)
# 'by'