จะทำอย่างไรถ้า __name__ ==“ __main__”: ทำอย่างไร


6062

รับรหัสต่อไปนี้สิ่งที่จะif __name__ == "__main__":ทำอย่างไร

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

ได้if __name__ == "__main__":สภาพถูกเลิกบล็อก / จำหน่ายแล้วเท่าที่หลาม 3 หรือไม่? ฉันพบข้อมูลบางอย่างที่ระบุว่า
carloswm85

1
@ carloswm85 นั่นไม่เป็นความจริง
Giorgos Myrianthous

คำตอบ:


6641

เมื่อใดก็ตามที่ Python interpreter อ่านไฟล์ต้นฉบับมันจะทำสองสิ่ง:

  • มันตั้งค่าตัวแปรพิเศษบางอย่างเช่น__name__แล้ว

  • มันรันรหัสทั้งหมดที่พบในไฟล์

เรามาดูกันว่ามันใช้งานอย่างไรและเกี่ยวข้องกับคำถามของคุณอย่างไรเกี่ยวกับการ__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"

การดำเนินการของโมดูล

หลังจากตั้งค่าตัวแปรพิเศษแล้วล่ามจะเรียกใช้งานรหัสทั้งหมดในโมดูลหนึ่งคำสั่งพร้อมกัน คุณอาจต้องการเปิดหน้าต่างอื่นที่ด้านข้างพร้อมตัวอย่างรหัสเพื่อให้คุณสามารถติดตามพร้อมกับคำอธิบายนี้

เสมอ

  1. มันพิมพ์สตริง"before import"(โดยไม่ใส่เครื่องหมายอัญประกาศ)

  2. มันโหลดโมดูลและกำหนดให้กับตัวแปรที่เรียกว่า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")
  1. "before functionA"มันพิมพ์สตริง

  2. มันดำเนินการบล็อกการสร้างวัตถุฟังก์ชั่นแล้วกำหนดว่าฟังก์ชันวัตถุให้กับตัวแปรที่เรียกว่าdeffunctionA

  3. "before functionB"มันพิมพ์สตริง

  4. มันรันที่สองบล็อกสร้างวัตถุฟังก์ชั่นอื่นแล้วกำหนดให้กับตัวแปรที่เรียกว่าdeffunctionB

  5. "before __name__ guard"มันพิมพ์สตริง

เมื่อโมดูลของคุณเป็นโปรแกรมหลักเท่านั้น

  1. ถ้าโมดูลของคุณเป็นโปรแกรมหลักแล้วก็จะเห็นว่า__name__ถูกกำหนดแน่นอน"__main__"และจะเรียกทั้งสองฟังก์ชั่นการพิมพ์สตริงและ"Function A""Function B 10.0"

เมื่อโมดูลของคุณถูกอิมพอร์ตโดยโมดูลอื่นเท่านั้น

  1. ( แทน ) หากโมดูลของคุณไม่ได้เป็นโปรแกรมหลัก แต่ถูกนำเข้าโดยอีกโมดูลหนึ่ง__name__จะ"foo"ไม่ใช่"__main__"และจะข้ามเนื้อหาของifคำสั่งนั้น

เสมอ

  1. มันจะพิมพ์สตริง"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 เพียงแค่ตั้งค่าตัวแปรเวทย์มนตร์ไม่กี่ตัวและนำเข้าสคริปต์ "การทำงาน" สคริปต์เป็นผลข้างเคียงของการนำเข้าโมดูลของสคริปต์

อาหารสมอง

  • คำถาม: ฉันสามารถมี__name__บล็อกการตรวจสอบหลายอันได้หรือไม่? คำตอบ: มันแปลกที่จะทำเช่นนั้น แต่ภาษาจะไม่หยุดคุณ

  • foo2.pyสมมติว่าต่อไปนี้อยู่ใน จะเกิดอะไรขึ้นถ้าคุณพูดpython foo2.pyในบรรทัดคำสั่ง ทำไม?

# 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")

14
หมดความอยากรู้: เกิดอะไรขึ้นถ้าฉันทำงานsubprocess.run('foo_bar.py')ในสคริปต์หลาม? ฉันคิดว่าfoo_barจะเริ่มต้นด้วย__name__ = '__main__'เหมือนเมื่อฉัน tipe foo_bar.pyใน cmd ด้วยตนเอง เป็นอย่างนั้นเหรอ? การรับ @MrFooz 'คำตอบเข้าบัญชีไม่ควรมีปัญหาใด ๆ ในการทำเช่นนี้และมีโมดูล "หลัก" มากที่สุดเท่าที่ฉันต้องการ แม้การเปลี่ยน__name__ค่าหรือมีหลายอินสแตนซ์ที่สร้างอินสแตนซ์ (หรืออินสแตนซ์ที่สร้างโดยกันและกันsubprocess) โต้ตอบกับกันและกันควรเป็นธุรกิจตามปกติสำหรับ Python ฉันพลาดอะไรไปหรือเปล่า?
hajef

12
@hajef subprocess.runคุณที่ถูกต้องเกี่ยวกับสิ่งที่จะทำงานร่วมกับ วิธีที่ดีกว่าในการแบ่งปันรหัสระหว่างสคริปต์คือการสร้างโมดูลและให้สคริปต์เรียกโมดูลที่ใช้ร่วมกันแทนการเรียกใช้ซึ่งกันและกันเป็นสคริปต์ เป็นการยากที่จะทำการดีบักการsubprocess.runโทรเนื่องจาก debuggers ส่วนใหญ่จะไม่ข้ามขอบเขตของกระบวนการมันสามารถเพิ่มโอเวอร์เฮดของระบบที่ไม่สำคัญเพื่อสร้างและทำลายกระบวนการพิเศษ ฯลฯ
Mr Fooz

4
ฉันมีข้อสงสัยในตัวอย่าง foo2.py ในส่วนอาหารสำหรับความคิดสิ่งที่มาจากฟังก์ชั่นการนำเข้า foo2.py จาก B ทำอย่างไร ในมุมมองของฉันมันแค่นำเข้า foo2.py จาก functionB
user471651

1
@ MRFooz ฉันไม่เคยตั้งใจที่จะทำอะไรเช่นนี้ xD มันมาถึงใจของฉันและฉันรู้ว่ามันแปลกพอที่จะช่วย ppl ห่อจิตใจของพวกเขารอบ ๆ สิ่งเหล่านี้ @ user471651 ทำไมต้องfrom foo2 import functionBนำเข้า foo2 จาก functionB นั่นคือการบิดเบือนความหมาย from module import methodนำเข้าวิธีการจากโมดูล
hajef

2
หนึ่งในโมดูลที่อาจนำเข้ารหัสของคุณคือmultiprocessingโดยเฉพาะอย่างยิ่งการทดสอบนี้จำเป็นใน Windows
Yann Vernier

1801

เมื่อสคริปต์ของคุณทำงานโดยส่งผ่านมันเป็นคำสั่งไปยัง Python interpreter

python myscript.py

รหัสทั้งหมดที่อยู่ในระดับเยื้อง 0 ได้รับการดำเนินการ ฟังก์ชั่นและชั้นเรียนที่กำหนดไว้คือดีกำหนด แต่ไม่มีรหัสของพวกเขาได้รับการเรียกใช้ แตกต่างจากภาษาอื่น ๆ ไม่มีmain()ฟังก์ชั่นที่จะทำงานอัตโนมัติ - main()ฟังก์ชั่นนี้มีรหัสทั้งหมดที่ระดับบนสุดโดยปริยาย

