Como realizo variáveis variáveis em Python?
Aqui está uma entrada manual elaborativa, por exemplo: Variáveis variáveis
Ouvi dizer que essa é uma má ideia em geral, e é uma falha de segurança no Python. Isso é verdade?
Como realizo variáveis variáveis em Python?
Aqui está uma entrada manual elaborativa, por exemplo: Variáveis variáveis
Ouvi dizer que essa é uma má ideia em geral, e é uma falha de segurança no Python. Isso é verdade?
Respostas:
Você pode usar dicionários para fazer isso. Dicionários são lojas de chaves e valores.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2
Você pode usar nomes de chaves variáveis para obter o efeito de variáveis variáveis sem o risco à segurança.
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
Nos casos em que você está pensando em fazer algo como
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
uma lista pode ser mais apropriada que um ditado. Uma lista representa uma sequência ordenada de objetos, com índices inteiros:
lst = ['foo', 'bar', 'baz']
print(lst[1]) # prints bar, because indices start at 0
lst.append('potatoes') # lst is now ['foo', 'bar', 'baz', 'potatoes']
Para as seqüências ordenadas, listas são mais convenientes do que dicts com chaves inteiras, porque as listas apoiar iteração na ordem do índice, corte , append
e outras operações que exigiria o gerenciamento de chaves desajeitado com um dicionário.
Use a getattr
função interna para obter um atributo em um objeto pelo nome. Modifique o nome conforme necessário.
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
Não é uma boa ideia. Se você estiver acessando uma variável global, poderá usar globals()
.
>>> a = 10
>>> globals()['a']
10
Se você deseja acessar uma variável no escopo local, pode usar locals()
, mas não pode atribuir valores ao ditado retornado.
Uma solução melhor é usar getattr
ou armazenar suas variáveis em um dicionário e depois acessá-las pelo nome.
Sempre que você quiser usar variáveis variáveis, provavelmente é melhor usar um dicionário. Então, ao invés de escrever
$foo = "bar"
$$foo = "baz"
você escreve
mydict = {}
foo = "bar"
mydict[foo] = "baz"
Dessa forma, você não substituirá acidentalmente variáveis existentes anteriormente (que é o aspecto de segurança) e poderá ter "namespaces" diferentes.
Às vezes, novos codificadores escrevem código assim:
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 codificador é então deixado com uma pilha de variáveis chamadas, com um esforço de codificação de O ( m * n ), onde m é o número de variáveis nomeadas e n é o número de vezes que o grupo de necessidades variáveis para ser acedido (incluindo criação ) O iniciante mais astuto observa que a única diferença em cada uma dessas linhas é um número que muda com base em uma regra e decide usar um loop. No entanto, eles ficam presos em como criar dinamicamente esses nomes de variáveis e podem tentar algo como isto:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Eles logo descobrem que isso não funciona.
Se o programa exigir "nomes" variáveis arbitrários, um dicionário é a melhor opção, conforme explicado em outras respostas. No entanto, se você está simplesmente tentando criar muitas variáveis e não se importa de se referir a elas com uma sequência de números inteiros, provavelmente está procurando por list
. Isso é particularmente verdadeiro se seus dados forem homogêneos, como leituras diárias de temperatura, pontuações semanais de questionários ou uma grade de widgets gráficos.
Isso pode ser montado da seguinte maneira:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Isso list
também pode ser criado em uma linha com uma compreensão:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Em ambos os casos, o resultado é um preenchido list
, com o primeiro elemento acessado com my_calculator.buttons[0]
, o próximo com my_calculator.buttons[1]
e assim por diante. O nome da variável "base" torna-se o nome do list
e o identificador variável é usado para acessá-lo.
Por fim, não esqueça de outras estruturas de dados, como o set
- isto é semelhante a um dicionário, exceto que cada "nome" não tem um valor anexado a ele. Se você simplesmente precisa de uma "bolsa" de objetos, essa pode ser uma ótima opção. Em vez de algo como isto:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
Você terá isso:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Use a list
para uma sequência de objetos semelhantes, set
para uma bolsa de objetos ordenada arbitrariamente ou dict
para uma bolsa de nomes com valores associados.
Em vez de um dicionário, você também pode usar namedtuple
o módulo de coleções, o que facilita o acesso.
Por exemplo:
# 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)
Se você não quiser usar nenhum objeto, ainda poderá usá-lo setattr()
dentro do seu módulo atual:
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
__dict__
variável no entanto. Gostaria de saber se existe um mecanismo geral para criar qualquer variável global dinamicamente.
globals()
pode fazer isso
A SimpleNamespace
classe pode ser usada para criar novos atributos com setattr
ou subclasse SimpleNamespace
e criar sua própria função para adicionar novos nomes de atributos (variáveis).
from types import SimpleNamespace
variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
Estou respondendo à pergunta: como obter o valor de uma variável com o nome em uma string? que é fechado como duplicado com um link para esta pergunta.
Se as variáveis em questão fazem parte de um objeto (parte de uma classe, por exemplo), em seguida, algumas funções úteis para conseguir exatamente o que são hasattr
, getattr
e setattr
.
Então, por exemplo, você pode ter:
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)
Então você pode fazer:
v = Variables()
v.get_var("foo")
"Variável_inicial"
v.create_new_var(v.foo,"is actually not initial")
v.initial_variable
"na verdade não é inicial"
Usar globals()
Você pode realmente atribuir variáveis ao escopo global dinamicamente, por exemplo, se desejar 10 variáveis que podem ser acessadas em um escopo global i_1
, i_2
... i_10
:
for i in range(10):
globals()['i_{}'.format(i)] = 'a'
Isso atribuirá 'a' a todas essas 10 variáveis, é claro que você também pode alterar o valor dinamicamente. Todas essas variáveis podem ser acessadas agora como outra variável declarada globalmente:
>>> i_5
'a'
Você precisa usar o globals()
método interno para obter esse comportamento:
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
O consenso é usar um dicionário para isso - veja as outras respostas. Essa é uma boa ideia para a maioria dos casos, no entanto, existem muitos aspectos decorrentes disso:
Dito isso, implementei uma classe- manager de variáveis variáveis, que fornece algumas das idéias acima. Funciona para o python 2 e 3.
Você usaria a classe assim:
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'])
Se você deseja permitir a substituição de variáveis apenas do mesmo tipo:
myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
Eu tentei tanto no python 3.7.3, você pode usar globals () ou vars ()
>>> food #Error
>>> milkshake #Error
>>> food="bread"
>>> drink="milkshake"
>>> globals()[food] = "strawberry flavor"
>>> vars()[drink] = "chocolate flavor"
>>> bread
'strawberry flavor'
>>> milkshake
'chocolate flavor'
>>> globals()[drink]
'chocolate flavor'
>>> vars()[food]
'strawberry flavor'
Qualquer conjunto de variáveis também pode ser agrupado em uma classe. As variáveis "Variáveis" podem ser adicionadas à instância da classe durante o tempo de execução, acessando diretamente o dicionário interno por meio do atributo __dict__.
O código a seguir define a classe Variables, que adiciona variáveis (neste caso, atributos) à sua instância durante a construção. Os nomes de variáveis são obtidos de uma lista especificada (que, por exemplo, poderia ter sido gerada pelo código do programa):
# 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