Câu hỏi Điều gì sẽ xảy ra nếu __name__ == “__main__”: làm gì?


Cái gì 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))

4149
2018-01-07 04:11


gốc




Các câu trả lời:


Khi trình thông dịch Python đọc một tệp nguồn, nó thực thi tất cả các mã được tìm thấy trong nó.

Trước khi thực thi mã, nó sẽ định nghĩa một vài biến đặc biệt. Ví dụ, nếu trình thông dịch Python đang chạy mô-đun đó (tệp nguồn) làm chương trình chính, nó sẽ đặt đặc biệt __name__ biến để có một giá trị "__main__". Nếu tệp 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.

Trong trường hợp tập lệnh của bạn, hãy giả sử rằng tập lệnh đó thực thi như hàm chính, ví dụ: bạn nói điều gì đó như

python threading_example.py

trên dòng lệnh. Sau khi thiết lập các biến đặc biệt, nó sẽ thực thi import tuyên bố và tải các mô-đun đó. Sau đó nó sẽ đánh giá def chặn, tạo đối tượng hàm và tạo biến được gọi myfunction trỏ đến đối tượng hàm. Sau đó nó sẽ đọc if tuyên bố và thấy rằng __name__ bằng nhau "__main__", do đó, nó sẽ thực hiện khối hiển thị ở đó.

Một lý do để làm điều này là đôi khi bạn viết một mô-đun (một .py tập tin) nơi nó có thể được thực hiện trực tiếp. Ngoài ra, nó cũng có thể được nhập khẩu và sử dụng trong mô-đun khác. Bằng cách thực hiện kiểm tra chính, bạn có thể có mã đó chỉ thực thi khi bạn muốn chạy mô-đun như một chương trình và không thực thi nó khi ai đó chỉ muốn nhập mô-đun của bạn và tự gọi các hàm của bạn.

Xem trang này để biết thêm chi tiết.


4421
2018-01-07 04:26



Lưu ý: Nếu bạn đặt mã trước các định nghĩa hàm, nó sẽ thực thi trước chính. print("This code executes before main.") def functionA(): print("Function A") def functionB(): print("Function B") if __name__ == '__main__': functionA() functionB()  Mã này dẫn đến: This code executes before main. Function A Function B - Stainsor


Khi kịch bản của bạn được chạy bằng cách chuyển nó thành một 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 hiện. Các hàm và các lớp được định nghĩa là, được định nghĩa, 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 được chạy tự động - main() chức năng là ngầm 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à if khố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ư trong myscript.py ở trên), sau đó __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 bạn có đang chạy trực tiếp hoặc được nhập bằng cách nào khác bằng cách kiểm tra

if __name__ == "__main__":
    ...

Nếu kịch bản 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 hiện, nhưng mã trong phần sau đó của if khoản trên sẽ không được chạy khi điều kiện không được đáp ứng. Như một ví dụ cơ bản, hãy xem xét hai tập lệnh sau đây:

# 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.py thay 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

Như vậy, khi mô-đun one được tải, __name__ bằng "one" thay vì "__main__".


1415
2018-01-07 04:28



Giải thích rõ ràng. - Poles


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

Tạo các tệp 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ó được kết quả này:

$ python a.py
Hello World from b!

Như bạn thấy, khi một mô-đun được nhập khẩu, bộ Python globals()['__name__'] trong mô-đun này vào tên của mô-đun.

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

Như bạn thấy, khi một tập tin được thực thi, bộ Python globals()['__name__'] trong tệp này "__main__".


562
2018-01-07 11:35





Cái gì if __name__ == "__main__": làm gì?

Để phác thảo kiến ​​thức 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__'. Nếu không, đó là tên bạn nhập mô-đun theo.

  • Vì vậy, mã theo if khố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 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 một kịch bản Python được thiết kế để được 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 hàm này vào cuối:

do_important()

và chạy nó (trên một dấu nhắc lệnh) với một cái gì đó như:

~$ python important.py

Vấn đề

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

import important

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

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

Và sau đó bạn sẽ phải nhớ có hay không bạn đã nhận xét cuộc gọi hàm thử nghiệm của mình. Và sự phức tạp thêm này có nghĩa là bạn có thể quên, khiến 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__ các điểm biến tới không gian tên bất cứ nơi nào trình thông dịch Python xảy ra tại thời điểm này.

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

Nhưng bên trong mô-đun chính (hoặc một phiên Python tương tác, tức là phiên dịch Đọc, Đánh giá, Vòng lặp, hoặc REPL) của trình thông dịch bạn đang chạy mọi thứ từ "__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 ở trên, mã của bạn sẽ chỉ thực thi khi bạn đang chạy nó như là mô-đun chính (hoặc cố ý gọi nó từ một tập lệnh khác).

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

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