ในกรณีนี้รหัสระดับบนสุดคือifบล็อก __name__เป็นตัวแปรในตัวซึ่งประเมินเป็นชื่อของโมดูลปัจจุบัน แต่ถ้าโมดูลจะถูกเรียกใช้โดยตรง (ในขณะที่myscript.pyด้านบน) แล้วแทนที่จะถูกตั้งค่าเป็นสตริง__name__ "__main__"ดังนั้นคุณสามารถทดสอบว่าสคริปต์ของคุณกำลังทำงานโดยตรงหรือนำเข้าอย่างอื่นโดยการทดสอบ

if __name__ == "__main__":
    ...

หากสคริปต์ของคุณจะถูกนำเข้ามาในโมดูลอื่นฟังก์ชั่นและระดับคำจำกัดความต่าง ๆ จะถูกนำเข้าและรหัสระดับบนสุดของมันจะถูกดำเนินการ แต่รหัสในแล้วร่างกายของifประโยคข้างต้นจะไม่ได้รับการเรียกใช้เป็นเงื่อนไขเป็น ไม่เจอ. เป็นตัวอย่างพื้นฐานพิจารณาสองสคริปต์ต่อไปนี้:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

ตอนนี้ถ้าคุณเรียกล่ามเป็น

python one.py

ผลลัพธ์จะเป็น

top-level in one.py
one.py is being run directly

หากคุณทำงานtwo.pyแทน:

python two.py

คุณได้รับ

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

ดังนั้นเมื่อโมดูลoneได้รับการโหลดมัน__name__เท่ากับแทน"one""__main__"


คำตอบที่ยอดเยี่ยมนี่เป็นคำตอบที่ชัดเจนที่สุดในความคิดของฉัน +1!
TheTechRobo36414519

+1 สำหรับวิธีการคิดเกี่ยวกับมัน: บรรทัดเยื้องครั้งแรกจะทำงานเฉพาะในตอนแรกจนกว่าคุณจะเรียกใช้ฟังก์ชั่นในบรรทัดแรกนั้น
Elijah Mock

719

คำอธิบายที่ง่ายที่สุดสำหรับ__name__ตัวแปร (imho) คือ:

สร้างไฟล์ต่อไปนี้

# a.py
import b

และ

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

ใช้พวกเขาจะได้รับผลลัพธ์นี้:

$ python a.py
Hello World from b!

อย่างที่คุณเห็นเมื่อนำเข้าโมดูล Python จะตั้งค่าglobals()['__name__']ในโมดูลนี้เป็นชื่อของโมดูล นอกจากนี้เมื่อนำเข้ารหัสทั้งหมดในโมดูลจะถูกเรียกใช้ ในขณะที่ifงบประเมินไปยังFalseส่วนนี้ไม่ได้ดำเนินการ

$ python b.py
Hello World from __main__!
Hello World again from __main__!

ในขณะที่คุณสามารถดูเมื่อไฟล์ถูกดำเนินการหลามชุดในแฟ้มนี้ไปยังglobals()['__name__'] "__main__"เวลานี้ifคำสั่งประเมินTrueและกำลังถูกเรียกใช้


513

อะไรif __name__ == "__main__":ทำอย่างไร

ในการจัดทำโครงร่างพื้นฐาน:

  • ตัวแปรระดับโลกในโมดูลที่เป็นจุดเริ่มต้นในการเขียนโปรแกรมของคุณคือ__name__ '__main__'มิฉะนั้นเป็นชื่อที่คุณนำเข้าโมดูลโดย

  • ดังนั้นรหัสภายใต้ifบล็อกจะทำงานก็ต่อเมื่อโมดูลนั้นเป็นจุดเข้าสู่โปรแกรมของคุณ

  • อนุญาตให้โค้ดในโมดูลสามารถนำเข้าได้โดยโมดูลอื่นโดยไม่ต้องดำเนินการบล็อกโค้ดด้านล่างเมื่อนำเข้า


ทำไมเราต้องการสิ่งนี้

การพัฒนาและทดสอบรหัสของคุณ

สมมติว่าคุณกำลังเขียนสคริปต์ Python ที่ออกแบบมาเพื่อใช้เป็นโมดูล:

def do_important():
    """This function does something very important"""

คุณสามารถทดสอบโมดูลโดยเพิ่มการเรียกฟังก์ชันนี้ที่ด้านล่าง:

do_important()

และเรียกใช้ (พร้อมรับคำสั่ง) กับสิ่งที่ชอบ:

~$ python important.py

ปัญหา

อย่างไรก็ตามหากคุณต้องการนำเข้าโมดูลไปยังสคริปต์อื่น:

import important

เมื่อนำเข้าdo_importantจะมีการเรียกใช้ฟังก์ชันดังนั้นคุณอาจแสดงความคิดเห็นในการเรียกใช้ฟังก์ชันdo_important()ที่ด้านล่าง

# do_important() # I must remember to uncomment to execute this!

แล้วคุณจะต้องจำไว้ว่าคุณได้แสดงความคิดเห็นการเรียกใช้ฟังก์ชันทดสอบของคุณหรือไม่ และความซับซ้อนที่เพิ่มขึ้นนี้จะหมายความว่าคุณมีแนวโน้มที่จะลืมทำให้กระบวนการพัฒนาของคุณยุ่งยากขึ้น

วิธีที่ดีกว่า

__name__ตัวแปรชี้ถึง namespace ใดก็ตามที่ล่ามงูใหญ่ที่จะเกิดขึ้นในขณะนี้

ภายในโมดูลที่นำเข้ามันเป็นชื่อของโมดูลนั้น

แต่ภายในโมดูลหลัก (หรือเซสชั่นหลามโต้ตอบเช่นล่ามอ่าน Eval พิมพ์ห่วงหรือ REPL) "__main__"คุณกำลังทำงานทุกอย่างจากมัน

ดังนั้นหากคุณตรวจสอบก่อนดำเนินการ:

if __name__ == "__main__":
    do_important()

ด้วยโค้ดข้างต้นโค้ดของคุณจะทำงานเมื่อคุณเรียกใช้เป็นโมดูลหลักเท่านั้น (หรือเรียกโดยเจตนาจากสคริปต์อื่น)

วิธีที่ดีกว่า

มีวิธี Pythonic เพื่อปรับปรุงเกี่ยวกับเรื่องนี้แม้ว่า

ถ้าเราต้องการเรียกใช้กระบวนการทางธุรกิจนี้จากนอกโมดูล

หากเราใส่รหัสที่เราต้องการออกกำลังกายในขณะที่เราพัฒนาและทดสอบในฟังก์ชั่นเช่นนี้แล้วทำการตรวจสอบของเรา'__main__'ทันทีหลังจาก:

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

ตอนนี้เรามีฟังก์ชั่นสุดท้ายสำหรับส่วนท้ายของโมดูลของเราที่จะทำงานถ้าเราเรียกใช้โมดูลเป็นโมดูลหลัก

