Nếu __name__ == thì __main__ thì: làm gì?


6065

Cho các mã sau đây, if __name__ == "__main__":làm gì?

# 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__":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.
carloswm85

2
@ carloswm85 Điều đó không đúng.
Giorgos Myrianthous

Câu trả lời:


6644

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.pytệ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

  1. Nó in chuỗi "before import"(không có dấu ngoặc kép).

  2. Nó tải mathmô-đ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 mathbằ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")
  1. Nó in chuỗi "before functionA".

  2. Nó thực thi defkhố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.

  3. Nó in chuỗi "before functionB".

  4. Nó thực thi defkhố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.

  5. Nó in chuỗi "before __name__ guard".

Chỉ khi mô-đun của bạn là chương trình chính

  1. 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""Function B 10.0".

Chỉ khi mô-đun của bạn được nhập bởi người khác

  1. ( 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 ifcâu lệnh.

Luôn luôn

  1. 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 .pytệ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 .pycá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.pytrê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")

14
Vì tò mò: Điều gì xảy ra nếu tôi chạy subprocess.run('foo_bar.py')trong một kịch bản python? Tôi cho rằng điều đó foo_barsẽ được bắt đầu __name__ = '__main__'giống như khi tôi hoàn foo_bar.pythành thủ công cmd. Có phải vậy không? Đưa tài khoản Trả lời của @MrFooz vào tài khoản sẽ không có vấn đề gì khi thực hiện việc này và có nhiều mô-đun "chính" tại một thời điểm tôi muốn. Ngay cả việc thay đổi __name__giá trị hoặc có một số trường hợp tạo độc lập (hoặc các trường hợp tạo ra bằng cách subprocess) tương tác với nhau cũng nên hoạt động như bình thường đối với Python. Tôi có bỏ lỡ điều gì không?
hajef

12
@hajef Bạn đúng về cách mọi thứ sẽ làm việc với subprocess.run. Điều đó nói rằng, một cách tốt hơn để chia sẻ mã giữa các tập lệnh là tạo các mô-đun và để các tập lệnh gọi các mô-đun được chia sẻ thay vì gọi nhau là tập lệnh. Thật khó để gỡ lỗi subprocess.runcác cuộc gọi vì hầu hết các trình gỡ lỗi không vượt qua các ranh giới của quy trình, nó có thể thêm chi phí hệ thống không tầm thường để tạo và phá hủy các quy trình bổ sung, v.v.
Ông Fooz

4
Tôi có một nghi ngờ trong ví dụ về foo2.py trong phần thực phẩm cho phần suy nghĩ. Làm thế nào từ chức năng nhập khẩu foo2.pyB làm gì? Theo quan điểm của tôi, nó chỉ nhập foo2.py từ functionB
user471651

1
@MrFooz Tôi chưa bao giờ có ý định làm bất cứ điều gì như thế này xD Nó xuất hiện trong đầu tôi và tôi nhận ra rằng thật kỳ lạ khi có thể giúp đỡ ppl. bao bọc tâm trí của họ xung quanh loại công cụ này. @ user471651 Tại sao nên from foo2 import functionBnhập foo2 từ functionB? Đó là một sự mâu thuẫn về ngữ nghĩa. from module import methodnhập khẩu phương thức từ modul.
hajef

2
Một trong những mô-đun có thể nhập mã của bạn multiprocessing, đặc biệt là làm cho thử nghiệm này cần thiết trên Windows.
Yann Vernier

1801

Khi tập lệnh của bạn được chạy bằng cách chuyển nó dưới dạng lệnh cho trình thông dịch Python,

python myscript.py

tất cả các mã ở mức thụt lề 0 được thực thi. Các hàm và các lớp được định nghĩa là, tốt, được xác định, nhưng không có mã nào của chúng được chạy. Không giống như các ngôn ngữ khác, không có main()chức năng nào được chạy tự động - main()chức năng này hoàn toàn là tất cả các mã ở cấp cao nhất.

Trong trường hợp này, mã cấp cao nhất là một ifkhối. __name__là một biến tích hợp để đánh giá tên của mô-đun hiện tại. Tuy nhiên, nếu một mô-đun đang được chạy trực tiếp (như ở myscript.pytrên), thì __name__thay vào đó được đặt thành chuỗi "__main__". Do đó, bạn có thể kiểm tra xem tập lệnh của mình đang được chạy trực tiếp hay đang được nhập bởi một thứ khác bằng cách kiểm tra

if __name__ == "__main__":
    ...

Nếu tập lệnh của bạn đang được nhập vào một mô-đun khác, các định nghĩa lớp và chức năng khác nhau của nó sẽ được nhập và mã cấp cao nhất của nó sẽ được thực thi, nhưng mã trong phần thân của ifmệnh đề trên sẽ không được chạy vì điều kiện là không gặp Để làm ví dụ cơ bản, hãy xem xét hai tập lệnh sau:

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

Bây giờ, nếu bạn gọi trình thông dịch là

python one.py

Đầu ra sẽ là

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

Nếu bạn chạy two.pythay thế:

python two.py

Bạn lấy

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

Vì vậy, khi mô-đun oneđược tải, nó __name__bằng "one"thay vì "__main__".


Câu trả lời tuyệt vời, đây là câu trả lời rõ ràng nhất theo ý kiến ​​của tôi. +1!
TheTechRobo36414519

+1 cho cách nghĩ đó: dòng thụt đầu tiên chỉ được chạy lúc đầu, cho đến khi bạn chạy các chức năng trên dòng đầu tiên đó
Elijah Mock

719

Giải thích đơn giản nhất cho __name__biến (imho) là như sau:

Tạo các tập tin sau.

# a.py
import b

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

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

Chạy chúng sẽ giúp bạn có đầu ra này:

$ python a.py
Hello World from b!

Như bạn có thể thấy, khi một mô-đun được nhập, Python đặt globals()['__name__']trong mô-đun này thành tên của mô-đun. Ngoài ra, khi nhập tất cả các mã trong mô-đun đang được chạy. Vì ifcâu lệnh ước tính cho Falsephần này không được thực thi.

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

Như bạn có thể thấy, khi một tệp được thực thi, Python sẽ đặt globals()['__name__']trong tệp này thành "__main__". Lần này, ifcâu lệnh ước tính Truevà đang được chạy.


513

Làm gì if __name__ == "__main__":?

Để phác thảo những điều cơ bản:

  • Biến toàn cục, __name__trong mô-đun là điểm vào chương trình của bạn, là '__main__'. Mặt khác, đó là tên bạn nhập mô-đun bằng.

  • Vì vậy, mã dưới ifkhối sẽ chỉ chạy nếu mô-đun là điểm vào chương trình của bạn.

  • Nó cho phép mã trong mô-đun có thể được nhập bởi các mô-đun khác mà không cần thực thi khối mã bên dưới khi nhập.


Tại sao chúng ta cần điều này?

Phát triển và kiểm tra mã của bạn

Giả sử bạn đang viết tập lệnh Python được thiết kế để sử dụng làm mô-đun:

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

Bạn có thể kiểm tra mô-đun bằng cách thêm lệnh gọi này của hàm vào dưới cùng:

do_important()

và chạy nó (trên dấu nhắc lệnh) với nội dung như:

~$ python important.py

Vấn đề

Tuy nhiên, nếu bạn muốn nhập mô-đun sang tập lệnh khác:

import important

Khi nhập, do_importanthàm sẽ được gọi, vì vậy bạn có thể nhận xét cuộc gọi hàm của bạn do_important(), ở phía dưới.

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

Và sau đó bạn sẽ phải nhớ liệu bạn có nhận xét cuộc gọi chức năng kiểm tra của mình hay không. Và sự phức tạp thêm này có nghĩa là bạn có khả năng sẽ quên, làm cho quá trình phát triển của bạn trở nên rắc rối hơn.

Một cách tốt hơn

Các __name__ điểm biến để không gian tên bất cứ nơi nào thông dịch Python sẽ xảy ra là vào lúc này.

Bên trong một mô-đun nhập khẩu, đó là tên của mô-đun đó.

Nhưng bên trong mô-đun chính (hoặc phiên Python tương tác, tức là Đọc, Eval, Vòng lặp in hoặc REPL của trình thông dịch), bạn đang chạy mọi thứ từ nó "__main__".

Vì vậy, nếu bạn kiểm tra trước khi thực hiện:

if __name__ == "__main__":
    do_important()

Với cách trên, mã của bạn sẽ chỉ thực thi khi bạn chạy nó dưới dạng mô-đun chính (hoặc cố ý gọi nó từ tập lệnh khác).

Một cách thậm chí tốt hơn

Mặc dù vậy, có một cách Pythonic để cải thiện điều này.

Điều gì xảy ra nếu chúng ta muốn chạy quy trình kinh doanh này từ bên ngoài mô-đun?

Nếu chúng tôi đặt mã chúng tôi muốn thực hiện khi chúng tôi phát triển và thử nghiệm trong một chức năng như thế này và sau đó kiểm tra '__main__'ngay sau đó:

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()

Bây giờ chúng ta có một chức năng cuối cùng cho phần cuối của mô-đun sẽ chạy nếu chúng ta chạy mô-đun làm mô-đun chính.

Nó sẽ cho phép mô-đun và các chức năng và lớp của nó được nhập vào các tập lệnh khác mà không chạy mainchức năng, và cũng sẽ cho phép mô-đun (và các chức năng và lớp của nó) được gọi khi chạy từ một '__main__'mô-đun khác , tức là

import important
important.main()

Thành ngữ này cũng có thể được tìm thấy trong tài liệu Python trong phần giải thích về __main__mô-đun. Văn bản đó nêu rõ:

Mô-đun này biểu thị phạm vi (ẩn danh) trong đó chương trình chính của trình thông dịch thực thi - các lệnh được đọc từ đầu vào tiêu chuẩn, từ tệp tập lệnh hoặc từ dấu nhắc tương tác. Chính môi trường này trong đó tập lệnh có điều kiện thành ngữ, tập lệnh stanza, có thể tạo ra một tập lệnh:

if __name__ == '__main__':
    main()

125

if __name__ == "__main__"là phần chạy khi tập lệnh được chạy từ (nói) dòng lệnh sử dụng lệnh như thế nào python myscript.py.


2
Tại sao một tệp helloworld.pychỉ print("hello world")trong nó có thể chạy bằng lệnh python helloworld.pyngay cả khi không có if __name__ == "__main__"?
hi15

83

Không gì if __name__ == "__main__":làm gì?

__name__là một biến toàn cục (trong Python, toàn cầu thực sự có nghĩa là ở cấp độ mô-đun ) tồn tại trong tất cả các không gian tên. Nó thường là tên của mô-đun (dưới dạng một strloại).

Tuy nhiên, là trường hợp đặc biệt duy nhất, trong bất kỳ quy trình Python nào bạn chạy, như trong mycode.py:

python mycode.py

không gian tên toàn cầu ẩn danh được gán giá trị của '__main__'__name__.

Do đó, bao gồm các dòng cuối cùng

if __name__ == '__main__':
    main()
  • ở cuối tập lệnh mycode.py của bạn,
  • khi nó là mô đun điểm chính, điểm đầu vào được chạy bởi một quy trình Python,

sẽ khiến mainchức năng được xác định duy nhất của tập lệnh của bạn chạy.

Một lợi ích khác của việc sử dụng cấu trúc này: bạn cũng có thể nhập mã của mình dưới dạng một mô-đun trong một tập lệnh khác và sau đó chạy chức năng chính nếu và khi chương trình của bạn quyết định:

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

72

Có rất nhiều cách khác nhau ở đây về cơ chế của mã được đề cập, "Làm thế nào", nhưng đối với tôi không có ý nghĩa nào cho đến khi tôi hiểu "Tại sao". Điều này sẽ đặc biệt hữu ích cho các lập trình viên mới.

Lấy tệp "ab.py":

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

Và một tập tin thứ hai "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()

Mã này thực sự đang làm gì?

Khi bạn thực thi xy.py, bạn import ab. Câu lệnh nhập chạy mô-đun ngay lập tức khi nhập, do đó ab, các hoạt động được thực thi trước phần còn lại của xy. Sau khi kết thúc ab, nó tiếp tục vớixy .

Trình thông dịch theo dõi các kịch bản đang chạy với __name__. Khi bạn chạy một tập lệnh - bất kể bạn đã đặt tên cho nó là gì - trình thông dịch gọi nó "__main__", biến nó thành tập lệnh chính hoặc 'nhà' được trả về sau khi chạy tập lệnh bên ngoài.

Bất kỳ tập lệnh nào khác được gọi từ "__main__"tập lệnh này đều được gán tên tệp của nó là __name__(ví dụ __name__ == "ab.py":). Do đó, dòngif __name__ == "__main__": là thử nghiệm của trình thông dịch để xác định xem nó có phiên dịch / phân tích cú pháp 'nhà' ban đầu được thực hiện hay không, hoặc nếu nó tạm thời nhìn trộm vào một tập lệnh (bên ngoài) khác. Điều này cho phép lập trình viên linh hoạt để kịch bản hoạt động khác đi nếu nó được thực thi trực tiếp so với được gọi bên ngoài.

Hãy xem qua đoạn mã trên để hiểu những gì đang xảy ra, trước tiên tập trung vào các dòng không được cấp phép và thứ tự chúng xuất hiện trong các tập lệnh. Hãy nhớ rằng chức năng - hoặc def- các khối không tự làm bất cứ điều gì cho đến khi chúng được gọi. Người phiên dịch có thể nói gì nếu tự lẩm bẩm:

  • Mở xy.py dưới dạng tệp 'nhà'; gọi nó "__main__"trong __name__biến.
  • Nhập và mở tệp với __name__ == "ab.py".
  • Ồ, một chức năng. Tôi sẽ nhớ điều đó.
  • Ok, chức năng a(); Tôi chỉ học được rằng. In ' Một chức năng trong tập tin ab '.
  • Phần cuối của tập tin; trở lại "__main__"!
  • Ồ, một chức năng. Tôi sẽ nhớ điều đó.
  • Một số khác.
  • Chức năng x(); ok, in ' tác vụ ngoại vi: có thể hữu ích trong các dự án khác '.
  • Đây là gì? Một iftuyên bố. Chà, điều kiện đã được đáp ứng (biến __name__đã được đặt thành "__main__"), vì vậy tôi sẽ nhập main()hàm và in ' hàm chính: đây là nơi hành động '.

Hai dòng dưới cùng có nghĩa là: "Nếu đây là tập lệnh "__main__"hoặc 'home', hãy thực thi chức năng được gọi là main()". Đó là lý do tại sao bạn sẽ thấy một def main():khối trên cùng, chứa dòng chính của chức năng của tập lệnh.

Tại sao phải thực hiện điều này?

Hãy nhớ những gì tôi đã nói trước đó về báo cáo nhập khẩu? Khi bạn nhập một mô-đun, nó không chỉ 'nhận ra' nó và chờ hướng dẫn thêm - nó thực sự chạy tất cả các hoạt động thực thi có trong tập lệnh. Vì vậy, việc đưa tập lệnh của tập lệnh vào main()chức năng cách ly nó một cách hiệu quả, đặt tập lệnh một cách hiệu quả để nó không chạy ngay lập tức khi được tập lệnh khác nhập vào.

Một lần nữa, sẽ có ngoại lệ, nhưng thực tế phổ biến là main()thường không được gọi là bên ngoài. Vì vậy, bạn có thể tự hỏi một điều nữa: nếu chúng ta không gọimain() , tại sao chúng ta lại gọi kịch bản? Đó là bởi vì nhiều người cấu trúc các tập lệnh của họ với các hàm độc lập được xây dựng để chạy độc lập với phần còn lại của mã trong tệp. Sau đó, họ được gọi ở một nơi khác trong cơ thể của kịch bản. Điều này đưa tôi đến điều này:

Nhưng mã hoạt động mà không có nó

Vâng đúng vậy. Các hàm riêng biệt này có thể được gọi từ một tập lệnh nội tuyến không có trong main()hàm. Nếu bạn đã quen (như tôi, trong giai đoạn đầu học lập trình) để xây dựng các tập lệnh nội tuyến thực hiện chính xác những gì bạn cần, và bạn sẽ cố gắng tìm ra lại nếu bạn cần thao tác đó một lần nữa .. tốt, bạn không quen với loại cấu trúc bên trong này cho mã của mình, vì việc xây dựng nó phức tạp hơn và nó không trực quan để đọc.

Nhưng đó là một tập lệnh có thể không có chức năng của nó được gọi là bên ngoài, bởi vì nếu nó được thực hiện, nó sẽ ngay lập tức bắt đầu tính toán và gán các biến. Và rất có thể là nếu bạn đang cố gắng sử dụng lại một hàm, tập lệnh mới của bạn có liên quan chặt chẽ với hàm cũ sẽ có các biến xung đột.

Khi tách các chức năng độc lập, bạn có khả năng sử dụng lại công việc trước đó bằng cách gọi chúng vào một tập lệnh khác. Ví dụ: "example.py" có thể nhập "xy.py" và gọi x(), sử dụng chức năng 'x' từ "xy.py". (Có thể nó viết hoa từ thứ ba của một chuỗi văn bản nhất định; tạo một mảng NumPy từ một danh sách các số và bình phương chúng; hoặc tách ra một bề mặt 3D. Khả năng là vô hạn.)

(Bên cạnh đó, câu hỏi này chứa câu trả lời của @kindall cuối cùng đã giúp tôi hiểu - tại sao, không phải như thế nào. Thật không may, nó được đánh dấu là một bản sao của câu hỏi này , mà tôi nghĩ là một sai lầm.)


52

Khi có một số câu lệnh nhất định trong mô-đun của chúng tôi ( M.py) chúng tôi muốn được thực thi khi nó sẽ chạy dưới dạng chính (không được nhập), chúng tôi có thể đặt các câu lệnh đó (trường hợp thử nghiệm, câu lệnh in) trong ifkhối này .

Theo mặc định (khi mô-đun chạy là chính, không được nhập), __name__biến được đặt thành "__main__"và khi được nhập, __name__biến sẽ nhận một giá trị khác, rất có thể là tên của mô-đun ( 'M'). Điều này rất hữu ích trong việc chạy các biến thể khác nhau của các mô-đun với nhau và tách biệt các câu lệnh đầu vào và đầu ra cụ thể của chúng và nếu có bất kỳ trường hợp thử nghiệm nào.

Nói tóm lại , hãy sử dụng if __name__ == "main"khối '' này để ngăn không cho mã (nhất định) chạy khi mô-đun được nhập.


43

Nói một cách đơn giản, __name__là một biến được xác định cho mỗi tập lệnh xác định xem tập lệnh đang được chạy dưới dạng mô-đun chính hay nó đang được chạy dưới dạng mô-đun nhập.

Vì vậy, nếu chúng ta có hai kịch bản;

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

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

Đầu ra từ việc thực thi script1 là

Script 1's name: __main__

Và đầu ra từ việc thực thi script2 là:

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

Như bạn có thể thấy, __name__cho chúng tôi biết mã nào là mô-đun 'chính'. Điều này thật tuyệt vời, vì bạn chỉ có thể viết mã và không phải lo lắng về các vấn đề cấu trúc như trong C / C ++, trong đó, nếu một tệp không thực hiện chức năng 'chính' thì nó không thể được biên dịch thành tệp thực thi và nếu có, sau đó nó không thể được sử dụng như một thư viện.

Giả sử bạn viết một tập lệnh Python làm một cái gì đó tuyệt vời và bạn thực hiện một khối các hàm hữu ích cho các mục đích khác. Nếu tôi muốn sử dụng chúng, tôi chỉ có thể nhập tập lệnh của bạn và sử dụng chúng mà không cần thực thi chương trình của bạn (với điều kiện là mã của bạn chỉ thực thi trong if __name__ == "__main__":ngữ cảnh). Trong khi đó trong C / C ++, bạn sẽ phải chia các phần đó thành một mô-đun riêng biệt bao gồm tệp. Hình ảnh tình huống dưới đây;

Nhập khẩu phức tạp trong C

Các mũi tên là liên kết nhập khẩu. Đối với ba mô-đun, mỗi mô-đun cố gắng bao gồm mã mô-đun trước đó, có sáu tệp (chín, đếm các tệp thực hiện) và năm liên kết. Điều này gây khó khăn cho việc đưa mã khác vào dự án C trừ khi nó được biên dịch cụ thể dưới dạng thư viện. Bây giờ hãy hình dung nó cho Python:

Nhập khẩu thanh lịch trong Python

Bạn viết một mô-đun và nếu ai đó muốn sử dụng mã của bạn, họ chỉ cần nhập nó và __name__biến có thể giúp tách phần thực thi của chương trình khỏi phần thư viện.


2
Hình minh họa C / C ++ là sai: 3 lần cùng tên đơn vị ( file1 ).
Sói

40

Hãy nhìn vào câu trả lời một cách trừu tượng hơn:

Giả sử chúng ta có mã này trong x.py:

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

Khối A và B được chạy khi chúng ta đang chạy x.py.

Nhưng chỉ khối A (chứ không phải B) được chạy khi chúng tôi đang chạy một mô-đun khác, y.py ví dụ, trong đó x.pyđược nhập và mã được chạy từ đó (như khi một hàm trong x.pyđược gọi từ y.py).


1
Tôi không thể chỉnh sửa bài đăng (tối thiểu 6 ký tự nếu cần thay đổi). Dòng 14 có 'xy' thay vì 'x.py'.
Luôn luôn học

35

Khi bạn chạy Python tương tác, __name__biến cục bộ được gán một giá trị là __main__. Tương tự, khi bạn thực thi một mô-đun Python từ dòng lệnh, thay vì nhập nó vào một mô-đun khác, __name__thuộc tính của nó được gán một giá trị __main__, thay vì tên thực của mô-đun. Theo cách này, các mô-đun có thể xem xét __name__giá trị của chính chúng để tự xác định cách chúng đang được sử dụng, cho dù là hỗ trợ cho chương trình khác hoặc là ứng dụng chính được thực thi từ dòng lệnh. Do đó, thành ngữ sau khá phổ biến trong các mô-đun 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

Xem xét:

if __name__ == "__main__":
    main()

Nó kiểm tra xem __name__thuộc tính của tập lệnh Python là "__main__". Nói cách khác, nếu chính chương trình được thực thi, thuộc tính sẽ là __main__, do đó chương trình sẽ được thực thi (trong trường hợp này là main()hàm).

Tuy nhiên, nếu tập lệnh Python của bạn được sử dụng bởi một mô-đun, bất kỳ mã nào bên ngoài ifcâu lệnh sẽ được thực thi, do đó, if \__name__ == "\__main__"chỉ được sử dụng để kiểm tra xem chương trình có được sử dụng làm mô-đun hay không và do đó quyết định có chạy mã không.


có vẻ như đã quá lâu để viết câu trả lời sáng +1
snr

27

Trước khi giải thích bất cứ điều gì về if __name__ == '__main__'điều quan trọng là phải hiểu những gì __name__và những gì nó làm.

__name__

__name__là một DunderAlias - có thể được coi là một biến toàn cục (có thể truy cập từ các mô-đun) và hoạt động theo cách tương tự global.

Nó là một chuỗi (toàn cầu như đã đề cập ở trên) như được chỉ ra bởi type(__name__)(năng suất <class 'str'>) và là một tiêu chuẩn sẵn có cho cả hai phiên bản Python 3Python 2 .

Ở đâu:

Nó không chỉ có thể được sử dụng trong các tập lệnh mà còn có thể được tìm thấy trong cả trình thông dịch và các mô-đun / gói.

Thông dịch viên:

>>> print(__name__)
__main__
>>>

Kịch bản:

test_file.py :

print(__name__)

Kết quả là __main__

Mô-đun hoặc gói:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

Kết quả là somefile

Lưu ý rằng khi được sử dụng trong một gói hoặc mô-đun, __name__sẽ lấy tên của tệp. Đường dẫn của mô-đun thực tế hoặc đường dẫn gói không được đưa ra, nhưng có DunderAlias ​​riêng __file__, cho phép thực hiện điều này.

Bạn sẽ thấy rằng, ở đâu __name__, nơi mà tệp chính (hoặc chương trình) sẽ luôn trả về __main__và nếu đó là mô-đun / gói hoặc bất cứ thứ gì đang chạy khỏi một tập lệnh Python khác, sẽ trả về tên của tệp nơi nó có nguồn gốc từ.

Thực hành:

Là một biến có nghĩa là giá trị của nó có thể được ghi đè ("có thể" không có nghĩa là "nên"), ghi đè lên giá trị của__name__ ý chí sẽ dẫn đến việc thiếu khả năng đọc. Vì vậy, không làm điều đó, vì bất kỳ lý do. Nếu bạn cần một biến xác định một biến mới.

Nó luôn luôn giả định rằng giá trị của __name____main__hoặc tên của tập tin. Một lần nữa thay đổi giá trị mặc định này sẽ gây ra nhiều nhầm lẫn rằng nó sẽ hoạt động tốt, gây ra các vấn đề tiếp theo.

thí dụ:

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

Nó được coi là thực hành tốt nói chung để bao gồm if __name__ == '__main__'trong các kịch bản.

Bây giờ để trả lời if __name__ == '__main__':

Bây giờ chúng ta biết hành vi của __name__mọi thứ trở nên rõ ràng hơn:

An iflà một câu lệnh điều khiển luồng chứa khối mã sẽ thực thi nếu giá trị đã cho là đúng. Chúng tôi đã thấy rằng __name__có thể lấy __main__hoặc tên tệp mà nó đã được nhập từ.

Điều này có nghĩa là nếu __name__bằng __main__thì tệp phải là tệp chính và thực sự phải đang chạy (hoặc đó là trình thông dịch), không phải là mô-đun hoặc gói được nhập vào tập lệnh.

Nếu thực sự __name__có giá trị __main__thì bất cứ thứ gì trong khối mã đó sẽ thực thi.

Điều này cho chúng ta biết rằng nếu tệp đang chạy là tệp chính (hoặc bạn đang chạy trực tiếp từ trình thông dịch) thì điều kiện đó phải được thực thi. Nếu nó là một gói thì không nên và giá trị sẽ không như vậy __main__.

Mô-đun:

__name__ cũng có thể được sử dụng trong các mô-đun để xác định tên của một mô-đun

Các biến thể:

Cũng có thể làm những việc khác, ít phổ biến hơn nhưng hữu ích hơn __name__, một số điều tôi sẽ trình bày ở đây:

Chỉ thực hiện nếu tệp là một mô-đun hoặc gói:

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

Chạy một điều kiện nếu tệp là chính và một điều kiện khác nếu không phải là:

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

Bạn cũng có thể sử dụng nó để cung cấp các chức năng / tiện ích trợ giúp có thể chạy được trên các gói và mô-đun mà không cần sử dụng các thư viện phức tạp.

Nó cũng cho phép các mô-đun được chạy từ dòng lệnh dưới dạng các tập lệnh chính, cũng có thể rất hữu ích.


25

Tôi nghĩ tốt nhất là phá vỡ câu trả lời sâu sắc và bằng những từ đơn giản:

__name__: Mỗi mô-đun trong Python có một thuộc tính đặc biệt được gọi là __name__. Nó là một biến tích hợp trả về tên của mô-đun.

__main__: Giống như các ngôn ngữ lập trình khác, Python cũng có một điểm nhập thực thi, tức là chính. '__main__' là tên của phạm vi mà mã cấp cao nhất thực thi . Về cơ bản, bạn có hai cách sử dụng mô-đun Python: Chạy trực tiếp dưới dạng tập lệnh hoặc nhập mô-đun. Khi một mô-đun được chạy như một tập lệnh, nó __name__được đặt thành __main__.

Do đó, giá trị của __name__thuộc tính được đặt thành __main__khi mô đun được chạy như chương trình chính. Mặt khác, giá trị của __name__ được đặt để chứa tên của mô-đun.


23

Nó là một đặc biệt khi một tệp Python được gọi từ dòng lệnh. Điều này thường được sử dụng để gọi hàm "main ()" hoặc thực thi mã khởi động thích hợp khác, chẳng hạn như xử lý đối số dòng lệnh.

Nó có thể được viết theo nhiều cách. Cái khác là:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

Tôi không nói rằng bạn nên sử dụng điều này trong mã sản xuất, nhưng nó dùng để minh họa rằng không có gì "kỳ diệu" về if __name__ == '__main__'. Đây là một quy ước tốt để gọi một hàm chính trong các tệp Python.


7
Tôi sẽ xem xét hình thức xấu này vì bạn 1) dựa vào tác dụng phụ và 2) lạm dụng and. andđược sử dụng để kiểm tra xem hai câu lệnh boolean đều đúng. Vì bạn không quan tâm đến kết quả của and, một iftuyên bố truyền đạt rõ ràng hơn ý định của bạn.
jpmc26

