เมื่อใดก็ตามที่ Python interpreter อ่านไฟล์ต้นฉบับมันจะทำสองสิ่ง:
เรามาดูกันว่ามันใช้งานอย่างไรและเกี่ยวข้องกับคำถามของคุณอย่างไรเกี่ยวกับการ__name__
ตรวจสอบที่เราเห็นในสคริปต์ Python
ตัวอย่างโค้ด
ลองใช้ตัวอย่างรหัสที่แตกต่างกันเล็กน้อยเพื่อสำรวจว่าการนำเข้าและสคริปต์ทำงานอย่างไร 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")
ตัวแปรพิเศษ
เมื่อ Python interpeter อ่านไฟล์ต้นฉบับมันจะกำหนดตัวแปรพิเศษบางอย่างก่อน ในกรณีนี้เราใส่ใจ__name__
ตัวแปร
เมื่อโมดูลของคุณเป็นโปรแกรมหลัก
หากคุณใช้โมดูล (ไฟล์ต้นฉบับ) เป็นโปรแกรมหลักเช่น
python foo.py
ล่ามจะกำหนดสตริงฮาร์ดโค้ด"__main__"
ให้กับ__name__
ตัวแปรเช่น
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
เมื่อโมดูลของคุณถูกอิมพอร์ตโดยโมดูลอื่น
ในทางกลับกันสมมติว่าโมดูลอื่นเป็นโปรแกรมหลักและนำเข้าโมดูลของคุณ ซึ่งหมายความว่ามีคำสั่งเช่นนี้ในโปรแกรมหลักหรือในโมดูลอื่น ๆ ที่โปรแกรมหลักนำเข้า:
# Suppose this is in some other main program.
import foo
ล่ามจะค้นหาfoo.py
ไฟล์ของคุณ(พร้อมกับค้นหาตัวแปรอื่น ๆ สองสามตัว) และก่อนที่จะดำเนินการโมดูลนั้นมันจะกำหนดชื่อ"foo"
จากคำสั่งนำเข้าให้กับ__name__
ตัวแปรเช่น
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
การดำเนินการของโมดูล
หลังจากตั้งค่าตัวแปรพิเศษแล้วล่ามจะเรียกใช้งานรหัสทั้งหมดในโมดูลหนึ่งคำสั่งพร้อมกัน คุณอาจต้องการเปิดหน้าต่างอื่นที่ด้านข้างพร้อมตัวอย่างรหัสเพื่อให้คุณสามารถติดตามพร้อมกับคำอธิบายนี้
เสมอ
มันพิมพ์สตริง"before import"
(โดยไม่ใส่เครื่องหมายอัญประกาศ)
มันโหลดโมดูลและกำหนดให้กับตัวแปรที่เรียกว่าmath
math
นี่เทียบเท่ากับการแทนที่import math
ด้วยสิ่งต่อไปนี้ (โปรดทราบว่า__import__
เป็นฟังก์ชันระดับต่ำใน Python ที่ใช้สตริงและทริกเกอร์การนำเข้าจริง):
# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
"before functionA"
มันพิมพ์สตริง
มันดำเนินการบล็อกการสร้างวัตถุฟังก์ชั่นแล้วกำหนดว่าฟังก์ชันวัตถุให้กับตัวแปรที่เรียกว่าdef
functionA
"before functionB"
มันพิมพ์สตริง
มันรันที่สองบล็อกสร้างวัตถุฟังก์ชั่นอื่นแล้วกำหนดให้กับตัวแปรที่เรียกว่าdef
functionB
"before __name__ guard"
มันพิมพ์สตริง
เมื่อโมดูลของคุณเป็นโปรแกรมหลักเท่านั้น
- ถ้าโมดูลของคุณเป็นโปรแกรมหลักแล้วก็จะเห็นว่า
__name__
ถูกกำหนดแน่นอน"__main__"
และจะเรียกทั้งสองฟังก์ชั่นการพิมพ์สตริงและ"Function A"
"Function B 10.0"
เมื่อโมดูลของคุณถูกอิมพอร์ตโดยโมดูลอื่นเท่านั้น
- ( แทน ) หากโมดูลของคุณไม่ได้เป็นโปรแกรมหลัก แต่ถูกนำเข้าโดยอีกโมดูลหนึ่ง
__name__
จะ"foo"
ไม่ใช่"__main__"
และจะข้ามเนื้อหาของif
คำสั่งนั้น
เสมอ
- มันจะพิมพ์สตริง
"after __name__ guard"
ในทั้งสองสถานการณ์
สรุป
โดยสรุปนี่คือสิ่งที่จะพิมพ์ในสองกรณี:
# 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
ทำไมมันทำงานด้วยวิธีนี้
คุณอาจสงสัยว่าทำไมทุกคนต้องการสิ่งนี้ บางครั้งคุณต้องการเขียน.py
ไฟล์ที่สามารถใช้งานได้โดยโปรแกรมอื่น ๆ และ / หรือโมดูลเป็นโมดูลและสามารถเรียกใช้เป็นโปรแกรมหลักได้ ตัวอย่าง:
โมดูลของคุณเป็นไลบรารี แต่คุณต้องการมีโหมดสคริปต์ที่ใช้ทดสอบหน่วยหรือสาธิต
โมดูลของคุณใช้เป็นโปรแกรมหลักเท่านั้น แต่มีการทดสอบหน่วยและกรอบการทดสอบใช้งานได้โดยการนำเข้า.py
ไฟล์เช่นสคริปต์ของคุณและใช้งานฟังก์ชั่นทดสอบพิเศษ คุณไม่ต้องการให้ลองเรียกใช้สคริปต์เพียงเพราะมันกำลังนำเข้าโมดูล
โมดูลของคุณส่วนใหญ่จะใช้เป็นโปรแกรมหลัก แต่ก็ยังมี API ที่เป็นมิตรกับโปรแกรมเมอร์สำหรับผู้ใช้ขั้นสูง
นอกเหนือจากตัวอย่างเหล่านั้นมันเป็นเรื่องสวยงามที่การเรียกใช้สคริปต์ใน Python เพียงแค่ตั้งค่าตัวแปรเวทย์มนตร์ไม่กี่ตัวและนำเข้าสคริปต์ "การทำงาน" สคริปต์เป็นผลข้างเคียงของการนำเข้าโมดูลของสคริปต์
อาหารสมอง
# 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")
- ตอนนี้ให้คิดว่าจะเกิดอะไรขึ้นถ้าคุณลบ
__name__
เช็คอินออก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")
- จะทำอย่างไรเมื่อใช้เป็นสคริปต์? เมื่อนำเข้าเป็นโมดูล
# 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__":
สภาพถูกเลิกบล็อก / จำหน่ายแล้วเท่าที่หลาม 3 หรือไม่? ฉันพบข้อมูลบางอย่างที่ระบุว่า