มันจะช่วยให้โมดูลและฟังก์ชั่นและชั้นเรียนของมันจะถูกนำเข้าสู่สคริปต์อื่น ๆ โดยไม่ต้องใช้mainฟังก์ชั่นและยังจะช่วยให้เรียกโมดูล (และฟังก์ชั่นและชั้นเรียน) เมื่อเรียกใช้จาก'__main__'โมดูลที่แตกต่างกัน

import important
important.main()

สำนวนนี้สามารถพบได้ในเอกสาร Python ในคำอธิบายของ__main__โมดูล ข้อความนั้นระบุว่า:

โมดูลนี้แสดงขอบเขต (ไม่ระบุชื่อเป็นอย่างอื่น) ซึ่งโปรแกรมหลักของล่ามดำเนินการ - คำสั่งอ่านจากอินพุตมาตรฐานจากไฟล์สคริปต์หรือจากพรอมต์แบบโต้ตอบ เป็นสภาพแวดล้อมที่ stanza "ตามเงื่อนไข" ที่เป็นสำนวนนี้ทำให้สคริปต์ทำงาน:

if __name__ == '__main__':
    main()

125

if __name__ == "__main__"เป็นส่วนหนึ่งที่วิ่งเมื่อสคริปต์มีการเรียกใช้จาก (พูด) python myscript.pyบรรทัดคำสั่งโดยใช้คำสั่งที่ชอบ


2
ทำไมไฟล์helloworld.pyที่มีเพียงแค่print("hello world")ในนั้นสามารถทำงานได้ด้วยคำสั่งpython helloworld.pyแม้เมื่อไม่มีif __name__ == "__main__"?
hi15

83

อะไรif __name__ == "__main__":ทำอย่างไร

__name__เป็นตัวแปรโกลบอล (ใน Python โกลบอลจริงหมายถึงระดับโมดูล ) ที่มีอยู่ในเนมสเปซทั้งหมด โดยทั่วไปจะเป็นชื่อของโมดูล (เป็นstrชนิด)

อย่างไรก็ตามเป็นกรณีพิเศษเพียงอย่างเดียวในกระบวนการ Python ที่คุณเรียกใช้เช่นเดียวกับใน mycode.py:

python mycode.py

namespace โลกที่ไม่ระบุชื่ออย่างอื่นที่ได้รับมอบหมายค่าของของมัน'__main__'__name__

ดังนั้นรวมถึงบรรทัดสุดท้าย

if __name__ == '__main__':
    main()
  • ในตอนท้ายของสคริปต์ mycode.py ของคุณ
  • เมื่อเป็นโมดูลจุดเริ่มต้นที่เรียกใช้โดยกระบวนการ Python

จะทำให้mainฟังก์ชันที่กำหนดไว้เฉพาะของสคริปต์ทำงาน

ประโยชน์อีกประการของการใช้โครงสร้างนี้: คุณยังสามารถนำเข้ารหัสของคุณเป็นโมดูลในสคริปต์อื่นแล้วเรียกใช้ฟังก์ชันหลักหากและเมื่อโปรแกรมของคุณตัดสินใจ:

import mycode
# ... any amount of other code
mycode.main()

72

มีหลายสิ่งที่แตกต่างกันในกลไกของโค้ดที่เรียกว่า "อย่างไร" แต่สำหรับฉันมันไม่มีเหตุผลใด ๆ จนกว่าฉันจะเข้าใจ "ทำไม" สิ่งนี้จะเป็นประโยชน์อย่างยิ่งสำหรับโปรแกรมเมอร์ใหม่

ใช้ไฟล์ "ab.py":

def a():
    print('A function in ab file');
a()

และไฟล์ที่สอง "xy.py":

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

รหัสนี้กำลังทำอะไรอยู่?

เมื่อคุณรันคุณxy.py import abคำสั่งนำเข้าที่ทำงานโมดูลทันทีในการนำเข้าเพื่อab'การดำเนินงานได้รับการดำเนินการก่อนส่วนที่เหลือของxy' s เมื่อเสร็จสิ้นก็ยังคงมีabxy

ล่ามจะติดตามว่ามีสคริปต์ใดทำงาน__name__อยู่ เมื่อคุณเรียกใช้สคริปต์ - ไม่ว่าคุณจะตั้งชื่ออะไร - ล่ามจะเรียกมัน"__main__"ว่าเป็นสคริปต์หลักหรือสคริปต์ 'โฮม' ที่กลับมาหลังจากเรียกใช้สคริปต์ภายนอก

สคริปต์อื่นที่ถูกเรียกจาก"__main__"สคริปต์นี้จะถูกกำหนดชื่อไฟล์เป็น__name__(เช่น__name__ == "ab.py") ดังนั้นบรรทัดif __name__ == "__main__":คือการทดสอบของล่ามเพื่อตรวจสอบว่ามันเป็นการตีความ / แยกวิเคราะห์สคริปต์ 'โฮม' ที่ถูกเรียกใช้ครั้งแรกหรือถ้ามันเป็นการแอบดูสคริปต์อื่น (ภายนอก) ชั่วคราว สิ่งนี้จะช่วยให้โปรแกรมเมอร์มีความยืดหยุ่นในการให้สคริปต์ทำงานแตกต่างกันหากสคริปต์ถูกเรียกใช้โดยตรงกับชื่อภายนอก

ลองทำตามโค้ดด้านบนเพื่อทำความเข้าใจสิ่งที่เกิดขึ้นโดยเน้นไปที่บรรทัดที่ไม่มีการจดสิทธิบัตรและลำดับที่ปรากฏในสคริปต์ โปรดจำไว้ว่าฟังก์ชั่น - หรือdef- บล็อกจะไม่ทำอะไรด้วยตัวเองจนกว่าจะถูกเรียกใช้ ล่ามอาจจะพูดอะไรถ้าพูดพึมพำกับตัวเอง:

  • เปิด xy.py เป็นไฟล์ 'home' เรียกว่า"__main__"ใน__name__ตัวแปร
  • __name__ == "ab.py"นำเข้าและเปิดไฟล์ด้วย
  • โอ้ฟังก์ชั่น ฉันจะจำได้
  • ตกลงฟังก์ชั่นa(); ฉันเพิ่งเรียนรู้ว่า การพิมพ์ ' ฟังก์ชั่นในไฟล์ ab '
  • สิ้นสุดไฟล์ กลับไปที่"__main__"!
  • โอ้ฟังก์ชั่น ฉันจะจำได้
  • อีกอันหนึ่ง
  • ฟังก์ชั่นx(); ตกลงการพิมพ์ ' งานต่อพ่วง: อาจมีประโยชน์ในโครงการอื่น '
  • นี่อะไรน่ะ? ifคำสั่ง ตรงตามเงื่อนไข (ตัวแปร__name__ถูกตั้งไว้ที่"__main__") ดังนั้นฉันจะเข้าสู่main()ฟังก์ชั่นและพิมพ์ ' ฟังก์ชั่นหลัก: นี่คือที่ที่การกระทำคือ '

บรรทัดสองบรรทัดล่างหมายถึง: "ถ้านี่เป็น"__main__"สคริปต์หรือ 'โฮม' ให้เรียกใช้งานฟังก์ชันที่เรียกว่าmain()" นั่นเป็นเหตุผลที่คุณจะเห็นdef main():บล็อกอัพด้านบนซึ่งมีโฟลว์หลักของฟังก์ชันการทำงานของสคริปต์