8
Bỏ qua câu hỏi liệu khai thác hành vi ngắn mạch của các nhà khai thác boolean như một cơ chế kiểm soát dòng chảy có phải là phong cách xấu hay không, vấn đề lớn hơn là điều này hoàn toàn không trả lời câu hỏi .
Đánh dấu Amery

@MarkAmery haha, sheesh, bây giờ thì có. 😊
Hợp đồng GS Falken vi phạm

19

Có một số biến mà hệ thống (trình thông dịch Python) cung cấp cho các tệp nguồn (mô-đun). Bạn có thể nhận các giá trị của chúng bất cứ lúc nào bạn muốn, vì vậy, hãy để chúng tôi tập trung vào biến / thuộc tính __name__ :

Khi Python tải một tệp mã nguồn, nó sẽ thực thi tất cả các mã được tìm thấy trong đó. (Lưu ý rằng nó không gọi tất cả các phương thức và hàm được định nghĩa trong tệp, nhưng nó xác định chúng.)

Trước khi trình thông dịch thực thi tệp mã nguồn, nó xác định một vài biến đặc biệt cho tệp đó; __Tên__ là một trong những biến đặc biệt mà Python tự động định nghĩa cho mỗi tệp mã nguồn.

Nếu Python đang tải tệp mã nguồn này làm chương trình chính (tức là tệp bạn chạy), thì nó sẽ đặt biến __name__ đặc biệt cho tệp này có giá trị "__main__" .

