변수 수의 변수를 작성하는 방법


364

파이썬에서 변수 변수를 어떻게 달성합니까?

다음은 정교한 수동 항목입니다. 변수 변수

나는 이것이 일반적으로 나쁜 생각이라고 들었고, 파이썬의 보안 구멍입니다. 그게 사실입니까?


39
공포를 유발하는 것은 유지 관리 및 디버깅 측면입니다. 코드에 실제로 'foo'를 변경할 위치가 없을 때 변수 'foo'가 변경된 위치를 찾으려고 상상해보십시오. 당신이 유지해야하는 다른 사람의 코드라는 것을 더 상상해보십시오. 자, 이제 당신은 행복한 곳으로 갈 수 있습니다.
glenn jackman

4
지금까지 언급되지 않은 또 다른 함정은 동적으로 작성된 변수가 논리에 사용되는 변수와 이름이 같은 경우입니다. 기본적으로 소프트웨어는 입력에 대한 인질로 소프트웨어를 엽니 다.
holdenweb

여기의 모든 응답은 이름으로 동적으로 액세스하려는 기본 변수에 액세스 할 수 있다고 가정합니다. 항상 그런 것은 아닙니다. PHP에서 예제 동작을 재현하는 가장 일반적인 방법은 다음과 같이 eval ()을 사용하는 것입니다. var_name = 'foo'; 바 = 5; 출력 = eval (var_name)
Luis Vazquez

1
전역 및 로컬 변수를 기본 사전에 액세스하여 수정할 수 있습니다. 유지 관리 측면에서 끔찍한 아이디어입니다 ...하지만 globals (). update ()locals (). update () 를 통해 수행 할 수 있습니다 (또는 그중 하나에서 dict 참조를 저장하고 다른 사전과 같이 사용하여) ). 권장하지 않음 ...하지만 가능하다는 것을 알아야합니다.
짐 데니스

(이 종류의 조작을 요청하는 비슷한 질문이이 "닫기"질문에 대한 포인터로 닫 혔기 때문에이 의견을 추가하고 있습니다. 닫힌 질문 다음에 나오는 사람들이 답변을 받기를 원합니다).
짐 데니스

답변:


297

사전 을 사용 하여이를 수행 할 수 있습니다 . 사전은 키와 값의 저장소입니다.

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

dict보다 목록이 더 적합 할 수 있습니다. 목록은 정수 인덱스를 사용하여 순서가 지정된 객체 시퀀스를 나타냅니다.

lst = ['foo', 'bar', 'baz']
print(lst[1])           # prints bar, because indices start at 0
lst.append('potatoes')  # lst is now ['foo', 'bar', 'baz', 'potatoes']

리스트는 인덱스 순서에 반복을 지원하기 때문에 명령 시퀀스를 들어, 목록, 정수 키 dicts보다 더 편리 슬라이스 , append사전인가와 어색한 키 관리를 필요로하고, 다른 작업.


88

내장 getattr함수를 사용하여 이름으로 객체의 속성을 가져옵니다. 필요에 따라 이름을 수정하십시오.

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

70

좋은 생각이 아닙니다. 전역 변수에 액세스하는 경우 사용할 수 있습니다 globals().

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

로컬 범위의 변수에 액세스하려면을 사용할 수 locals()있지만 반환 된 dict에 값을 할당 할 수 없습니다.

더 좋은 해결책getattr변수를 사전에 사용 하거나 저장 한 다음 이름으로 변수에 액세스하는 것입니다.


locals (). update ({ 'new_local_var': 'some local value'}) 는 Python 3.7.6에서 나에게 잘 작동합니다. 따라서 값을 할당 할 수 없다고 말할 때 무슨 의미인지 잘 모르겠습니다.
짐 데니스

주어 x = "foo"locals()["x"] = "bar"사용은 print x출력을 제공 bar자이 썬 2.5.2을 위해. 이것은 maximo의 주문형 자동화 스크립트로 테스트되었습니다 .
설교자

37

변수 변수를 사용할 때마다 사전을 사용하는 것이 좋습니다. 그래서 글을 쓰는 대신

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

당신은 쓰기

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

이렇게하면 실수로 기존 변수 (보안 측면)를 덮어 쓰지 않으며 다른 "네임 스페이스"를 가질 수 있습니다.


34

새로운 코더는 때때로 다음과 같은 코드를 작성합니다.

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]됩니다. "기본"변수 이름은의 이름이되고 변수 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관련 값 이름의 가방.


12

사전 대신 namedtuplecollections 모듈에서 사용할 수 있으므로 액세스가 더 쉽습니다.

예를 들면 다음과 같습니다.

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

10

객체를 사용하지 않으려면 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

이것은 'exec'를 사용하는 것보다 나에게 더 잘 들립니다.
fralau

__dict__그러나 변수 와 함께 작동하지 않습니다 . 만들 수있는 일반적인 메커니즘이 있는지 궁금해 어떤 동적으로 전역 변수를.
Alexey

globals()이 작업을 수행
Guillaume Lebreton

9

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

6

나는 질문에 대답하고있다 : 문자열에 이름이 주어진 변수의 값을 얻는 방법? 이 질문에 대한 링크와 함께 중복으로 닫힙니다.

문제의 변수가 객체 (예를 들어, 클래스의 일부)의 일부인 경우, 몇 가지 유용한 기능은이 정확히 달성하기 위해 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

"실제로 초기가 아니다"


5

사용하다 globals()

당신은 전역 실제로 할당 변수를 동적으로, 예를 들어, 당신이 전역 범위에 액세스 할 수 있습니다 (10 개) 변수를 할 수 있다면 i_1, i_2... i_10:

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

이렇게하면 10 개의 변수 모두에 'a'가 할당되며 물론 값을 동적으로 변경할 수도 있습니다. 이러한 전역 변수는 모두 전역 적으로 선언 된 다른 변수처럼 액세스 할 수 있습니다.

>>> i_5
'a'

4

해당 동작을 달성 하려면 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

3

합의는이를 위해 사전을 사용하는 것입니다. 다른 답변을보십시오. 이것은 대부분의 경우 좋은 아이디어이지만 이로 인해 여러 가지 측면이 있습니다.

  • 가비지 수집 (예측 변수) 등을 포함하여이 사전에 대한 책임은 사용자에게 있습니다.
  • 변수 변수에 대한 지역성 또는 전역 성이 없으며 사전의 전역성에 따라 다릅니다.
  • 변수 이름을 바꾸려면 수동으로 변경해야합니다
  • 그러나 훨씬 유연합니다. 예 :
    • 기존 변수를 덮어 쓰거나 ...
    • ... const 변수를 구현하도록 선택
    • 다른 유형의 덮어 쓰기에 대한 예외를 제기
    • 기타

즉, 변수 변수 관리자를 구현했습니다. , 위의 아이디어 중 일부를 제공 클래스를 . 파이썬 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)

언뜻보기에 오랫동안 camelised 수입은 이것이 Java라고 생각하게했습니다.
markroxor

3

파이썬 3.7.3에서 모두 시도했지만 globals () 또는 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'


참조 :
https://www.daniweb.com/programming/software-development/threads/111526/setting-a-string-as-a-variable-name#post548936


0

모든 변수 집합을 클래스로 래핑 할 수도 있습니다. __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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.