ทำไมต้องใช้สิ่งนี้

จำสิ่งที่ฉันพูดไว้ก่อนหน้านี้เกี่ยวกับคำสั่งนำเข้าได้หรือไม่ เมื่อคุณนำเข้าโมดูลมันไม่เพียง 'จดจำ' มันและรอคำแนะนำเพิ่มเติม - จริง ๆ แล้วมันทำงานการดำเนินการปฏิบัติการทั้งหมดที่มีอยู่ภายในสคริปต์ ดังนั้นการนำเนื้อของสคริปต์ของคุณไปไว้ในmain()ฟังก์ชันกักกันอย่างมีประสิทธิภาพวางแยกไว้เพื่อไม่ให้ทำงานทันทีเมื่อนำเข้าโดยสคริปต์อื่น

อีกครั้งจะมีข้อยกเว้น แต่การปฏิบัติทั่วไปคือmain()ปกติไม่เรียกจากภายนอก ดังนั้นคุณอาจสงสัยอีกสิ่งหนึ่ง: ถ้าเราไม่โทรmain()เราจะเรียกสคริปต์ทำไม เป็นเพราะคนจำนวนมากจัดโครงสร้างสคริปต์ของพวกเขาด้วยฟังก์ชั่นสแตนด์อโลนที่สร้างขึ้นเพื่อให้ทำงานโดยไม่ขึ้นกับโค้ดที่เหลือในไฟล์ หลังจากนั้นพวกเขาจะถูกเรียกที่อื่นในเนื้อหาของสคริปต์ ซึ่งนำฉันมาที่นี่:

แต่รหัสก็ใช้ไม่ได้

ใช่ถูกแล้ว. ฟังก์ชั่นแยกเหล่านี้สามารถเรียกใช้จากสคริปต์ในบรรทัดที่ไม่มีอยู่ในmain()ฟังก์ชัน หากคุณคุ้นเคยกับการเขียนโปรแกรมในช่วงต้นของการเรียนรู้ (เช่นฉันในช่วงเริ่มต้นของการเขียนโปรแกรม) ที่จะทำสิ่งที่คุณต้องการและคุณจะลองคิดดูอีกครั้งหากคุณต้องการการดำเนินการอีกครั้ง .. คุณไม่คุ้นเคยกับโครงสร้างภายในชนิดนี้ในรหัสของคุณเพราะมันซับซ้อนกว่าในการสร้างและไม่ง่ายต่อการอ่าน

แต่นั่นเป็นสคริปต์ที่อาจไม่มีฟังก์ชั่นที่เรียกว่าภายนอกเพราะถ้ามันมันจะเริ่มคำนวณและกำหนดตัวแปรทันที และโอกาสคือถ้าคุณพยายามใช้ฟังก์ชันอีกครั้งสคริปต์ใหม่ของคุณจะเกี่ยวข้องอย่างใกล้ชิดกับฟังก์ชันเก่าซึ่งจะมีตัวแปรที่ขัดแย้งกัน

ในการแยกฟังก์ชั่นอิสระคุณจะสามารถใช้งานก่อนหน้าของคุณได้อีกครั้งโดยการเรียกใช้งานเป็นสคริปต์อื่น ตัวอย่างเช่น "example.py" อาจนำเข้า "xy.py" และการโทรx()ใช้ประโยชน์จากฟังก์ชั่น 'x' จาก "xy.py" (อาจจะเป็นการใช้ประโยชน์จากคำที่สามของสตริงข้อความที่กำหนดไว้การสร้างอาร์เรย์ NumPy จากรายการตัวเลขและการยกกำลังสองหรือการทำลายพื้นผิว 3 มิติความเป็นไปได้ไม่มี จำกัด )

(เช่นกันคำถามนี้มีคำตอบโดย @kindall ที่ในที่สุดก็ช่วยให้ฉันเข้าใจ. - ทำไมไม่ว่า แต่น่าเสียดายที่มันถูกทำเครื่องหมายเป็นซ้ำของคนนี้ซึ่งผมคิดว่าเป็นความผิดพลาด.)


52

เมื่อมีคำสั่งบางอย่างในโมดูลของเรา ( M.py) เราต้องการที่จะดำเนินการเมื่อมันจะทำงานเป็นหลัก (ไม่ได้นำเข้า) เราสามารถวางคำสั่งเหล่านั้น (กรณีทดสอบงบพิมพ์) ภายใต้ifบล็อกนี้

ตามค่าเริ่มต้น (เมื่อโมดูลที่ทำงานเป็นหลักไม่ได้นำเข้า) __name__ตัวแปรจะถูกตั้งค่าเป็น"__main__"และเมื่อมันจะถูกนำเข้า__name__ตัวแปรจะได้รับค่าที่แตกต่างกันส่วนใหญ่อาจเป็นชื่อของโมดูล ( 'M') สิ่งนี้มีประโยชน์ในการรันชุดรูปแบบที่แตกต่างกันของโมดูลเข้าด้วยกันและแยกคำสั่งอินพุทและเอาท์พุทเฉพาะของพวกเขาและถ้ามีกรณีทดสอบใด ๆ

กล่าวโดยย่อให้ใช้if __name__ == "main"บล็อกนี้เพื่อป้องกันไม่ให้มีการเรียกใช้รหัสเมื่อมีการนำเข้าโมดูล


43

กล่าวง่ายๆ__name__คือเป็นตัวแปรที่กำหนดไว้สำหรับแต่ละสคริปต์ที่กำหนดว่าสคริปต์นั้นจะถูกเรียกใช้เป็นโมดูลหลักหรือจะถูกเรียกใช้เป็นโมดูลที่นำเข้า

ดังนั้นถ้าเรามีสองสคริปต์

#script1.py
print "Script 1's name: {}".format(__name__)

และ

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

เอาต์พุตจากการเรียกใช้งาน script1 คือ

Script 1's name: __main__

และเอาต์พุตจากการเรียกใช้งาน script2 คือ:

Script1's name is script1
Script 2's name: __main__

อย่างที่คุณเห็น__name__บอกรหัสซึ่งเป็นโมดูล 'หลัก' นี่ยอดเยี่ยมเพราะคุณสามารถเขียนโค้ดและไม่ต้องกังวลเกี่ยวกับปัญหาเชิงโครงสร้างเช่นใน C / C ++ ที่ซึ่งหากไฟล์ไม่ได้ใช้ฟังก์ชั่น 'main' ก็จะไม่สามารถคอมไพล์เป็นไฟล์ที่เรียกใช้งานได้และถ้าเป็นเช่นนั้น ไม่สามารถใช้เป็นห้องสมุดได้

สมมติว่าคุณเขียนสคริปต์ Python ที่ทำสิ่งที่ยอดเยี่ยมและคุณใช้ฟังก์ชั่นต่าง ๆ ที่มีประโยชน์สำหรับวัตถุประสงค์อื่น หากฉันต้องการใช้ฉันสามารถนำเข้าสคริปต์ของคุณและใช้งานได้โดยไม่ต้องเรียกใช้งานโปรแกรมของคุณ (เนื่องจากรหัสของคุณดำเนินการภายใน if __name__ == "__main__":บริบทเท่านั้น) ในขณะที่ C / C ++ คุณจะต้องแบ่งส่วนเหล่านั้นออกเป็นโมดูลแยกต่างหากจากนั้นรวมไฟล์ รูปภาพสถานการณ์ด้านล่าง