Nếu điều này đang được nhập từ một mô-đun khác, __name__ sẽ được đặt thành tên của mô-đun đó.

Vì vậy, trong ví dụ của bạn một phần:

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

có nghĩa là khối mã:

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

sẽ chỉ được thực hiện khi bạn chạy mô-đun trực tiếp; khối mã sẽ không thực thi nếu một mô-đun khác đang gọi / nhập nó bởi vì giá trị của __name__ sẽ không bằng " chính " trong trường hợp cụ thể đó.

Hy vọng điều này sẽ giúp ra.


17

if __name__ == "__main__": về cơ bản là môi trường tập lệnh cấp cao nhất và nó chỉ định trình thông dịch rằng ('Tôi có mức ưu tiên cao nhất được thực thi trước').

'__main__'là tên của phạm vi mà mã cấp cao nhất thực thi. Một mô-đun __name__được đặt bằng với '__main__'khi đọc từ đầu vào tiêu chuẩn, tập lệnh hoặc từ dấu nhắc tương tác.

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

17

Tôi đã đọc rất nhiều trong suốt câu trả lời trên trang này. Tôi sẽ nói, nếu bạn biết điều đó, chắc chắn bạn sẽ hiểu những câu trả lời đó, nếu không, bạn vẫn còn bối rối.

