Làm cách nào để thực hiện các biến biến trong Python?
Dưới đây là một mục thủ công chi tiết: Ví dụ: Biến biến
Tôi đã nghe nói rằng đây là một ý tưởng tồi nói chung và nó là một lỗ hổng bảo mật trong Python. Điều đó có đúng không?
Làm cách nào để thực hiện các biến biến trong Python?
Dưới đây là một mục thủ công chi tiết: Ví dụ: Biến biến
Tôi đã nghe nói rằng đây là một ý tưởng tồi nói chung và nó là một lỗ hổng bảo mật trong Python. Điều đó có đúng không?
Câu trả lời:
Bạn có thể sử dụng từ điển để thực hiện điều này. Từ điển là cửa hàng của các khóa và giá trị.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2
Bạn có thể sử dụng tên khóa biến để đạt được hiệu quả của biến biến mà không có rủi ro bảo mật.
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
Đối với trường hợp bạn đang nghĩ làm một cái gì đó như
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
một danh sách có thể phù hợp hơn một lệnh. Một danh sách đại diện cho một chuỗi các đối tượng được sắp xếp, với các chỉ số nguyên:
lst = ['foo', 'bar', 'baz']
print(lst[1]) # prints bar, because indices start at 0
lst.append('potatoes') # lst is now ['foo', 'bar', 'baz', 'potatoes']
Đối với chuỗi lệnh, danh sách được thuận tiện hơn dicts với các phím số nguyên, bởi vì danh sách hỗ trợ lặp để chỉ mục, cắt , append
và các hoạt động khác mà có thể yêu cầu quản lý chủ chốt vụng về với một dict.
Nó không phải là một ý tưởng tốt. Nếu bạn đang truy cập một biến toàn cục, bạn có thể sử dụng globals()
.
>>> a = 10
>>> globals()['a']
10
Nếu bạn muốn truy cập một biến trong phạm vi cục bộ bạn có thể sử dụng locals()
, nhưng bạn không thể gán giá trị cho dict được trả về.
Một giải pháp tốt hơn là sử dụng getattr
hoặc lưu trữ các biến của bạn trong từ điển và sau đó truy cập chúng theo tên.
x = "foo"
và locals()["x"] = "bar"
sử dụng print x
cung cấp đầu ra bar
cho Jython 2.5.2. Điều này đã được thử nghiệm với Tập lệnh tự động hóa theo yêu cầu trong maximo .
Bất cứ khi nào bạn muốn sử dụng các biến số, có lẽ tốt hơn là sử dụng từ điển. Vì vậy, thay vì viết
$foo = "bar"
$$foo = "baz"
bạn viết
mydict = {}
foo = "bar"
mydict[foo] = "baz"
Bằng cách này, bạn sẽ không vô tình ghi đè lên các biến hiện có trước đây (đó là khía cạnh bảo mật) và bạn có thể có các "không gian tên" khác nhau.
Các lập trình viên mới đôi khi viết mã như thế này:
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)
...
Bộ mã hóa sau đó được để lại một đống các biến được đặt tên, với nỗ lực mã hóa là O ( m * n ), trong đó m là số lượng biến được đặt tên và n là số lần mà nhóm biến cần truy cập (bao gồm cả việc tạo ). Người mới bắt đầu sắc sảo hơn nhận thấy rằng sự khác biệt duy nhất trong mỗi dòng đó là một số thay đổi dựa trên quy tắc và quyết định sử dụng một vòng lặp. Tuy nhiên, họ bị mắc kẹt về cách tự động tạo các tên biến đó và có thể thử một cái gì đó như thế này:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Họ sớm thấy rằng điều này không hoạt động.
Nếu chương trình yêu cầu "tên" tùy ý, thì từ điển là lựa chọn tốt nhất, như được giải thích trong các câu trả lời khác. Tuy nhiên, nếu bạn chỉ đơn giản là cố gắng tạo nhiều biến và bạn không ngại đề cập đến chúng bằng một chuỗi số nguyên, có lẽ bạn đang tìm kiếm một list
. Điều này đặc biệt đúng nếu dữ liệu của bạn là đồng nhất, chẳng hạn như đọc nhiệt độ hàng ngày, điểm kiểm tra hàng tuần hoặc một lưới các vật dụng đồ họa.
Điều này có thể được lắp ráp như sau:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Điều này list
cũng có thể được tạo ra trong một dòng với sự hiểu biết:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Kết quả trong cả hai trường hợp là một quần thể list
, với phần tử đầu tiên được truy cập my_calculator.buttons[0]
, phần tiếp theo my_calculator.buttons[1]
, v.v. Tên biến "cơ sở" trở thành tên của list
và định danh khác nhau được sử dụng để truy cập nó.
Cuối cùng, đừng quên các cấu trúc dữ liệu khác, chẳng hạn như set
- điều này tương tự như từ điển, ngoại trừ mỗi "tên" không có giá trị kèm theo. Nếu bạn chỉ cần một "túi" đồ vật, đây có thể là một lựa chọn tuyệt vời. Thay vì một cái gì đó như thế này:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
Bạn sẽ có điều này:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Sử dụng một list
chuỗi cho các đối tượng tương tự, một set
túi đối tượng được sắp xếp tùy ý hoặc dict
một túi tên có giá trị liên quan.
Thay vì từ điển, bạn cũng có thể sử dụng namedtuple
từ mô-đun bộ sưu tập, giúp truy cập dễ dàng hơn.
Ví dụ:
# 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)
Nếu bạn không muốn sử dụng bất kỳ đối tượng nào, bạn vẫn có thể sử dụng setattr()
bên trong mô-đun hiện tại của mình:
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__
biến tuy nhiên. Tôi tự hỏi nếu có một cơ chế chung để tạo ra bất kỳ biến toàn cầu nào một cách linh hoạt.
globals()
có thể làm điều này
Các SimpleNamespace
lớp có thể được sử dụng để tạo các thuộc tính mới với setattr
, hoặc phân lớp SimpleNamespace
và tạo chức năng của riêng bạn để thêm tên thuộc tính mới (biến).
from types import SimpleNamespace
variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
Tôi đang trả lời câu hỏi: Làm thế nào để lấy giá trị của biến được đặt tên trong chuỗi? được đóng lại như một bản sao với một liên kết đến câu hỏi này.
Nếu các biến trong câu hỏi là một phần của một đối tượng (một phần của một lớp chẳng hạn) sau đó một số chức năng hữu ích để đạt được chính xác điều đó là hasattr
, getattr
vàsetattr
.
Vì vậy, ví dụ bạn có thể có:
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)
Sau đó, bạn có thể làm:
v = Variables()
v.get_var("foo")
"init_variable"
v.create_new_var(v.foo,"is actually not initial")
v.initial_variable
"thực sự không phải là ban đầu"
Sử dụng globals()
Ví dụ, bạn thực sự có thể gán biến cho phạm vi toàn cầu một cách linh hoạt, nếu bạn muốn 10 biến có thể được truy cập trên phạm vi toàn cầu i_1
, i_2
... i_10
:
for i in range(10):
globals()['i_{}'.format(i)] = 'a'
Điều này sẽ gán 'a' cho tất cả 10 biến này, tất nhiên bạn cũng có thể thay đổi giá trị một cách linh hoạt. Tất cả các biến này có thể được truy cập ngay bây giờ giống như các biến được khai báo toàn cầu khác:
>>> i_5
'a'
Bạn phải sử dụng globals()
phương thức được xây dựng để đạt được hành vi đó:
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
Sự đồng thuận là sử dụng một từ điển cho việc này - xem các câu trả lời khác. Đây là một ý tưởng tốt cho hầu hết các trường hợp, tuy nhiên, có nhiều khía cạnh phát sinh từ điều này:
Điều đó nói rằng, tôi đã triển khai một trình quản lý biến biến - lớp cung cấp một số ý tưởng trên. Nó hoạt động cho python 2 và 3.
Bạn sẽ sử dụng lớp như thế này:
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'])
Nếu bạn chỉ muốn cho phép ghi đè các biến có cùng loại:
myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
Tôi đã thử cả trong python 3.7.3, bạn có thể sử dụng cả globalals () hoặc 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'
Bất kỳ tập hợp các biến cũng có thể được gói trong một lớp. Các biến "Biến" có thể được thêm vào thể hiện của lớp trong thời gian chạy bằng cách truy cập trực tiếp vào từ điển tích hợp thông qua thuộc tính __dict__.
Đoạn mã sau định nghĩa lớp Biến, thêm các biến (trong trường hợp này là thuộc tính) vào thể hiện của nó trong quá trình xây dựng. Tên biến được lấy từ một danh sách cụ thể (ví dụ, có thể được tạo bởi mã chương trình):
# 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