Đây là những gì đang diễn ra.
Đầu tiên, các biến toàn cục duy nhất mà Python thực sự có là các biến phạm vi mô-đun. Bạn không thể tạo ra một biến thực sự toàn cầu; tất cả những gì bạn có thể làm là tạo một biến trong một phạm vi cụ thể. (Nếu bạn tạo một biến bên trong trình thông dịch Python, và sau đó nhập các mô-đun khác, biến của bạn nằm trong phạm vi ngoài cùng và do đó toàn cầu trong phiên Python của bạn.)
Tất cả những gì bạn phải làm để tạo biến toàn cầu là chỉ cần gán cho một cái tên.
Hãy tưởng tượng một tập tin gọi là foo.py, chứa dòng này:
X = 1
Bây giờ hãy tưởng tượng bạn nhập nó.
import foo
print(foo.X) # prints 1
Tuy nhiên, giả sử bạn muốn sử dụng một trong các biến phạm vi mô-đun của bạn như một hàm bên trong chung, như trong ví dụ của bạn. Mặc định của Python là giả định rằng các biến chức năng là cục bộ. Bạn chỉ cần thêm tuyên bố global
vào chức năng của mình, trước khi bạn cố gắng sử dụng toàn cục.
def initDB(name):
global __DBNAME__ # add this line!
if __DBNAME__ is None: # see notes below; explicit test for None
__DBNAME__ = name
else:
raise RuntimeError("Database name has already been set.")
Bằng cách này, ví dụ này, if not __DBNAME__
kiểm tra đơn giản là đủ, bởi vì bất kỳ chuỗi giá trị khác hơn là một chuỗi rỗng sẽ đánh giá đúng, vì vậy bất kỳ tên cơ sở dữ liệu thực tế sẽ đánh giá đúng. Nhưng đối với các biến có thể chứa giá trị số có thể là 0, bạn không thể chỉ nói if not variablename
; trong trường hợp đó, bạn nên kiểm tra rõ ràng None
bằng toán tử is
. Tôi đã sửa đổi ví dụ để thêm bài kiểm tra None
rõ ràng. Các thử nghiệm rõ ràng cho None
là không bao giờ sai, vì vậy tôi mặc định để sử dụng nó.
Cuối cùng, như những người khác đã lưu ý trên trang này, hai dấu gạch dưới hàng đầu báo hiệu cho Python rằng bạn muốn biến là "riêng tư" đối với mô-đun. Nếu bạn đã từng làm một import * from mymodule
, Python sẽ không nhập tên có hai dấu gạch dưới hàng đầu vào không gian tên của bạn. Nhưng nếu bạn chỉ cần thực hiện một đơn giản import mymodule
và sau đó nói dir(mymodule)
bạn sẽ thấy các biến "riêng tư" trong danh sách và nếu bạn tham chiếu rõ ràng mymodule.__DBNAME__
Python sẽ không quan tâm, nó sẽ chỉ cho phép bạn tham chiếu đến nó. Các dấu gạch dưới hàng đầu kép là một đầu mối chính cho người dùng của mô-đun của bạn mà bạn không muốn họ rebinding tên đó cho một số giá trị của riêng mình.
Nó được coi là thực hành tốt nhất trong Python không làm import *
, nhưng để giảm thiểu khớp nối và tối đa hóa nhân chứng bằng cách sử dụng mymodule.something
hoặc bằng cách nhập một cách rõ ràng như from mymodule import something
.
EDIT: Nếu vì một lý do nào đó, bạn cần phải làm điều gì đó như thế này trong phiên bản cũ của Python không có từ khóa global
, có cách giải quyết dễ dàng. Thay vì đặt trực tiếp biến toàn cục mô-đun, hãy sử dụng loại có thể thay đổi ở cấp mô-đun toàn cầu và lưu trữ các giá trị của bạn bên trong nó.
Trong các chức năng của bạn, tên biến toàn cục sẽ là chỉ đọc; bạn sẽ không thể rebind tên biến toàn cầu thực tế. (Nếu bạn gán cho tên biến đó bên trong hàm của bạn, nó sẽ chỉ ảnh hưởng đến tên biến cục bộ bên trong hàm.) Nhưng bạn có thể sử dụng tên biến cục bộ đó để truy cập đối tượng toàn cục thực và lưu trữ dữ liệu bên trong nó.
Bạn có thể sử dụng một list
nhưng mã của bạn sẽ xấu xí:
__DBNAME__ = [None] # use length-1 list as a mutable
# later, in code:
if __DBNAME__[0] is None:
__DBNAME__[0] = name
Một dict
là tốt hơn. Tuy nhiên, thuận tiện nhất là một cá thể của lớp, và bạn chỉ có thể sử dụng một lớp tầm thường: (. Bạn không thực sự cần phải tận dụng biến tên cơ sở dữ liệu)
class Box:
pass
__m = Box() # m will contain all module-level values
__m.dbname = None # database name global in module
# later, in code:
if __m.dbname is None:
__m.dbname = name
Tôi thích đường cú pháp của chỉ sử dụng __m.dbname
thay vì __m["DBNAME"]
; nó có vẻ là giải pháp thuận tiện nhất theo ý kiến của tôi. Nhưng giải pháp dict
cũng hoạt động tốt.
Với dict
bạn có thể sử dụng bất kỳ giá trị băm nào làm khóa, nhưng khi bạn hài lòng với tên là số nhận dạng hợp lệ, bạn có thể sử dụng một lớp tầm thường như Box
ở trên.
Nhờ mọi người vì câu trả lời tuyệt vời! Đã học nhiều về Python hơn tôi mong đợi. – daveslab