Để ngắn gọn, bạn cần biết một số điểm:

  1. import a hành động thực sự chạy tất cả những gì có thể được chạy trong "a"

  2. Vì điểm 1, bạn có thể không muốn mọi thứ được chạy trong "a" khi nhập nó

  3. Để giải quyết vấn đề ở điểm 2, python cho phép bạn đặt kiểm tra điều kiện

  4. __name__là một biến ẩn trong tất cả các .pymô-đun; khi a.pyđược nhập, giá trị __name__của a.pymô-đun được đặt thành tên tệp " a"; khi a.pyđược chạy trực tiếp bằng cách sử dụng " python a.py", có nghĩa a.pylà điểm vào, thì giá trị __name__của a.pymô-đun được đặt thành một chuỗi__main__

  5. Dựa trên cơ chế làm thế nào python thiết lập biến __name__cho mỗi mô-đun, bạn có biết làm thế nào để đạt được điểm 3 không? Câu trả lời khá dễ, phải không? Đặt một điều kiện if : if __name__ == "__main__": ...; bạn thậm chí có thể đặt nếu __name__ == "a"tùy thuộc vào nhu cầu chức năng của bạn

Điều quan trọng mà trăn đặc biệt ở điểm 4! Phần còn lại chỉ là logic cơ bản.


