web-dev-qa-db-ja.com

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

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

以下に詳細な手動入力を示します。たとえば、変数

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

284
Pyornide

dictionaries を使用してこれを実現できます。辞書はキーと値のストアです。

>>> 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、および辞書による扱いにくいキー管理を必要とするその他の操作をサポートするためです。

241
c_harm

組み込みの getattr 関数を使用して、名前でオブジェクトの属性を取得します。必要に応じて名前を変更します。

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

良い考えではありません。グローバル変数にアクセスしている場合は、 globals() を使用できます。

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

ローカルスコープの変数にアクセスする場合は、 locals() を使用できますが、返されたdictに値を割り当てることはできません。

より良い解決策は、getattrを使用するか、変数を辞書に保存してから名前でアクセスすることです。

58
Nadia Alramli

変数変数を使用したいときはいつでも、辞書を使用したほうがいいでしょう。だから書く代わりに

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

あなたが書く

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

この方法では、以前の既存の変数(セキュリティの側面)を誤って上書きすることはなく、異なる「名前空間」を持つことができます。

31
sepp2k

新しいコーダーは時々このようなコードを書きます:

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

どちらの場合でも、結果は、my_calculator.buttons[0]で最初の要素にアクセスし、my_calculator.buttons[1]で次の要素にアクセスするなど、listが設定されます。 「ベース」変数名は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を、オブジェクトの任意の順序のバッグにはsetを、関連する値を持つ名前のバッグにはdictを使用します。

23
TigerhawkT3

辞書の代わりに、コレクションモジュールの 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)
9
ojas mohril

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
Bill Oldroyd

globals() built in method を使用して、その動作を実現する必要があります。

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
7
Andriy Ivaneyko

オブジェクトを使用したくない場合でも、現在のモジュール内で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
7

globals()を使用します

たとえば、グローバルスコープi_1i_2 ... i_10でアクセスできる10個の変数が必要な場合、実際に変数をグローバルスコープに動的に割り当てることができます。

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

これにより、これら10個の変数すべてに「a」が割り当てられます。もちろん、値を動的に変更することもできます。これらの変数はすべて、他のグローバルに宣言された変数と同様にアクセスできます。

>>> i_5
'a'
4
Rocky Li

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

問題の変数がオブジェクトの一部(クラスの一部など)である場合、正確に達成するためのいくつかの便利な関数はhasattrgetattr、および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

「実際には初期ではない」

3
patapouf_ai

変数のコンテナをエミュレートする既知の方法があります。これは、変数名と文字列キーによるアクセスの両方の方法をサポートします。

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

コンセンサスは、このために辞書を使用することです-他の回答を参照してください。ほとんどの場合、これは良い考えですが、これには多くの側面があります。

  • (辞書内変数の)ガベージコレクションなど、この辞書の責任はあなた自身にあります。
  • 変数変数には局所性も大域性もない、それは辞書の大域性に依存する
  • 変数名を変更する場合は、手動で名前を変更する必要があります
  • ただし、はるかに柔軟です(例:)
    • 既存の変数を上書きするか、...
    • ... 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)
1
DomTomCat

変数ランタイムを作成するには、次の例を参照してください。 globals()を使用できます。

for i in range(3):
    globals() ['variable_'+str(i)] = i

上記の例では、実行時にそれぞれ値0、1、2の3つの変数variable_0variable_1variable_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
1
Sayali Sonawane

変数のセットもクラスにまとめることができます。 __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
0
Alexey Rodimov

組み込み関数vars()を使用できます

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