Bất cứ khi nào trình thông dịch Python đọc một tệp nguồn, nó sẽ thực hiện hai điều:
nó đặt một vài biến đặc biệt như __name__
, và sau đó
nó thực thi tất cả các mã được tìm thấy trong tập tin.
Hãy xem cách nó hoạt động và nó liên quan đến câu hỏi của bạn về __name__
kiểm tra mà chúng ta luôn thấy trong các tập lệnh Python.
Mẫu mã
Chúng ta hãy sử dụng một mẫu mã hơi khác nhau để khám phá cách nhập và tập lệnh hoạt động. Giả sử sau đây là trong một tập tin được gọi là foo.py
.
# Suppose this is foo.py.
print("before import")
import math
print("before functionA")
def functionA():
print("Function A")
print("before functionB")
def functionB():
print("Function B {}".format(math.sqrt(100)))
print("before __name__ guard")
if __name__ == '__main__':
functionA()
functionB()
print("after __name__ guard")
Biến đặc biệt
Khi trình thông dịch Python đọc một tệp nguồn, đầu tiên nó xác định một vài biến đặc biệt. Trong trường hợp này, chúng tôi quan tâm đến các __name__
biến.
Khi mô-đun của bạn là chương trình chính
Nếu bạn đang chạy mô-đun của mình (tệp nguồn) làm chương trình chính, vd
python foo.py
trình thông dịch sẽ gán chuỗi mã hóa cứng "__main__"
cho __name__
biến, tức là
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Khi mô-đun của bạn được nhập bởi người khác
Mặt khác, giả sử một số mô-đun khác là chương trình chính và nó nhập mô-đun của bạn. Điều này có nghĩa là có một tuyên bố như thế này trong chương trình chính hoặc trong một số mô-đun khác, chương trình chính nhập khẩu:
# Suppose this is in some other main program.
import foo
Trình thông dịch sẽ tìm kiếm foo.py
tệp của bạn (cùng với tìm kiếm một vài biến thể khác) và trước khi thực hiện mô-đun đó, nó sẽ gán tên "foo"
từ câu lệnh nhập cho __name__
biến, nghĩa là
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Thực thi mã của mô-đun
Sau khi các biến đặc biệt được thiết lập, trình thông dịch sẽ thực thi tất cả mã trong mô-đun, mỗi lần một câu lệnh. Bạn có thể muốn mở một cửa sổ khác ở bên cạnh với mẫu mã để bạn có thể làm theo cùng với lời giải thích này.
Luôn luôn
Nó in chuỗi "before import"
(không có dấu ngoặc kép).
Nó tải math
mô-đun và gán nó cho một biến được gọi là math
. Điều này tương đương với việc thay thế import math
bằng cách sau (lưu ý rằng đó __import__
là một hàm cấp thấp trong Python lấy một chuỗi và kích hoạt nhập thực tế):
# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
Nó in chuỗi "before functionA"
.
Nó thực thi def
khối, tạo một đối tượng hàm, sau đó gán đối tượng hàm đó cho một biến được gọi functionA
.
Nó in chuỗi "before functionB"
.
Nó thực thi def
khối thứ hai , tạo một đối tượng hàm khác, sau đó gán nó cho một biến được gọi functionB
.
Nó in chuỗi "before __name__ guard"
.
Chỉ khi mô-đun của bạn là chương trình chính
- Nếu mô-đun của bạn là chương trình chính, thì nó sẽ thấy nó
__name__
thực sự được đặt thành "__main__"
và nó gọi hai hàm, in chuỗi "Function A"
và "Function B 10.0"
.
Chỉ khi mô-đun của bạn được nhập bởi người khác
- ( thay vào đó ) Nếu mô-đun của bạn không phải là chương trình chính nhưng được nhập bởi một chương trình khác, thì
__name__
sẽ "foo"
không "__main__"
, và nó sẽ bỏ qua phần thân của if
câu lệnh.
Luôn luôn
- Nó sẽ in chuỗi
"after __name__ guard"
trong cả hai tình huống.
Tóm lược
Tóm lại, đây là những gì sẽ được in trong hai trường hợp:
# What gets printed if foo is the main program
before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before functionA
before functionB
before __name__ guard
after __name__ guard
Tại sao nó hoạt động theo cách này?
Bạn có thể tự nhiên tự hỏi tại sao bất cứ ai sẽ muốn điều này. Chà, đôi khi bạn muốn viết một .py
tệp có thể được sử dụng bởi các chương trình và / hoặc mô-đun khác như một mô-đun, và cũng có thể được chạy như chính chương trình chính. Ví dụ:
Mô-đun của bạn là một thư viện, nhưng bạn muốn có một chế độ tập lệnh nơi nó chạy một số bài kiểm tra đơn vị hoặc bản demo.
Mô-đun của bạn chỉ được sử dụng như một chương trình chính, nhưng nó có một số thử nghiệm đơn vị và khung kiểm tra hoạt động bằng cách nhập .py
các tệp như tập lệnh của bạn và chạy các chức năng kiểm tra đặc biệt. Bạn không muốn nó thử chạy tập lệnh chỉ vì nó đang nhập mô-đun.
Mô-đun của bạn chủ yếu được sử dụng như một chương trình chính, nhưng nó cũng cung cấp API thân thiện với lập trình viên cho người dùng nâng cao.
Ngoài những ví dụ đó, thật thú vị khi chạy tập lệnh trong Python chỉ là thiết lập một vài biến ma thuật và nhập tập lệnh. "Chạy" tập lệnh là một tác dụng phụ của việc nhập mô-đun của tập lệnh.
Thức ăn cho suy nghĩ
Câu hỏi: Tôi có thể có nhiều __name__
khối kiểm tra không? Trả lời: thật lạ khi làm như vậy, nhưng ngôn ngữ sẽ không ngăn bạn.
Giả sử sau đây là trong foo2.py
. Điều gì xảy ra nếu bạn nói python foo2.py
trên dòng lệnh? Tại sao?
# Suppose this is foo2.py.
def functionA():
print("a1")
from foo2 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
if __name__ == "__main__":
print("m1")
functionA()
print("m2")
print("t2")
- Bây giờ, hãy tìm hiểu điều gì sẽ xảy ra nếu bạn xóa
__name__
đăng ký foo3.py
:
# Suppose this is foo3.py.
def functionA():
print("a1")
from foo3 import functionB
print("a2")
functionB()
print("a3")
def functionB():
print("b")
print("t1")
print("m1")
functionA()
print("m2")
print("t2")
- Điều này sẽ làm gì khi được sử dụng như một kịch bản? Khi nhập khẩu dưới dạng mô-đun?
# Suppose this is in foo4.py
__name__ = "__main__"
def bar():
print("bar")
print("before __name__ guard")
if __name__ == "__main__":
bar()
print("after __name__ guard")
if __name__ == "__main__":
tình trạng khối được tán / lỗi thời như xa như Python 3? Tôi đã tìm thấy một số thông tin nói rằng.