1
Vâng, điểm 1 là rất quan trọng để hiểu. Từ đó, sự cần thiết cho cơ chế này trở nên rõ ràng.
Eureka

16

Xem xét:

print __name__

Đầu ra cho ở trên là __main__.

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

Tuyên bố trên là đúng và in "phương pháp trực tiếp" . Giả sử nếu họ đã nhập lớp này trong một lớp khác thì nó không in "phương thức trực tiếp" bởi vì, trong khi nhập, nó sẽ được đặt __name__ equal to "first model name".


14

Bạn có thể làm cho tập tin có thể sử dụng như một tập lệnh cũng như một mô-đun có thể nhập .

fibo.py (một mô-đun có tên 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]))

Tham khảo: https://docs.python.org/3.5/tutorial/modules.html


14

Lý giải cho việc

if __name__ == "__main__":
    main()

chủ yếu là để tránh các vấn đề khóa nhập sẽ phát sinh từ việc nhập mã trực tiếp . Bạn muốn main()chạy nếu tệp của bạn được gọi trực tiếp (đó là __name__ == "__main__"trường hợp), nhưng nếu mã của bạn đã được nhập thì nhà nhập khẩu phải nhập mã của bạn từ mô-đun chính thực sự để tránh các vấn đề khóa nhập.