Điều gì sẽ xảy ra nếu chúng tôi muốn chạy quy trình nghiệp vụ này từ bên ngoài mô-đun?

Nếu chúng ta đặt mã chúng ta muốn tập thể dục khi chúng ta phát triển và thử nghiệm trong một hàm như thế này và sau đó thực hiện kiểm tra của chúng ta '__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 hàm 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 hàm và lớp của nó được nhập vào các tập lệnh khác mà không cần chạy main chức năng, và cũng sẽ cho phép các mô-đun (và các chức năng và các lớp học của nó) được gọi khi chạy từ một khác nhau '__main__' mô-đun, 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 đó tuyên bố:

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

if __name__ == '__main__':
    main()

413
2017-11-23 04:38





if __name__ == "__main__"là một phần chạy khi kịch bản được chạy từ (nói) dòng lệnh bằng cách sử dụng một lệnh như python myscript.py.


92
2018-01-07 04:14





Cái gì if __name__ == "__main__": làm gì?

__name__ là một biến toàn cầu (trong Python, toàn cầu thực sự có nghĩa là trên mức 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 (như một str kiểu).

Tuy nhiên, như 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 khác được gán giá trị của '__main__' cho nó __name__.

Như vậy, 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 chính, điểm vào được chạy bởi một quá trình Python,

sẽ khiến cho tập lệnh của bạn được xác định duy nhất main để 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 làm mô-đun trong một tập lệnh khác và sau đó chạy hàm 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()

57
2017-10-14 20:22





Có rất nhiều cách khác nhau ở đây về cơ chế của mã trong câu hỏi, "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 được "Tại sao". Điều này đặ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à tệp 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 sẽ chạy mô-đun ngay lập tức khi nhập, vì vậy abcác hoạt động của nó được thực thi trước phần còn lại của xy'S. Sau khi kết thúc với ab, nó tiếp tục với xy.

Trình thông dịch theo dõi các tập lệnh đang chạy với __name__. Khi bạn chạy tập lệnh - bất kể bạn đã đặt tên gì - trình thông dịch gọi nó "__main__", biến nó thành kịch bản chính hoặc 'home' đượ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 được gán tên tệp của nó làm __name__ (ví dụ., __name__ == "ab.py"). Do đó, dòng if __name__ == "__main__": là bài kiểm tra của thông dịch viên để xác định xem nó có giải thích / phân tích cú pháp kịch bản 'home' ban đầu được thực hiện hay không hoặc tạm thời xem xét tập lệnh khác (bên ngoài). Điều này cho phép lập trình linh hoạt để có kịch bản hoạt động khác nhau nếu nó được thực hiện trực tiếp so với được gọi là bên ngoài.

Hãy bước qua đoạn mã trên để hiểu những gì đang xảy ra, tập trung đầu tiên vào các dòng không bị cản trở và thứ tự chúng xuất hiện trong các kịch bản 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 thông dịch có thể nói gì nếu tự lầm bầm:

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

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

Tại sao 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ờ các chỉ dẫn thêm - nó thực sự chạy tất cả các hoạt động thực thi có trong kịch bản lệnh. Vì vậy, đặt thịt của kịch bản của bạn vào main() chức năng kiểm dịch hiệu quả nó, đặt nó trong sự cô lập để nó sẽ không chạy ngay lập tức khi được nhập bởi tập lệnh khác.

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 ra 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ọi main()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 kịch bản 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. Họ sau đó được gọi là 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ừ tập lệnh nội tuyến không được chứa bên trong main() chức năng. Nếu bạn quen với các giai đoạn lập trình sớm của tôi để xây dựng các kịch bản trực 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 lại nếu bạn cần lại thao tác đó. Vâng, bạn không quen với loại cấu trúc bên trong này đối với mã của bạn, bởi vì nó phức tạp hơn để xây dựng và nó không trực quan để đọc.

Nhưng đó là một kịch bản 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ó đã làm nó ngay lập tức sẽ 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 chức năng, tập lệnh mới của bạn có liên quan chặt chẽ với tập lệnh cũ sẽ có các biến xung đột.

Trong việc tách ra các chức năng độc lập, bạn có thể sử dụng lại công việc trước đây của mình 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 hàm 'x' từ "xy.py". (Có lẽ nó đang tận dụng từ thứ ba của một chuỗi văn bản đã cho; tạo ra một mảng NumPy từ một danh sách các số và bình phương chúng; hoặc làm giảm bề mặt 3D. Các khả năng là vô hạn.)

(Như một bên, câu hỏi này có một 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. Rất tiếc, nó được đánh dấu là bản sao của cái này, mà tôi nghĩ là một sai lầm.)


47
2017-09-29 04:33