ทำไมไพ ธ อนจึงรันโมดูลเมื่อฉันนำเข้ามันและฉันจะหยุดมันได้อย่างไร


173

ฉันมีโปรแกรม Python ฉันกำลังสร้างที่สามารถเรียกใช้ในสองวิธี: แรกคือการเรียกว่า "python main.py" ซึ่งจะแจ้งให้ผู้ใช้สำหรับการป้อนข้อมูลในลักษณะที่เป็นมิตรแล้วเรียกใช้การป้อนข้อมูลของผู้ใช้ผ่านโปรแกรม อีกวิธีหนึ่งคือการเรียก "python batch.py -file- " ซึ่งจะผ่านการรวบรวมอินพุตที่เป็นมิตรทั้งหมดและเรียกใช้ค่าอินพุตทั้งหมดของไฟล์ผ่านโปรแกรมในครั้งเดียว

ปัญหาคือเมื่อฉันรัน "batch.py" มันจะนำเข้าตัวแปร / methods / etc บางอย่างจาก "main.py" และเมื่อมันรันรหัสนี้:

import main

ที่บรรทัดแรกของโปรแกรมจะเกิดข้อผิดพลาดทันทีเนื่องจากพยายามเรียกใช้รหัสใน "main.py"

ฉันจะหยุด Python ไม่ให้รันโค้ดที่อยู่ในโมดูล "main" ที่ฉันกำลังนำเข้าได้อย่างไร

คำตอบ:


251

เพราะนี่เป็นเพียงวิธีการทำงานของงูหลาม - คำหลักเช่นclassและdefมีไม่ได้ประกาศ แต่เป็นแถลงการณ์สดจริงที่ดำเนินการแทน หากพวกเขาไม่ได้ดำเนินการโมดูลของคุณจะเป็น .. ว่างเปล่า :-)

อย่างไรก็ตามวิธีการใช้สำนวนคือ:

# stuff to run always here such as class/def
def main():
    pass

if __name__ == "__main__":
   # stuff only to run when not called via 'import' here
   main()

ดูว่ามีif __name__ == "__main__"ไว้เพื่ออะไร

มันไม่จำเป็นต้องมีการควบคุมแหล่งที่มาของโมดูลที่กำลังimported อย่างไรก็ตาม

การเข้ารหัสที่มีความสุข


1
เพียงเพื่อยืนยันความคิดเห็นของคุณ "สิ่งเดียวที่จะทำงานเมื่อไม่ได้เรียกผ่าน 'นำเข้า' ที่นี่" หมายถึงคำสั่งที่จะเขียนภายใต้ main () ใช่ไหม? หรือไม่เป็นไร ??
Goldname

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

51

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

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

if __name__ == "__main__":
    # this won't be run when imported

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

def main():
    print "Hello World"

if __name__ == "__main__":
    main()

โปรแกรมนี้สามารถรันได้โดยไปpython foo.pyหรือจากสคริปต์ Python อื่น:

import foo

...

foo.main()

12

ใช้if __name__ == '__main__'สำนวน - __name__เป็นตัวแปรพิเศษที่มีค่าเป็น'__main__'ถ้าโมดูลจะถูกเรียกใช้เป็นสคริปต์และชื่อโมดูลถ้ามันถูกนำเข้า ดังนั้นคุณจะทำอะไรเช่น

# imports
# class/function definitions
if __name__ == '__main__':
    # code here will only run when you invoke 'python main.py'

4

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

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


1
ตามที่ทราบ: หากไม่มีวิธีการแก้ไขสภาพแวดล้อมเพื่อให้สามารถป้องกันข้อผิดพลาดได้คุณอาจใช้โมดูลอื่น
cwallenpoole

4

ใส่รหัสในฟังก์ชั่นและมันจะไม่ทำงานจนกว่าคุณจะเรียกใช้ฟังก์ชั่น main.pyคุณควรจะมีฟังก์ชั่นหลักในของคุณ ด้วยคำสั่ง:

if __name__ == '__main__':
  main()

จากนั้นถ้าคุณเรียกpython main.pyใช้main()ฟังก์ชั่นจะทำงาน หากคุณนำเข้าmain.pyก็จะไม่ นอกจากนี้คุณควรเปลี่ยนชื่อmain.pyเป็นอย่างอื่นเพื่อความชัดเจน


3

มีข้อเสนอการปรับปรุง Python PEP 299ซึ่งมีวัตถุประสงค์เพื่อแทนที่if __name__ == '__main__':สำนวนด้วยdef __main__:แต่มันถูกปฏิเสธ if __name__ = '__main__':ก็ยังคงเป็นที่ดีอ่านจะรู้ว่าสิ่งที่จะเก็บไว้ในใจเมื่อใช้


2

คุณสามารถเขียน "main.py" ของคุณเช่นนี้:

#!/usr/bin/env python

__all__=["somevar", "do_something"]

somevar=""

def do_something():
    pass #blahblah

if __name__=="__main__":
    do_something()

-1

แม้ว่าคุณจะไม่สามารถใช้งานได้importหากไม่ใช้รหัส มีวิธีที่รวดเร็วในการที่คุณสามารถป้อนตัวแปรของคุณ โดยใช้numpy.savezซึ่งเก็บตัวแปรเป็นอาร์เรย์ numpy ในไฟล์. npz numpy.loadหลังจากนั้นคุณสามารถโหลดตัวแปรโดยใช้

ดูคำอธิบายแบบเต็มในเอกสารประกอบคำอธิบาย

โปรดทราบว่านี่เป็นเพียงกรณีของตัวแปรและอาร์เรย์ของตัวแปรและไม่ใช่สำหรับวิธีการ ฯลฯ


-4

ลองนำเข้าฟังก์ชั่นที่จำเป็นจาก main.py หรือไม่ ดังนั้น,

from main import SomeFunction

อาจเป็นได้ว่าคุณได้ตั้งชื่อฟังก์ชั่นใน batch.py ​​เหมือนกับหนึ่งใน main.py และเมื่อคุณนำเข้า main.py โปรแกรมจะเรียกใช้ฟังก์ชัน main.py แทนฟังก์ชั่น batch.py การทำข้างต้นควรแก้ไข ฉันหวังว่า.


อย่างน้อยใน Windows ก็ไม่เป็นเช่นนั้น
Martín Coll

2
import mainไม่นำเข้าทุกอย่างจาก main ลงใน namespace ปัจจุบัน มันเพิ่มmainสัญลักษณ์เดียวในเนมสเปซปัจจุบันเท่านั้นดังนั้นจึงไม่สามารถเกิดการชนได้
remram
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.