Một tác dụng phụ là bạn tự động đăng nhập vào một phương pháp hỗ trợ nhiều điểm vào. Bạn có thể chạy chương trình của mình bằng cách sử dụng main()làm điểm vào, nhưng bạn không phải làm thế . Trong khi setup.pymong đợi main(), các công cụ khác sử dụng điểm nhập cảnh thay thế. Ví dụ: để chạy tệp của bạn dưới dạng một gunicornquy trình, bạn xác định app()hàm thay vì a main(). Cũng giống như setup.py, gunicornnhập mã của bạn để bạn không muốn nó làm bất cứ điều gì trong khi nó được nhập (vì vấn đề khóa nhập).


3
Tốt để tìm hiểu về khóa nhập khẩu . Bạn có thể giải thích về việc đăng nhập vào một phương pháp mà [...] chia sẻ thêm một chút không?
Sói

1
@Wolf: Chắc chắn rồi. Tôi đã thêm một vài câu về phương pháp luận nhiều điểm.
Personal_cloud

11

Câu trả lời này dành cho các lập trình viên Java học Python. Mỗi tệp Java thường chứa một lớp công khai. Bạn có thể sử dụng lớp đó theo hai cách:

  1. Gọi lớp từ các tập tin khác. Bạn chỉ cần nhập nó trong chương trình gọi.

  2. Chạy lớp đứng một mình, cho mục đích thử nghiệm.