การนำเข้าที่ซับซ้อนใน C.

ลูกศรเป็นลิงค์นำเข้า สำหรับสามโมดูลแต่ละครั้งที่พยายามรวมรหัสโมดูลก่อนหน้านี้จะมีหกไฟล์ (เก้าไฟล์การนับการใช้งาน) และห้าลิงก์ สิ่งนี้ทำให้เป็นการยากที่จะรวมรหัสอื่น ๆ ลงในโครงการ C ยกเว้นว่าจะรวบรวมเป็นไลบรารีโดยเฉพาะ ตอนนี้ภาพมันสำหรับ Python:

การนำเข้าที่หรูหราใน Python

คุณเขียนโมดูลและถ้ามีคนต้องการใช้รหัสของพวกเขาพวกเขาเพียงแค่นำเข้าและ__name__ตัวแปรสามารถช่วยในการแยกส่วนที่ปฏิบัติการของโปรแกรมจากส่วนห้องสมุด


2
ภาพประกอบ C / C ++ ผิด: 3 ครั้งชื่อหน่วยเดียวกัน ( file1 )
Wolf

40

ลองดูคำตอบด้วยวิธีที่เป็นนามธรรมมากขึ้น:

สมมติว่าเรามีรหัสนี้ในx.py:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

บล็อก A และ B x.pyจะถูกเรียกใช้เมื่อเรากำลังทำงานอยู่

แต่เพียงแค่บล็อก A (และไม่ใช่ B) จะถูกรันเมื่อเรารันโมดูลอื่นy.pyตัวอย่างเช่นซึ่งx.pyจะถูกอิมพอร์ตและโค้ดจะถูกเรียกใช้จากที่นั่น (เช่นเมื่อมีการx.pyเรียกใช้ฟังก์ชันจากy.py)


1
ฉันไม่สามารถแก้ไขโพสต์ (ขั้นต่ำ 6 ตัวอักษรหากต้องการการเปลี่ยนแปลง) บรรทัดที่ 14 มี 'xy' แทนที่จะเป็น 'x.py'
alwaysLearning

35

เมื่อคุณเรียกงูหลามโต้ตอบท้องถิ่นตัวแปรมีการกำหนดค่าของ__name__ __main__ในทำนองเดียวกันเมื่อคุณเรียกใช้งานโมดูล Python จากบรรทัดคำสั่งแทนที่จะนำเข้าสู่โมดูลอื่นแอ__name__ททริบิวจะถูกกำหนดค่า__main__เป็นแทนที่จะเป็นชื่อจริงของโมดูล ด้วยวิธีนี้โมดูลสามารถดู__name__มูลค่าของตัวเองเพื่อพิจารณาด้วยตนเองว่ามีการใช้งานอย่างไรไม่ว่าจะเป็นการสนับสนุนโปรแกรมอื่นหรือเป็นแอปพลิเคชันหลักที่เรียกใช้จากบรรทัดคำสั่ง ดังนั้นสำนวนต่อไปนี้เป็นเรื่องธรรมดาในโมดูล Python:

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.

34

พิจารณา:

if __name__ == "__main__":
    main()

มันจะตรวจสอบถ้า__name__แอตทริบิวต์ของสคริปต์ Python "__main__"เป็น กล่าวอีกนัยหนึ่งหากมีการดำเนินการโปรแกรมตัวเองจะมีคุณลักษณะดังกล่าว__main__ดังนั้นโปรแกรมจะถูกดำเนินการ (ในกรณีนี้คือmain()ฟังก์ชัน)

อย่างไรก็ตามหากสคริปต์ Python ของคุณถูกใช้โดยโมดูลโค้ดใด ๆ ที่อยู่ภายนอกifคำสั่งจะถูกดำเนินการดังนั้นif \__name__ == "\__main__"จะใช้เพื่อตรวจสอบว่าโปรแกรมนั้นถูกใช้เป็นโมดูลหรือไม่และตัดสินใจว่าจะรันโค้ดหรือไม่


ดูเหมือนจะใช้เวลานานเกินไปในการเขียนคำตอบที่ส่องสว่าง +1
snr

27

ก่อนอธิบายสิ่งใดสิ่งif __name__ == '__main__'สำคัญคือต้องเข้าใจว่าอะไร__name__คืออะไรและทำอะไร

คือ__name__อะไร

__name__เป็นDunderAlias - ถือได้ว่าเป็นตัวแปรทั่วโลก (เข้าถึงได้จากโมดูล) และทำงานในลักษณะเดียวกันกับglobalและทำงานในลักษณะที่คล้ายกับ

มันเป็นสตริง (ทั่วโลกดังกล่าวข้างต้น) ตามที่ระบุโดยtype(__name__)(ยอม<class 'str'>) และเป็นมาตรฐาน inbuilt สำหรับทั้งPython 3และPython 2รุ่น

ที่ไหน:

มันไม่เพียง แต่สามารถใช้ในสคริปต์ แต่ยังสามารถพบได้ในทั้งล่ามและโมดูล / แพ็คเกจ

ล่าม:

>>> print(__name__)
__main__
>>>

สคริปต์:

test_file.py :

print(__name__)

ที่เกิดขึ้นใน __main__

โมดูลหรือแพคเกจ:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

ที่เกิดขึ้นใน somefile

โปรดสังเกตว่าเมื่อใช้ในแพ็คเกจหรือโมดูลให้__name__ใช้ชื่อของไฟล์ ไม่ได้กำหนดเส้นทางของโมดูลหรือเส้นทางที่แท้จริง แต่มี DunderAlias ​​ของตัวเอง__file__ที่ช่วยให้นี้

คุณจะเห็นว่าที่ไหน__name__ที่เป็นไฟล์หลัก (หรือโปรแกรม) จะกลับมาเสมอ__main__และถ้ามันเป็นโมดูล / แพคเกจหรือสิ่งที่ทำงานออกสคริปต์ Python อื่น ๆ จะกลับชื่อของไฟล์ที่มัน มีต้นกำเนิดมาจาก

การปฏิบัติ:

การเป็นตัวแปรหมายความว่าค่าของมันสามารถเขียนทับได้ ("สามารถ" ไม่ได้หมายความว่า "ควร") เขียนทับค่าของ__name__จะทำให้ขาดความสามารถในการอ่าน ดังนั้นอย่าทำด้วยเหตุผลใดก็ตาม หากคุณต้องการตัวแปรกำหนดตัวแปรใหม่

มันจะสันนิษฐานเสมอว่าค่าของ__name__การเป็น__main__หรือชื่อของไฟล์ การเปลี่ยนค่าเริ่มต้นนี้อีกครั้งจะทำให้เกิดความสับสนมากขึ้นว่าจะทำได้ดีทำให้เกิดปัญหาต่อไปในบรรทัด

ตัวอย่าง:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

ถือว่าเป็นการปฏิบัติที่ดีโดยทั่วไปในการรวมif __name__ == '__main__'สคริปต์เข้าด้วยกัน

ตอนนี้ที่จะตอบif __name__ == '__main__':

ตอนนี้เรารู้ว่าพฤติกรรมของ__name__สิ่งต่าง ๆ ชัดเจนขึ้น:

