ต่อไปนี้เป็นสูตรทั่วไปที่ปรับเปลี่ยนให้เหมาะกับตัวอย่างที่ฉันใช้อยู่ตอนนี้เพื่อจัดการกับไลบรารี Python ที่เขียนเป็นแพ็คเกจซึ่งมีไฟล์พึ่งพาซึ่งฉันต้องการทดสอบชิ้นส่วนต่างๆ โทร Let 's นี้lib.fooและบอกว่ามันต้องการเข้าถึงlib.fileAฟังก์ชั่นf1และf2และสำหรับการเรียนlib.fileBClass3
ฉันได้รวมการprintโทรไปสองสามครั้งเพื่อช่วยอธิบายวิธีการทำงานของมัน ในทางปฏิบัติคุณต้องการลบออก (และอาจเป็นfrom __future__ import print_functionเส้น)
sys.pathตัวอย่างนี้โดยเฉพาะอย่างยิ่งเป็นเรื่องง่ายเกินไปที่จะแสดงให้เห็นเมื่อเราต้องการจริงๆที่จะแทรกเข้าไปในรายการ (ดูคำตอบของลาร์สในกรณีที่เราไม่จำเป็นต้องใช้มันเมื่อเรามีสองคนหรือมากกว่าระดับของไดเรกทอรีแพคเกจและจากนั้นเราจะใช้os.path.dirname(os.path.dirname(__file__))-but มันไม่ได้โดดเจ็บใดที่นี่.) นอกจากนี้ยังพอที่ปลอดภัยที่จะทำเช่นนี้ได้โดยไม่ต้องif _i in sys.pathทดสอบ. อย่างไรก็ตามหากไฟล์ที่นำเข้าแต่ละไฟล์แทรกพา ธ เดียวกัน - เช่นถ้าทั้งคู่fileAและfileBต้องการนำเข้ายูทิลิตี้จากแพ็คเกจ - กลุ่มนี้ขึ้นsys.pathกับเส้นทางเดียวกันหลายครั้งดังนั้นจึงเป็นเรื่องดีที่จะมีif _i not in sys.pathในสำเร็จรูป
from __future__ import print_function # only when showing how this works
if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space
    from fileA import f1, f2
    from fileB import Class3
... all the code as usual ...
if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)
ความคิดที่นี่คือ (และโปรดทราบว่าสิ่งเหล่านี้ทำงานเหมือนกันใน python2.7 และ python 3.x):
ถ้าทำงานเป็นimport libหรือfrom lib import fooเป็นการนำเข้าแพคเกจปกติจากรหัสสามัญ__packageเป็นlibและเป็น__name__ lib.fooเราใช้พา ธ โค้ดแรกการนำเข้าจาก.fileAและอื่น ๆ
 
ถ้าทำงานเป็นpython lib/foo.py, __package__จะไม่มีและจะ__name____main__
เราใช้เส้นทางรหัสที่สอง libไดเรกทอรีแล้วจะอยู่ในsys.pathดังนั้นจึงไม่มีความจำเป็นที่จะต้องเพิ่ม เรานำเข้าจากfileAฯลฯ
 
หากทำงานในlibไดเรกทอรีเช่นpython foo.pyพฤติกรรมจะเหมือนกับกรณีที่ 2
 
หากเรียกใช้ภายในlibไดเรกทอรีเป็นpython -m fooพฤติกรรมจะคล้ายกับกรณีที่ 2 และ 3 อย่างไรก็ตามเส้นทางไปยังlibไดเรกทอรีไม่ได้อยู่ในsys.pathดังนั้นเราจึงเพิ่มมันก่อนที่จะนำเข้า import fooเช่นเดียวกับถ้าเราเรียกงูใหญ่แล้ว
(เนื่องจาก. อยู่ในsys.pathเราไม่จำเป็นต้องเพิ่มรุ่นที่แน่นอนของเส้นทางที่นี่นี่เป็นที่ซึ่งโครงสร้างการซ้อนของแพ็กเกจที่เราต้องการทำfrom ..otherlib.fileC import ...มีความแตกต่างหากคุณไม่ได้ทำเช่นนี้คุณสามารถ ละเว้นการsys.pathจัดการทั้งหมดอย่างสิ้นเชิง)
 
หมายเหตุ
ยังมีการเล่นโวหาร หากคุณดำเนินการทั้งหมดนี้จากภายนอก:
$ python2 lib.foo
หรือ:
$ python3 lib.foo
lib/__init__.pyลักษณะการทำงานขึ้นอยู่กับเนื้อหาของ หากสิ่งนั้นมีอยู่และว่างเปล่าทั้งหมดนั้นก็เป็นอย่างดี:
Package named 'lib'; __name__ is '__main__'
แต่ถ้านำเข้าlib/__init__.py เองroutineเพื่อให้สามารถส่งออกroutine.nameได้โดยตรงlib.nameคุณจะได้รับ:
$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'
นั่นคือโมดูลจะได้รับการนำเข้าสองครั้งครั้งเดียวผ่านแพคเกจแล้วอีกครั้ง__main__เพื่อที่จะเรียกใช้mainรหัสของคุณ Python 3.6 และใหม่กว่าเตือนเกี่ยวกับสิ่งนี้:
$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'
เตือนเป็นของใหม่ แต่เตือนเกี่ยวกับพฤติกรรมไม่ได้ มันเป็นส่วนหนึ่งของสิ่งที่บางคนเรียกดักนำเข้าคู่ (สำหรับรายละเอียดเพิ่มเติมดูปัญหา 27487 ) Nick Coghlan พูดว่า:
  กับดักต่อไปนี้มีอยู่ใน Python เวอร์ชันปัจจุบันทั้งหมดรวมถึง 3.3 และสามารถสรุปได้ในแนวทางทั่วไปต่อไปนี้: "อย่าเพิ่มไดเรกทอรีแพ็คเกจหรือไดเรกทอรีใด ๆ ภายในแพ็คเกจโดยตรงไปยังเส้นทาง Python"
โปรดทราบว่าในขณะที่เราละเมิดกฎนี้เราจะทำเฉพาะเมื่อไฟล์ที่โหลดไม่ได้ถูกโหลดเป็นส่วนหนึ่งของแพ็คเกจและการดัดแปลงของเราได้รับการออกแบบมาโดยเฉพาะเพื่อให้เราสามารถเข้าถึงไฟล์อื่น ๆ ในแพ็คเกจนั้นได้ (และอย่างที่ฉันสังเกตเห็นเราอาจไม่ควรทำเช่นนี้สำหรับแพ็คเกจระดับเดียว) หากเราต้องการความสะอาดเป็นพิเศษเราอาจเขียนสิ่งนี้เป็นเช่น:
    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None
    from sub.fileA import f1, f2
    from sub.fileB import Class3
    if _i:
        sys.path.remove(_i)
    del _i
นั่นคือเราปรับเปลี่ยนได้sys.pathนานพอที่จะบรรลุการนำเข้าของเราจากนั้นนำกลับมาใช้ใหม่ (ลบหนึ่งสำเนา_iหากและถ้าเราเพิ่มอีกหนึ่งสำเนา_i)