Đối với trường hợp sau, lớp nên chứa phương thức void static (). Trong Python mục đích này được phục vụ bởi nhãn được xác định toàn cầu '__main__'.


11

Mã bên dưới if __name__ == '__main__': sẽ chỉ được thực thi nếu mô-đun được gọi dưới dạng tập lệnh .

Ví dụ, xem xét các mô-đun sau 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')

Khả năng thứ nhất: Nhập my_test_module.pyvào mô-đun khác

# main.py

import my_test_module

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

Bây giờ nếu bạn gọi main.py:

python main.py 

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

Lưu ý rằng chỉ có print()câu lệnh cấp cao nhất my_test_moduleđược thực thi.


Khả năng thứ 2: Gọi my_test_module.pynhư một kịch bản

Bây giờ nếu bạn chạy my_test_module.pynhư một tập lệnh Python, cả hai print()câu lệnh sẽ được thực hiện:

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

Mỗi mô-đun trong python có một thuộc tính được gọi là __name__. Giá trị của __name__ thuộc tính là __main__ khi mô-đun được chạy trực tiếp, như thế nào python my_module.py. Mặt khác (như khi bạn nói import my_module) giá trị của__name__ là tên của mô-đun.

Ví dụ nhỏ để giải thích ngắn gọn.

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