An ifเป็นคำสั่งควบคุมการไหลที่มีการบล็อกรหัสจะดำเนินการถ้าค่าที่กำหนดเป็นจริง เราได้เห็นแล้วว่า__name__สามารถรับได้ __main__ไฟล์ไฟล์หรือชื่อไฟล์ที่นำเข้ามาจาก

ซึ่งหมายความว่าหาก__name__เท่ากับ__main__ไฟล์นั้นจะต้องเป็นไฟล์หลักและต้องใช้งานจริง (หรือเป็นล่าม) ไม่ใช่โมดูลหรือแพ็กเกจที่นำเข้ามาในสคริปต์

หาก__name__ใช้ค่าของ__main__อะไรก็ตามที่อยู่ในบล็อกของรหัสนั้นจะถูกดำเนินการ

สิ่งนี้บอกเราว่าหากไฟล์ที่เรียกใช้เป็นไฟล์หลัก (หรือคุณกำลังเรียกใช้จากล่ามโดยตรง) ดังนั้นเงื่อนไขนั้นจะต้องดำเนินการ __main__ถ้ามันเป็นแพคเกจแล้วมันไม่ควรและความคุ้มค่าจะไม่

โมดูล

__name__ ยังสามารถใช้ในโมดูลเพื่อกำหนดชื่อของโมดูล

สายพันธุ์:

นอกจากนี้ยังเป็นไปได้ที่จะทำสิ่งอื่น ๆ ที่พบน้อย แต่มีประโยชน์ด้วย__name__บางอย่างฉันจะแสดงที่นี่:

การดำเนินการเฉพาะในกรณีที่ไฟล์เป็นโมดูลหรือแพคเกจ:

if __name__ != '__main__':
    # Do some useful things 

เรียกใช้หนึ่งเงื่อนไขหากไฟล์เป็นไฟล์หลักและอีกไฟล์หนึ่งหากไม่ใช่:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

คุณยังสามารถใช้มันเพื่อจัดเตรียมฟังก์ชัน / ยูทิลิตี้ช่วยเหลือที่รันได้บนแพ็คเกจและโมดูลโดยไม่ต้องใช้ไลบรารีอย่างละเอียด

นอกจากนี้ยังช่วยให้โมดูลสามารถเรียกใช้จากบรรทัดคำสั่งเป็นสคริปต์หลักซึ่งยังมีประโยชน์มาก


25

ฉันคิดว่ามันเป็นการดีที่สุดที่จะทำลายคำตอบในเชิงลึกและคำง่าย ๆ :

__name__: __name__โมดูลในหลามทุกคนมีคุณลักษณะพิเศษที่เรียกว่า มันเป็นตัวแปรบิวด์อินที่ส่งคืนชื่อของโมดูล

__main__: เช่นเดียวกับภาษาโปรแกรมอื่น ๆ Python ก็มีจุดเข้าใช้งานเช่นหลัก เป็นชื่อของขอบเขตที่รันรหัสระดับบนสุด'__main__' โดยทั่วไปคุณมีสองวิธีในการใช้โมดูล Python: เรียกใช้โดยตรงเป็นสคริปต์หรือนำเข้า เมื่อมีการเรียกใช้โมดูลเป็นสคริปต์ของมันถูกตั้งค่าให้__name____main__

ดังนั้นค่าของ__name__แอ็ตทริบิวต์ถูกตั้งค่าเป็น__main__เมื่อโมดูลถูกรันเป็นโปรแกรมหลัก มิฉะนั้นค่าของ__name__ จะถูกตั้งค่าให้มีชื่อของโมดูล


23

มันเป็นพิเศษสำหรับเมื่อไฟล์ Python ถูกเรียกจากบรรทัดคำสั่ง โดยทั่วไปจะใช้เพื่อเรียกใช้ฟังก์ชัน "main ()" หรือเรียกใช้รหัสเริ่มต้นที่เหมาะสมอื่น ๆ เช่นการจัดการอาร์กิวเมนต์บรรทัดคำสั่งเป็นต้น

มันสามารถเขียนได้หลายวิธี อีกอย่างคือ:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

ผมไม่ได้บอกคุณควรใช้วิธีนี้ในรหัสการผลิต แต่มันทำหน้าที่เพื่อแสดงให้เห็นว่ามีอะไรที่ "เสก" if __name__ == '__main__'เกี่ยวกับ มันเป็นการประชุมที่ดีสำหรับการเรียกใช้ฟังก์ชั่นหลักในไฟล์ Python


7
ฉันจะพิจารณารูปแบบที่เลวร้ายนี้ขณะที่คุณกำลัง 1) อาศัยผลข้างเคียงและ 2) andการเหยียดหยาม andใช้สำหรับตรวจสอบว่าทั้งสองคำสั่งบูลีนเป็นจริงหรือไม่ เนื่องจากคุณไม่ได้สนใจในผลของandการifคำสั่งอย่างชัดเจนมากขึ้นในการสื่อสารความตั้งใจของคุณ
jpmc26

8
ทิ้งคำถามว่าการใช้ประโยชน์จากพฤติกรรมการลัดวงจรของผู้ประกอบการบูลีนเป็นกลไกการควบคุมการไหลเป็นสไตล์ที่ไม่ดีหรือไม่ปัญหาที่ใหญ่กว่าคือมันไม่ตอบคำถามเลย
Mark Amery

@ MarkAmery ฮ่าฮ่าเชเชสตอนนี้มันทำ 😊
ศ. Falken ผิดสัญญา

19

มีตัวแปรหลายตัวที่ระบบ (Python interpreter) จัดเตรียมไว้สำหรับไฟล์ต้นฉบับ (โมดูล) คุณสามารถรับค่าได้ทุกเวลาที่ต้องการดังนั้นให้เรามุ่งเน้นที่ตัวแปร__name__ / คุณลักษณะ:

เมื่อ Python โหลดไฟล์ซอร์สโค้ดมันจะประมวลผลโค้ดทั้งหมดที่พบในนั้น (โปรดทราบว่ามันไม่ได้เรียกวิธีการและฟังก์ชั่นทั้งหมดที่กำหนดไว้ในไฟล์ แต่มันจะกำหนดพวกเขา)

ก่อนที่ล่ามจะเรียกใช้ไฟล์ซอร์สโค้ด แต่จะกำหนดตัวแปรพิเศษบางอย่างสำหรับไฟล์นั้น __name__เป็นหนึ่งในตัวแปรพิเศษที่ Python กำหนดโดยอัตโนมัติสำหรับไฟล์ซอร์สโค้ดแต่ละไฟล์

หาก Python กำลังโหลดไฟล์ซอร์สโค้ดนี้เป็นโปรแกรมหลัก (เช่นไฟล์ที่คุณเรียกใช้) ก็จะตั้งค่าตัวแปร__name__พิเศษสำหรับไฟล์นี้ให้มีค่า"__main__" "__main__"

หากสิ่งนี้กำลังถูกนำเข้าจากโมดูลอื่น__name__จะถูกตั้งค่าเป็นชื่อของโมดูลนั้น

ดังนั้นในตัวอย่างของคุณในส่วน:

if __name__ == "__main__":
   lock = thread.allocate_lock()
   thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
   thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

หมายความว่าการบล็อกรหัส:

lock = thread.allocate_lock()
thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

