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?
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?
Jawaban:
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 , append
dan operasi lainnya yang mengharuskan manajemen kunci canggung dengan dict.
Gunakan getattr
fungsi bawaan untuk mendapatkan atribut pada objek dengan nama. Ubah nama sesuai kebutuhan.
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
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 getattr
atau menyimpan variabel Anda dalam kamus dan kemudian mengaksesnya dengan nama.
x = "foo"
dan locals()["x"] = "bar"
digunakan print x
memberikan output bar
untuk Jython 2.5.2. Ini diuji dengan Script On Demand Automation dalam maximo .
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.
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 list
juga 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 list
dan 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 list
untuk urutan objek yang serupa, set
untuk tas yang dipesan secara sewenang-wenang, atau dict
untuk kantong nama dengan nilai terkait.
Alih-alih kamus Anda juga dapat menggunakan namedtuple
dari 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)
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
__dict__
variabel. Aku ingin tahu apakah ada mekanisme umum untuk membuat setiap variabel global secara dinamis.
globals()
dapat melakukan ini
The SimpleNamespace
kelas dapat digunakan untuk membuat atribut baru dengan setattr
, atau subclass SimpleNamespace
dan 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
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"
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'
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
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:
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)
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'
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