Chúng ta có thể thực hiện điều này trực tiếp như

python test.py  

Đầu ra

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

Bây giờ giả sử chúng ta gọi tập lệnh trên từ tập lệnh khác

#script external_calling.py

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

print(test.__name__)

Khi bạn thực hiện điều này

python external_calling.py

Đầu ra

42
I am inside hello_world
test

Vì vậy, ở trên là tự giải thích rằng khi bạn gọi kiểm tra từ tập lệnh khác, nếu vòng lặp __name__trong test.pysẽ không thực thi.


6

Nếu tệp .py này được nhập bởi các tệp .py khác, mã trong "câu lệnh if" sẽ không được thực thi.

Nếu .py này được chạy bởi python this_py.pyshell, hoặc nhấp đúp vào Windows. mã trong "câu lệnh if" sẽ được thực thi.

Nó thường được viết để thử nghiệm.


6

Nếu trình thông dịch python đang chạy một mô-đun cụ thể thì __name__biến toàn cục sẽ có giá trị"__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()

Khi bạn chạy tập lệnh này, bạn có thể thấy tôi

một

Nếu bạn nhập tệp này, hãy nói A đến tệp B và thực hiện tệp B thì if __name__ == "__main__"trong tệp A trở thành sai, vì vậy nó sẽ in Bạn không thể thấy tôi

b


5

Tất cả các câu trả lời đã giải thích khá nhiều chức năng. Nhưng tôi sẽ cung cấp một ví dụ về việc sử dụng nó có thể giúp xóa bỏ khái niệm này hơn nữa.

Giả sử rằng bạn có hai tệp Python, a.py và b.py. Bây giờ, a.txt nhập khẩu b.py. Chúng tôi chạy tệp a.py, trong đó mã "nhập b.py" được thực thi trước tiên. Trước khi phần còn lại của mã a.txt chạy, mã trong tệp b.py phải chạy hoàn toàn.

Trong mã b.py có một số mã dành riêng cho tệp đó b.txt và chúng tôi không muốn bất kỳ tệp nào khác (ngoài tệp b.py), đã nhập tệp b.py, để chạy tệp đó.

Vì vậy, đó là những gì dòng mã này kiểm tra. Nếu đó là tệp chính (tức là b.py) đang chạy mã, trong trường hợp này thì không phải (a.py là tệp chính đang chạy), thì chỉ có mã được thực thi.


4

Tạo một tập tin, a.py :

print(__name__) # It will print out __main__

__name__luôn luôn bằng với __main__bất cứ khi nào tệp đó được chạy trực tiếp cho thấy đây là tệp chính.

Tạo một tệp khác, b.py , trong cùng thư mục:

import a  # Prints a

Chạy nó Nó sẽ in một , tức là tên của tệp được nhập .

Vì vậy, để hiển thị hai hành vi khác nhau của cùng một tệp , đây là một mẹo thường được sử dụng:

# Code to be run when imported into another python file

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

4

nếu tên == ' chính ':

Chúng tôi thấy nếu __name__ == '__main__':khá thường xuyên.

Nó kiểm tra nếu một mô-đun đang được nhập khẩu hay không.

Nói cách khác, mã trong ifkhối sẽ chỉ được thực thi khi mã chạy trực tiếp. Ở đây directlycó nghĩa là not imported.

Hãy xem những gì nó làm bằng cách sử dụng một mã đơn giản in tên của mô-đun:

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

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

Nếu chúng tôi chạy mã trực tiếp qua python test.py, tên mô-đun là __main__:

call test()
test module name=__main__

4

Đơn giản, nó là điểm vào để chạy tệp, giống như mainhàm trong ngôn ngữ lập trình C.


8
Câu trả lời này đưa ra giả định rằng OP (hoặc bất kỳ người dùng nào có câu hỏi tương tự) đều quen thuộc với C biết điểm vào là gì.
arredond

1
Câu trả lời này cũng cho rằng không có mã nào (ngoài các định nghĩa không có tác dụng phụ) diễn ra trước if __name__ == "__main__"khối. Về mặt kỹ thuật, phần đầu của tập lệnh được thực thi là điểm vào của chương trình.
Charlie Harding
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.