จะถูกดำเนินการเฉพาะเมื่อคุณเรียกใช้โมดูลโดยตรง บล็อกโค้ดจะไม่ทำงานหากโมดูลอื่นกำลังเรียก / นำเข้าเพราะค่าของ__name__จะไม่เท่ากับ " main " ในอินสแตนซ์นั้น

หวังว่านี่จะช่วยได้


17

if __name__ == "__main__": นั้นเป็นสภาพแวดล้อมของสคริปต์ระดับบนสุดและจะระบุล่ามว่า ('ฉันมีลำดับความสำคัญสูงสุดที่ต้องดำเนินการก่อน')

'__main__'เป็นชื่อของขอบเขตที่ใช้รหัสระดับสูง โมดูล__name__ถูกตั้งค่าเท่ากับ'__main__'เมื่ออ่านจากอินพุตมาตรฐานสคริปต์หรือจากพรอมต์แบบโต้ตอบ

if __name__ == "__main__":
    # Execute only if run as a script
    main()

17

ฉันอ่านมามากมายตลอดคำตอบในหน้านี้ ฉันจะบอกว่าถ้าคุณรู้ว่าสิ่งที่แน่นอนคุณจะเข้าใจคำตอบเหล่านั้นมิฉะนั้นคุณยังสับสน

เมื่อต้องการย่อคุณต้องรู้หลายจุด:

  1. import a การกระทำจะทำงานทั้งหมดที่สามารถวิ่งได้ใน "a"

  2. เนื่องจากจุดที่ 1 คุณอาจไม่ต้องการให้ทุกอย่างทำงานใน "a" เมื่อนำเข้า

  3. เพื่อแก้ปัญหาในจุดที่ 2 งูใหญ่ช่วยให้คุณสามารถตรวจสอบเงื่อนไข

  4. __name__เป็นตัวแปรโดยนัยใน.pyโมดูลทั้งหมด เมื่อa.pyนำเข้า, ค่าของ__name__ของa.pyโมดูลถูกตั้งให้เป็นชื่อไฟล์ " a"; เมื่อa.pyรันโดยตรงโดยใช้ " python a.py" ซึ่งหมายความว่าa.pyเป็นจุดเข้าใช้งานดังนั้นค่า__name__ของa.pyโมดูลจะถูกตั้งค่าเป็นสตริง__main__

  5. ขึ้นอยู่กับกลไกที่ python ตั้งค่าตัวแปร__name__สำหรับแต่ละโมดูลคุณรู้วิธีการบรรลุจุดที่ 3 ได้อย่างไร คำตอบนั้นค่อนข้างง่ายใช่มั้ย ใส่ถ้าเงื่อนไข: if __name__ == "__main__": ...; คุณสามารถใส่ได้ถ้า__name__ == "a"ขึ้นอยู่กับความต้องการการทำงานของคุณ

สิ่งสำคัญที่หลามนั้นพิเศษที่จุด 4! ส่วนที่เหลือเป็นเพียงตรรกะพื้นฐาน


1
ใช่ประเด็นที่ 1 มีความสำคัญต่อการเข้าใจ จากนั้นความต้องการกลไกนี้ก็ชัดเจน
ยูเรก้า

16

พิจารณา:

print __name__

__main__สำหรับการส่งออกมีที่ดังกล่าวข้างต้น

if __name__ == "__main__":
  print "direct method"

ข้อความข้างต้นเป็นความจริงและภาพพิมพ์"วิธีการโดยตรง" สมมติว่าถ้าพวกเขานำเข้าระดับนี้ในชั้นเรียนอีกก็ไม่ได้พิมพ์"วิธีการโดยตรง"__name__ equal to "first model name"เพราะในขณะที่การนำเข้าก็จะตั้ง


14

คุณสามารถทำให้ไฟล์ใช้งานได้เป็นสคริปต์เช่นเดียวกับโมดูลที่สามารถอิมพอร์ตได้

fibo.py (ชื่อโมดูลfibo)

# Other modules can IMPORT this MODULE to use the function fib
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

# This allows the file to be used as a SCRIPT
if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

การอ้างอิง: https://docs.python.org/3.5/tutorial/modules.html


14

เหตุผลสำหรับ

if __name__ == "__main__":
    main()

เป็นหลักเพื่อหลีกเลี่ยงการล็อคนำเข้าปัญหาที่จะเกิดขึ้นจากการที่มีรหัสนำเข้าโดยตรง คุณต้องการmain()เรียกใช้หากไฟล์ของคุณถูกเรียกใช้โดยตรง (ใน__name__ == "__main__"กรณีนี้) แต่ถ้ารหัสของคุณถูกนำเข้าแล้วผู้นำเข้าจะต้องป้อนรหัสของคุณจากโมดูลหลักที่แท้จริงเพื่อหลีกเลี่ยงปัญหาการล็อคการนำเข้า

ผลข้างเคียงคือคุณลงชื่อเข้าใช้วิธีการที่สนับสนุนจุดเข้าใช้หลายจุดโดยอัตโนมัติ คุณสามารถเรียกใช้โปรแกรมของคุณโดยใช้main()เป็นจุดเริ่มต้นที่, แต่คุณไม่จำเป็นต้อง ในขณะที่setup.pyคาดว่าmain()เครื่องมืออื่น ๆ ใช้จุดเข้าใช้งานสำรอง ตัวอย่างเช่นในการเรียกใช้ไฟล์ของคุณเป็นgunicornกระบวนการคุณกำหนดฟังก์ชั่นแทนapp() main()เช่นเดียวกับsetup.py, gunicornนำเข้ารหัสของคุณเพื่อให้คุณไม่ต้องการจะทำอะไรในขณะที่มันถูกนำเข้า (เนื่องจากปัญหาล็อคนำเข้า)


3
ที่ดีในการเรียนรู้เกี่ยวกับการล็อคนำเข้า คุณช่วยอธิบายวิธีลงชื่อเข้าใช้ที่ [... ]เป็นส่วนเพิ่มเติมอีกหน่อยได้ไหม?
Wolf

1
@ Wolf: แน่นอน ฉันได้เพิ่มสองสามประโยคเกี่ยวกับวิธีการหลายจุดเข้าใช้งาน
personal_cloud

11

คำตอบนี้สำหรับโปรแกรมเมอร์ Java การเรียนรู้ Python โดยทั่วไปทุกไฟล์ Java จะมีหนึ่งคลาสสาธารณะ คุณสามารถใช้คลาสนั้นได้สองวิธี:

  1. เรียกคลาสจากไฟล์อื่น คุณเพียงแค่ต้องนำเข้ามันในโปรแกรมโทร

  2. ดำเนินการสอนแบบแยกเดี่ยวเพื่อทดสอบ

สำหรับกรณีหลังชั้นควรมีวิธีโมฆะหลักคงที่สาธารณะ () '__main__'ในหลามวัตถุประสงค์นี้มีการเสิร์ฟที่ฉลากกำหนดไว้ทั่วโลก


11

ภายใต้รหัสจะได้รับการดำเนินการถ้าโมดูลจะเรียกว่าเป็นสคริปต์if __name__ == '__main__':

เป็นตัวอย่างให้พิจารณาโมดูลต่อไปนี้my_test_module.py:

# my_test_module.py

print('This is going to be printed out, no matter what')

