Как создать переменное число переменных?

Как выполнить переменные переменные в Python?

Вот описательная ручная запись, например: Переменные переменные

Я слышал, что это вообще плохая идея, и это дыра в безопасности на Python. Это правда?

Ответ 1

Вы можете использовать словари для этого. Словари - это хранилища ключей и значений.

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

Ответ 2

Используйте встроенную функцию getattr, чтобы получить атрибут объекта по имени. Измените имя по мере необходимости.

obj.spam = 'eggs'
name = 'spam'
getattr(obj, name)  # returns 'eggs'

Ответ 3

Это не очень хорошая идея. Если вы обращаетесь к глобальной переменной, вы можете использовать globals().

>>> a = 10
>>> globals()['a']
10

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

Лучшее решение - использовать getattr или сохранить ваши переменные в словаре, а затем получить к ним доступ по имени.

Ответ 4

Всякий раз, когда вы хотите использовать переменные переменные, вероятно, лучше использовать словарь. Поэтому вместо написания

$foo = "bar"
$$foo = "baz"

вы пишете

mydict = {}
foo = "bar"
mydict[foo] = "baz"

Таким образом, вы не будете случайно перезаписывать ранее существовавшие переменные (это аспект безопасности), и вы можете иметь разные "пространства имен".

Ответ 5

Новые кодеры иногда пишут такой код:

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 для мешка с именами со связанными значениями.

Ответ 6

Вместо словаря вы также можете использовать 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)

Ответ 7

Класс 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

Ответ 8

Если вы не хотите использовать какой-либо объект, вы можете использовать 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

Ответ 9

Для достижения этого поведения вы должны использовать 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

Ответ 10

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

Если переменные, о которых идет речь, являются частью объекта (например, части класса), то некоторые полезные функции для достижения точности - это 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

"на самом деле не является начальным"

Ответ 11

Используйте globals()

На самом деле вы можете назначить переменные в глобальной области видимости динамически, например, если вы хотите 10 переменных, которые могут быть доступны в международном масштабе i_1, i_2... i_10:

for i in range(10):
    globals()['i_{}'.format(i)] = 'a'

Это назначит 'a' всем этим 10 переменным, конечно, вы можете также динамически изменять значение. Все эти переменные теперь доступны, как и другие глобально объявленные переменные:

>>> i_5
'a'

Ответ 12

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

  • вы сами будете нести ответственность за этот словарь, включая сбор мусора (из переменных в-dict) и т.д.
  • нет либо локальности, либо глобальности для переменных переменных, это зависит от глобальности словаря
  • Если вы хотите переименовать имя переменной, вам нужно будет сделать это вручную
  • однако вы гораздо более гибкие, например.
    • вы можете решить перезаписать существующие переменные или...
    • ... выберите реализацию константных переменных
    • для создания исключения при перезаписи для разных типов
    • и др.

Тем не менее, я реализовал менеджер переменных переменных, который предоставляет некоторые из вышеперечисленных идей. Он работает для 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)

Ответ 13

Пожалуйста, обратитесь к следующему примеру для создания переменных во время выполнения. Вы можете использовать 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

Ответ 14

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

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

Ответ 15

Любой набор переменных также может быть завершен в классе. Переменные "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

Ответ 16

Вы можете использовать встроенную функцию vars()

>>> foo = 'bar'
>>> vars()[foo] = 'something'
>>> bar
'something'

Ответ 17

a = 'hi'
# the expression below is a dynamic way of saying: b = 'by'
locals()['b'] = 'by'

print(a)
# 'hi'
print(b)
# 'by'