Bagaimana cara membuat variabel jumlah variabel?


364

Bagaimana cara menyelesaikan variabel variabel dalam Python?

Berikut ini adalah entri manual elaboratif, misalnya: Variabel variabel

Saya telah mendengar ini adalah ide yang buruk secara umum, dan itu adalah lubang keamanan di Python. Benarkah?


39
aspek pemeliharaan dan debug yang menyebabkan kengerian. Bayangkan mencoba mencari tahu di mana variabel 'foo' berubah ketika tidak ada tempat dalam kode Anda di mana Anda benar-benar mengubah 'foo'. Bayangkan lebih jauh bahwa itu adalah kode orang lain yang harus Anda pertahankan ... OK, Anda bisa pergi ke tempat bahagia Anda sekarang.
glenn jackman

4
Perangkap lebih lanjut yang belum disebutkan sejauh ini adalah jika variabel yang dibuat secara dinamis memiliki nama yang sama dengan variabel yang digunakan dalam logika Anda. Anda pada dasarnya membuka perangkat lunak Anda sebagai sandera terhadap input yang diberikan.
holdenweb

Semua respons di sini menganggap Anda memiliki akses ke variabel dasar yang ingin Anda akses secara dinamis berdasarkan nama, yang tidak selalu demikian. Saya pikir pendekatan paling umum untuk mereproduksi contoh perilaku dalam PHP adalah dengan menggunakan eval () seperti ini: var_name = 'foo'; bar = 5; output = eval (var_name)
Luis Vazquez

1
Anda dapat memodifikasi variabel global dan lokal Anda dengan mengakses kamus yang mendasari mereka; itu adalah ide yang mengerikan dari perspektif pemeliharaan ... tetapi dapat dilakukan melalui global (). pembaruan () dan penduduk setempat (). pembaruan () (atau dengan menyimpan referensi dikt dari salah satu dari mereka dan menggunakannya seperti kamus lain ). TIDAK DIANJURKAN ... tetapi Anda harus tahu bahwa itu mungkin.
Jim Dennis

(Saya menambahkan komentar ini karena pertanyaan yang serupa, lebih khusus meminta manipulasi semacam ini ditutup dengan sebuah pointer ke pertanyaan "cukup dekat" ini. Saya ingin mereka yang mengikuti pertanyaan tertutup untuk mendapatkan jawaban mereka).
Jim Dennis

Jawaban:


297

Anda dapat menggunakan kamus untuk mencapai ini. Kamus adalah penyimpan kunci dan nilai.

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

Anda dapat menggunakan nama kunci variabel untuk mencapai efek variabel variabel tanpa risiko keamanan.

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

Untuk kasus-kasus di mana Anda berpikir untuk melakukan sesuatu seperti

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

daftar mungkin lebih tepat daripada dict. Daftar mewakili urutan objek yang diurutkan, dengan indeks integer:

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

Untuk urutan memerintahkan, daftar lebih mudah daripada dicts dengan kunci integer, karena daftar mendukung iterasi agar indeks, mengiris , appenddan operasi lainnya yang mengharuskan manajemen kunci canggung dengan dict.


88

Gunakan getattrfungsi bawaan untuk mendapatkan atribut pada objek dengan nama. Ubah nama sesuai kebutuhan.

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

70

Itu bukan ide yang bagus. Jika Anda mengakses variabel global yang dapat Anda gunakan globals().

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

Jika Anda ingin mengakses variabel dalam lingkup lokal yang dapat Anda gunakan locals(), tetapi Anda tidak dapat menetapkan nilai ke dikt yang dikembalikan.

Solusi yang lebih baik adalah dengan menggunakan getattratau menyimpan variabel Anda dalam kamus dan kemudian mengaksesnya dengan nama.


lokal (). perbaruan ({'new_local_var': 'beberapa nilai lokal'}) berfungsi dengan baik bagi saya dengan Python 3.7.6; jadi saya tidak yakin apa yang Anda maksud ketika Anda mengatakan Anda tidak dapat menetapkan nilai melalui itu.
Jim Dennis

Diberikan x = "foo"dan locals()["x"] = "bar"digunakan print xmemberikan output baruntuk Jython 2.5.2. Ini diuji dengan Script On Demand Automation dalam maximo .
Pengkhotbah

37

Kapan pun Anda ingin menggunakan variabel variabel, mungkin lebih baik menggunakan kamus. Jadi alih-alih menulis

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

Anda menulis

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

Dengan cara ini Anda tidak akan secara tidak sengaja menimpa variabel yang sudah ada sebelumnya (yang merupakan aspek keamanan) dan Anda dapat memiliki "ruang nama" yang berbeda.


34

Coders baru terkadang menulis kode seperti ini:

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

Coder kemudian dibiarkan dengan tumpukan variabel bernama, dengan upaya pengkodean O ( m * n ), di mana m adalah jumlah variabel bernama dan n adalah berapa kali kelompok variabel perlu diakses (termasuk pembuatan ). Pemula yang lebih cerdik mengamati bahwa satu-satunya perbedaan dalam setiap baris tersebut adalah angka yang berubah berdasarkan aturan, dan memutuskan untuk menggunakan loop. Namun, mereka terjebak pada cara membuat nama variabel secara dinamis, dan dapat mencoba sesuatu seperti ini:

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

Mereka segera menemukan bahwa ini tidak berhasil.