if __name__ == '__main__':
    print('This is going to be printed out, only if user invokes the module as a script')

ความเป็นไปได้ที่ 1: นำเข้าmy_test_module.pyในโมดูลอื่น

# main.py

import my_test_module

if __name__ == '__main__':
    print('Hello from main.py')

ตอนนี้ถ้าคุณเรียกใช้main.py:

python main.py 

>> 'This is going to be printed out, no matter what'
>> 'Hello from main.py'

โปรดทราบว่าจะดำเนินการprint()คำสั่งระดับบนสุดmy_test_moduleเท่านั้น


ความเป็นไปได้ที่สอง: เรียกmy_test_module.pyใช้เป็นสคริปต์

ตอนนี้ถ้าคุณเรียกใช้my_test_module.pyเป็นสคริปต์ Python ทั้งสองprint()ข้อความจะถูกยกเลิก

python my_test_module.py

>>> 'This is going to be printed out, no matter what'
>>> 'This is going to be printed out, only if user invokes the module as a script'

10

__name__โมดูลในหลามทุกคนมีแอตทริบิวต์ที่เรียกว่า ค่าของ__name__ แอตทริบิวต์ เมื่อโมดูลจะเรียกใช้โดยตรงเช่น__main__ python my_module.pyมิฉะนั้น (เช่นเมื่อคุณพูดimport my_module) ค่าของ__name__ คือชื่อของโมดูล

ตัวอย่างเล็ก ๆ ที่จะอธิบายในระยะสั้น

#Script test.py

apple = 42

def hello_world():
    print("I am inside hello_world")

if __name__ == "__main__":
    print("Value of __name__ is: ", __name__)
    print("Going to call hello_world")
    hello_world()

เราสามารถดำเนินการได้โดยตรงในรูปแบบ

python test.py  

เอาท์พุต

Value of __name__ is: __main__
Going to call hello_world
I am inside hello_world

ตอนนี้สมมติว่าเราเรียกสคริปต์ด้านบนจากสคริปต์อื่น

#script external_calling.py

import test
print(test.apple)
test.hello_world()

print(test.__name__)

เมื่อคุณดำเนินการนี้

python external_calling.py

เอาท์พุต

42
I am inside hello_world
test

ดังนั้นข้างต้นเป็นตัวอธิบายว่าเมื่อคุณเรียกการทดสอบจากสคริปต์อื่น ๆ ถ้าวง__name__ในtest.pyจะไม่ดำเนินการ


6

หากไฟล์. py นี้นำเข้าโดยไฟล์. py อื่น ๆ รหัสภายใต้ "คำสั่ง if" จะไม่ถูกเรียกใช้งาน

หาก. py นี้ทำงานโดยใช้python this_py.pyเชลล์หรือคลิกสองครั้งใน Windows รหัสภายใต้ "คำสั่ง if" จะถูกดำเนินการ

มันมักจะเขียนสำหรับการทดสอบ


6

หากล่ามไพ ธ อนกำลังใช้งานโมดูลเฉพาะ__name__ตัวแปรกลางจะมีค่า"__main__"

  def a():
      print("a")
  def b():
      print("b")

  if __name__ == "__main__": 

          print ("you can see me" )
          a()
  else: 

          print ("You can't see me")
          b()

เมื่อคุณพิมพ์สคริปต์นี้คุณจะเห็นฉัน

a

หากคุณนำเข้าไฟล์นี้ว่า A ไปยังไฟล์ B และดำเนินการไฟล์ B จากนั้นif __name__ == "__main__"ในไฟล์ A กลายเป็นเท็จดังนั้นมันพิมพ์ คุณจะไม่เห็นฉัน


5

คำตอบทั้งหมดอธิบายการทำงานได้ค่อนข้างมาก แต่ฉันจะให้ตัวอย่างหนึ่งของการใช้งานซึ่งอาจช่วยล้างแนวคิดเพิ่มเติม

สมมติว่าคุณมีไฟล์ Python สองไฟล์คือ a.py และ b.py ตอนนี้ a.py นำเข้า b.py เราเรียกใช้ไฟล์ a.py โดยเรียกใช้รหัส "import b.py" ก่อน ก่อนที่โค้ด a.py ที่เหลือจะทำงานรหัสในไฟล์ b.py จะต้องทำงานอย่างสมบูรณ์

ในรหัส b.py มีรหัสบางส่วนที่ไม่รวมอยู่ในไฟล์นั้น b.py และเราไม่ต้องการไฟล์อื่นใด (นอกเหนือจากไฟล์ b.py) ที่นำเข้าไฟล์ b.py เพื่อเรียกใช้

ดังนั้นนี่คือสิ่งที่รหัสตรวจสอบนี้ หากเป็นไฟล์หลัก (เช่น b.py) ใช้รหัสซึ่งในกรณีนี้ไม่ใช่ (a.py เป็นไฟล์หลักทำงานอยู่) ดังนั้นจะมีเพียงรหัสเท่านั้นที่ได้รับการดำเนินการ


4

สร้างไฟล์a.py :

print(__name__) # It will print out __main__

__name__จะเท่ากับเสมอ__main__เมื่อใดก็ตามที่ไฟล์นั้นทำงานโดยตรงแสดงว่าไฟล์นี้เป็นไฟล์หลัก

สร้างไฟล์อื่นb.pyในไดเรกทอรีเดียวกัน:

import a  # Prints a

เรียกใช้ มันจะพิมพ์คือชื่อของไฟล์ที่จะนำเข้า

ดังนั้นเพื่อแสดงพฤติกรรมที่แตกต่างกันสองอย่างของไฟล์เดียวกันนี่เป็นเคล็ดลับที่ใช้กันโดยทั่วไป:

# Code to be run when imported into another python file

if __name__ == '__main__':
    # Code to be run only when run directly

4

ถ้าname == ' main ':

เราดูว่า__name__ == '__main__':ค่อนข้างบ่อย

มันจะตรวจสอบว่าโมดูลจะถูกนำเข้าหรือไม่

กล่าวอีกนัยหนึ่งรหัสภายในifบล็อกจะถูกดำเนินการเฉพาะเมื่อโค้ดทำงานโดยตรง นี่หมายถึงdirectlynot imported

มาดูกันว่ามันใช้งานอะไรโดยใช้โค้ดง่ายๆที่พิมพ์ชื่อของโมดูล:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

หากเรารันรหัสโดยตรงผ่านpython test.pyชื่อโมดูลคือ__main__:

call test()
test module name=__main__

4

เพียงแค่เป็นจุดเริ่มต้นในการเรียกใช้ไฟล์เช่นmainฟังก์ชั่นในภาษาการเขียนโปรแกรมC


8
คำตอบนี้ทำให้สมมุติว่า OP (หรือผู้ใช้ที่มีคำถามคล้ายกัน) ทั้งคู่คุ้นเคยกับC และรู้ว่าจุดเข้าคืออะไร
arredond

1
คำตอบนี้ยังถือว่าไม่มีรหัส (นอกเหนือจากคำจำกัดความที่ไม่มีผลข้างเคียง) เกิดขึ้นก่อนการif __name__ == "__main__"บล็อก ในทางเทคนิคด้านบนของสคริปต์ดำเนินการเป็นจุดเริ่มต้นของโปรแกรม
ชาร์ลีฮาร์ดิง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.