可変数の変数を作成するにはどうすればよいですか?


364

Pythonで変数変数を実現するにはどうすればよいですか?

たとえば、以下は手の込んだ手動入力です。

これは一般に悪い考えだと聞いていますが、これはPythonのセキュリティホールです。本当?


39
それは恐怖を引き起こすメンテナンスとデバッグの側面です。コード内に実際に「foo」を変更する場所がないときに、変数「foo」が変更された場所を見つけようとしていると想像してみてください。さらに、それはあなたが維持しなければならない他の誰かのコードであると想像してください... OK、あなたは今あなたの幸せな場所に行くことができます。
グレン・ジャックマン、2009

4
これまでに言及されていないさらなる落とし穴は、そのような動的に作成された変数が、ロジックで使用される変数と同じ名前を持っているかどうかです。あなたは本質的に、それが与えられた入力への人質としてソフトウェアを開きます。
holdenweb 2014

ここでのすべての応答は、名前で動的にアクセスする基本変数にアクセスできることを前提としていますが、常にそうであるとは限りません。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'
...

リストは辞書よりも適切かもしれません。リストは、整数インデックスを使用して、オブジェクトの順序付けされたシーケンスを表します。

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"使用すると、Jython 2.5.2 print xの出力barが得られます。これは、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は、内包表記付きの1行で作成することもできます。

my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]

いずれの場合も、結果はlistで作成され、最初の要素はでアクセスされmy_calculator.buttons[0]、次の要素はでアクセスさmy_calculator.buttons[1]れます。「ベース」変数名がの名前になり、listそれにアクセスするために可変IDが使用されます。

最後に、などの他のデータ構造を忘れないでください。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し、任意に順序付けされたオブジェクトのバッグにはa dictを使用し、関連する値を持つ名前のバッグにはを使用します。


12

辞書の代わりに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)

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__ただし、これは変数では機能しません。作成するための一般的なメカニズムがあるのだろうかどの動的にグローバル変数を。
アレクセイ

globals()これを行うことができます
Guillaume Lebreton 2018年

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

私は質問に答えています:文字列でその名前を与えられた変数の値を取得する方法? これは、この質問へのリンクを持つ重複として閉じられます。

問題の変数は、オブジェクト(例えば、クラスの一部)の一部である場合は、いくつかの有用な機能があることを正確に達成するためにhasattrgetattrsetattr

たとえば、次のようにすることができます。

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

たとえば、グローバルスコープi_1でアクセスできる10個の変数が必要な場合は、変数をグローバルスコープに動的に割り当てることができ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変数の実装を選択
    • 異なるタイプの上書きの例外を発生させる

そうは言っても、上記のアイデアのいくつかを提供する変数変数マネージャー -classを実装しました。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)

一見すると、ラクダに乗った長い輸入品から、これはJavaだと思いました。
markroxor

3

私はpython 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__属性を介して組み込み辞書に直接アクセスすることにより、クラスインスタンスに追加できます。

次のコードは、変数クラスを定義します。このクラスは、構築中にインスタンスに変数(この場合は属性)を追加します。変数名は、指定されたリストから取得されます(たとえば、プログラムコードによって生成された可能性があります)。

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