Jika program membutuhkan "nama" variabel arbitrer, kamus adalah pilihan terbaik, seperti dijelaskan dalam jawaban lain. Namun, jika Anda hanya mencoba membuat banyak variabel dan Anda tidak keberatan merujuknya dengan urutan bilangan bulat, Anda mungkin mencari a list. Ini terutama benar jika data Anda homogen, seperti pembacaan suhu harian, skor kuis mingguan, atau kisi-kisi widget grafis.

Ini dapat dirakit sebagai berikut:

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

Ini listjuga dapat dibuat dalam satu baris dengan pemahaman:

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

Hasil dalam kedua kasus adalah populasi list, dengan elemen pertama diakses dengan my_calculator.buttons[0], berikutnya dengan my_calculator.buttons[1], dan seterusnya. Nama variabel "dasar" menjadi nama listdan pengidentifikasi yang bervariasi digunakan untuk mengaksesnya.

Akhirnya, jangan lupa struktur data lain, seperti set- ini mirip dengan kamus, kecuali bahwa setiap "nama" tidak memiliki nilai yang melekat padanya. Jika Anda hanya membutuhkan "tas" benda, ini bisa menjadi pilihan yang bagus. Alih-alih sesuatu seperti ini:

keyword_1 = 'apple'
keyword_2 = 'banana'

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

Anda akan memiliki ini:

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

Gunakan listuntuk urutan objek yang serupa, setuntuk tas yang dipesan secara sewenang-wenang, atau dictuntuk kantong nama dengan nilai terkait.


12

Alih-alih kamus Anda juga dapat menggunakan namedtupledari modul koleksi, yang membuat akses lebih mudah.

Sebagai contoh:

# 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

Jika Anda tidak ingin menggunakan objek apa pun, Anda masih bisa menggunakan setattr()di dalam modul Anda saat ini:

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

Bagi saya ini terdengar lebih baik daripada menggunakan 'exec'.
fralau

Namun ini tidak bekerja dengan __dict__variabel. Aku ingin tahu apakah ada mekanisme umum untuk membuat setiap variabel global secara dinamis.
Alexey

globals()dapat melakukan ini
Guillaume Lebreton

9

The SimpleNamespacekelas dapat digunakan untuk membuat atribut baru dengan setattr, atau subclass SimpleNamespacedan membuat fungsi sendiri untuk menambahkan nama atribut baru (variabel).

from types import SimpleNamespace

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

6

Saya menjawab pertanyaan: Bagaimana cara mendapatkan nilai dari variabel yang diberi nama dalam sebuah string? yang ditutup sebagai duplikat dengan tautan ke pertanyaan ini.

Jika variabel yang dimaksud adalah bagian dari sebuah objek (bagian dari kelas misalnya) maka beberapa fungsi yang berguna untuk mencapai hal itu adalah hasattr, getattr, dan setattr.

Jadi misalnya Anda dapat memiliki:

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)

Maka Anda dapat melakukan:

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

"initial_variable"

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

"sebenarnya bukan inisial"


5

Menggunakan globals()

Anda sebenarnya dapat menetapkan variabel ke cakupan global secara dinamis, misalnya, jika Anda ingin 10 variabel yang dapat diakses pada cakupan global i_1, i_2... i_10:

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

Ini akan menetapkan 'a' untuk semua 10 variabel ini, tentu saja Anda dapat mengubah nilai secara dinamis juga. Semua variabel ini dapat diakses sekarang seperti variabel lain yang dideklarasikan secara global:

>>> i_5
'a'

4

Anda harus menggunakan globals()metode bawaan untuk mencapai perilaku itu:

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

Konsensus adalah menggunakan kamus untuk ini - lihat jawaban lain. Ini adalah ide yang bagus untuk sebagian besar kasus, namun ada banyak aspek yang timbul dari ini:

  • Anda sendiri yang akan bertanggung jawab atas kamus ini, termasuk pengumpulan sampah (dari variabel in-dict) dll.
  • tidak ada lokalitas atau globalitas untuk variabel variabel, itu tergantung pada globalitas kamus
  • jika Anda ingin mengganti nama nama variabel, Anda harus melakukannya secara manual
  • Namun, Anda jauh lebih fleksibel, misalnya
    • Anda dapat memutuskan untuk menimpa variabel yang ada atau ...
    • ... pilih untuk mengimplementasikan variabel const
    • untuk meningkatkan pengecualian pada penulisan ulang untuk berbagai jenis
    • dll.

Yang mengatakan, saya telah mengimplementasikan variabel variabel manajer- kelas yang menyediakan beberapa ide di atas. Ini berfungsi untuk python 2 dan 3.

Anda akan menggunakan kelas seperti ini:

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

Jika Anda ingin mengizinkan penimpaan variabel dengan tipe yang sama saja:

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

Sepintas impor camelised lama membuat saya berpikir ini adalah Jawa.
markroxor

3

Saya telah mencoba keduanya dengan python 3.7.3, Anda dapat menggunakan globals () atau 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'


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


0

Setiap set variabel juga dapat dibungkus dalam suatu kelas. Variabel "Variabel" dapat ditambahkan ke instance kelas selama runtime dengan secara langsung mengakses kamus bawaan melalui atribut __dict__.

Kode berikut mendefinisikan kelas Variabel, yang menambahkan variabel (dalam hal ini atribut) ke instance-nya selama konstruksi. Nama variabel diambil dari daftar yang ditentukan (yang, misalnya, bisa dihasilkan oleh kode program):

# 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.