Değişken sayıda değişkeni nasıl oluştururum?


364

Python'da değişken değişkenleri nasıl başarabilirim?

İşte ayrıntılı bir manuel giriş, örneğin: Değişken değişkenler

Bunun genel olarak kötü bir fikir olduğunu duydum ve Python'da bir güvenlik deliği. Bu doğru mu?


39
dehşete neden olan bakım ve hata ayıklama unsurlarıdır. Kodunuzda gerçekten 'foo'yu değiştirdiğiniz hiçbir yer olmadığında' foo 'değişkeninin nerede değiştiğini bulmaya çalıştığınızı düşünün. Ayrıca, bakmanız gereken bir başkasının kodu olduğunu düşünün ... Tamam, şimdi mutlu yerinize gidebilirsiniz.
glenn jackman

4
Şimdiye kadar bahsedilmeyen bir başka tuzak, dinamik olarak oluşturulmuş bir değişkenin mantığınızda kullanılan bir değişkenle aynı ada sahip olması. Yazılımınızı, verilmiş olan girdiye rehin olarak açıyorsunuz.
holdenweb

Buradaki tüm yanıtlar, dinamik olarak erişmek istediğiniz temel değişkenlere ada göre eriştiğinizi varsayar; bu her zaman geçerli değildir. PHP örnek davranış çoğaltmak için en genel yaklaşım eval () böyle kullanmaktır: var_name = 'foo'; bar = 5; çıktı = eval (var_name)
Luis Vazquez

1
Genel ve yerel değişkenlerinizi, bunlar için temel sözlüklere erişerek değiştirebilirsiniz; bu bakım açısından korkunç bir fikirdir ... ancak globals (). update () ve locals (). update () (ya da bunlardan herhangi birinin dict referansını kaydedip başka bir sözlük gibi kullanarak) yapılabilir. ). ÖNERİLMEZ ... ama bunun mümkün olduğunu bilmelisiniz.
Jim Dennis

(Ben bu yorumu ekleyerek benzer bir soru, daha spesifik olarak bu tür manipülasyon isteyen bu "yeterince yakın" soruya bir işaretçi ile kapatıldı. Ben kapalı soruyu takip edenler cevaplarını almak istiyorum).
Jim Dennis

Yanıtlar:


297

Bunu yapmak için sözlükleri kullanabilirsiniz . Sözlükler, anahtar ve değer depolarıdır.

>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2

Güvenlik riski olmadan değişken değişkenlerin etkisini elde etmek için değişken anahtar adlarını kullanabilirsiniz.

>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'

Gibi bir şey yapmayı düşündüğünüz durumlar için

var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...

bir liste bir diktenden daha uygun olabilir. Liste, tamsayı dizinleriyle sıralı bir nesne dizisini temsil eder:

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

Listeleri endeksi sırayla, içinde yinelemeyi desteklemesi nedeniyle sipariş dizileri için, liste, tamsayı tuşlarıyla dicts daha kullanışlıdır dilimleme , appendbir dict ile garip anahtar yönetimini gerektirir ve diğer operasyonlar.


88

getattrNesne üzerinde ada göre bir öznitelik almak için yerleşik işlevi kullanın. Adı gerektiği gibi değiştirin.

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

70

İyi bir fikir değil. Genel bir değişkene erişiyorsanız kullanabilirsiniz globals().

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

Yerel kapsamdaki bir değişkene erişmek istiyorsanız kullanabilirsiniz locals(), ancak döndürülen dikte değer atayamazsınız.

Daha iyi bir çözüm , getattrdeğişkenlerinizi bir sözlükte kullanmak veya saklamak ve daha sonra ada göre erişmek.


update ({'new_local_var': 'bazı yerel değer'}) Python 3.7.6'da benim için iyi çalışıyor; bu yüzden değer atayamayacağınızı söylediğinizde ne demek istediğinizden emin değilim.
Jim Dennis

Verilen x = "foo"ve locals()["x"] = "bar"kullanarak Jython 2.5.2 print xiçin çıktı verir bar. Bu, maximo'da bir İsteğe Bağlı Otomasyon Betiği ile test edilmiştir .
Vaiz

37

Değişken değişkenleri kullanmak istediğinizde, muhtemelen bir sözlük kullanmak daha iyidir. Yani yazmak yerine

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

Sen yaz

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

Bu şekilde daha önce var olan değişkenlerin (güvenlik yönüdür) üzerine yanlışlıkla yazmazsınız ve farklı "ad alanlarınız" olabilir.


34

Yeni kodlayıcılar bazen şöyle kod yazarlar:

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

Kodlayıcı daha sonra adlandırılmış değişkenlerden oluşan bir yığınla bırakılır, kodlama çabası O ( m * n ) 'dir, burada m , adlandırılmış değişkenlerin sayısıdır ve n , bu değişken grubuna erişilmesi gereken sayıdır (oluşturma dahil) ). Daha zekice başlayanlar, bu satırların her birindeki tek farkın, bir kurala göre değişen ve bir döngü kullanmaya karar veren bir sayı olduğunu gözlemler. Ancak, bu değişken adlarının dinamik olarak nasıl oluşturulacağı konusunda takılırlar ve şöyle bir şey deneyebilirler:

for i in range(10):
    my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)

Yakında bunun işe yaramadığını fark ettiler.

Program keyfi değişken "adlar" gerektiriyorsa, diğer cevaplarda açıklandığı gibi sözlük en iyi seçimdir. Bununla birlikte, sadece çok sayıda değişken oluşturmaya çalışıyorsanız ve bunlara bir tamsayı dizisiyle başvurmak sakıncası yoksa, muhtemelen bir list. Bu, özellikle verileriniz günlük sıcaklık okumaları, haftalık sınav puanları veya grafik widget'ları gibi homojense doğrudur.

Bu aşağıdaki gibi monte edilebilir:

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

Bu list, bir anlayışla tek bir satırda da oluşturulabilir:

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

Her iki durumda da sonuç list, ilk öğeye erişilen my_calculator.buttons[0], bir sonraki öğeyle my_calculator.buttons[1]vb. Yerleştirilmiş olarak doldurulur . "Base" değişken adı, adı olur listve değişken tanımlayıcı ona erişmek için kullanılır.

Son olarak, diğer veri yapılarını da unutmayın set- bu bir sözlüğe benzer, ancak her "ad" ın kendisine bir değeri eklenmez. Nesnelerin bir "çantasına" ihtiyacınız varsa, bu harika bir seçim olabilir. Bunun gibi bir şey yerine:

keyword_1 = 'apple'
keyword_2 = 'banana'

if query == keyword_1 or query == keyword_2:
    print('Match.')

Buna sahip olacaksınız:

keywords = {'apple', 'banana'}
if query in keywords:
    print('Match.')

Bir kullanma listbenzer nesnelerin bir dizi, bir için setbir isteğe bağlı olarak sipariş nesnelerin torba veya bir için dictilişkili değerlerin adları için bir torba.


12

Sözlük yerine, namedtupleerişimi kolaylaştıran koleksiyon modülünden de kullanabilirsiniz .

Örneğin:

# 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

Herhangi bir nesne kullanmak istemiyorsanız, yine de setattr()geçerli modülünüzün içinde kullanabilirsiniz :

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

Bu benim için 'exec' kullanmaktan daha iyi geliyor.
fralau

__dict__Ancak bu değişkenle çalışmaz . Dinamik olarak herhangi bir genel değişken oluşturmak için genel bir mekanizma olup olmadığını merak ediyorum .
Alexey

globals()bunu yapabilir
Guillaume Lebreton

9

SimpleNamespaceSınıf ile yeni özelliklerini oluşturmak için kullanılabilir setattr, ya da alt sınıf SimpleNamespaceve yeni özellik adları (değişkenler) eklemek için Kendi işlevi oluşturun.

from types import SimpleNamespace

variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a

6

Soruyu cevaplıyorum: Bir dize adı verilen bir değişkenin değeri nasıl alınır? ve bu soruya bağlantı içeren bir kopya olarak kapatılır.

Söz konusu değişkenler bir nesne (örneğin bir sınıfın bir parçası) bir parçası olan, o zaman bazı yararlı fonksiyonlar tam olarak elde etmek için hasattr, getattrve setattr.

Yani örneğin:

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)

Sonra şunları yapabilirsiniz:

v = Variables()
v.get_var("foo")

"İnitial_variable"

v.create_new_var(v.foo,"is actually not initial")
v.initial_variable

"aslında ilk değil"


6

kullanım globals()

Sen küresel kapsama aslında atama değişkenler dinamik, örneğin, bir genel kapsamına ulaşılabilir 10 değişkenleri istersem i_1, i_2... i_10:

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

Bu, bu 10 değişkenin tümüne 'a' atayacaktır, elbette değeri dinamik olarak da değiştirebilirsiniz. Bu değişkenlerin tümüne şimdi global olarak bildirilen diğer değişkenler gibi erişilebilir:

>>> i_5
'a'

4

Bu davranışı sağlamak için globals()yerleşik yöntemi kullanmanız gerekir :

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

Fikir birliği bunun için bir sözlük kullanmaktır - diğer cevaplara bakınız. Bu, çoğu durum için iyi bir fikirdir, ancak bundan kaynaklanan birçok yön vardır:

  • çöp toplama (in-dict değişkenleri) vb. dahil olmak üzere bu sözlükten kendiniz sorumlu olacaksınız.
  • değişken değişkenler için yer veya globality yoktur, sözlüğün globallitesine bağlıdır
  • bir değişken adını yeniden adlandırmak istiyorsanız, bunu manuel olarak yapmanız gerekir
  • ancak, çok daha esneksiniz, ör.
    • mevcut değişkenlerin üzerine yazmaya karar verebilir veya ...
    • ... const değişkenlerini uygulamayı seçin
    • farklı türler için üzerine yazma konusunda bir istisna oluşturmak
    • vb.

Bununla birlikte, yukarıdaki fikirlerden bazılarını sağlayan bir değişken değişkenleri yönetici- sınıfı uyguladım . Python 2 ve 3 için çalışır.

Sen kullanmak istiyorum sınıfını böyle:

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

Yalnızca aynı türde değişkenlerin üzerine yazmaya izin vermek istiyorsanız:

myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)

İlk bakışta uzun deve ithalatı bana bunun Java olduğunu düşündürdü.
markroxor

3

Ben hem python 3.7.3 denedim, sen globals () veya vars () kullanabilirsiniz

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


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


0

Herhangi bir değişken kümesi de bir sınıfa sarılabilir. Yerleşik sözlüğe doğrudan __dict__ özniteliği aracılığıyla erişilerek çalışma zamanında sınıf örneğine "değişken" değişkenler eklenebilir.

Aşağıdaki kod, inşaat sırasında örneğine değişkenler (bu durumda öznitelikler) ekleyen Değişkenler sınıfını tanımlar. Değişken adları belirtilen bir listeden alınır (örneğin, program kodu tarafından oluşturulmuş olabilir):

# 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.