ไม่จำเป็นต้อง __init__.py สำหรับแพ็คเกจใน Python 3.3+


195

ฉันใช้ Python 3.5.1 ฉันอ่านเอกสารและส่วนแพ็คเกจที่นี่: https://docs.python.org/3/tutorial/modules.html#packages

ตอนนี้ฉันมีโครงสร้างต่อไปนี้:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

ตอนนี้ในขณะที่/home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

ในทำนองเดียวกันตอนนี้อยู่ที่บ้าน superfolder ของPlayground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

ที่จริงฉันสามารถทำสิ่งต่าง ๆ ได้ทุกอย่าง:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

ทำไมจึงใช้งานได้ ผมคิดว่ามีความจำเป็นที่จะ__init__.pyไฟล์ (คนที่ว่างเปล่าจะทำงาน) ทั้งในaและbสำหรับmodule.pyที่จะ importable เมื่องูหลามจุดเส้นทางไปยังPlaygroundโฟลเดอร์?

ดูเหมือนว่าจะเปลี่ยนไปจาก Python 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

ด้วย__init__.pyทั้งใน~/Playground/aและ~/Playground/a/bมันใช้งานได้ดี

คำตอบ:


192

Python 3.3+ มีแพ็คเกจเนมสเปซโดยนัยที่อนุญาตให้สร้างแพ็กเกจโดยไม่มี__init__.pyไฟล์

การอนุญาตแพ็คเกจเนมสเปซโดยนัยหมายความว่าข้อกำหนดในการจัดหา__init__.pyไฟล์สามารถถูกดร็อปได้อย่างสมบูรณ์และได้รับผลกระทบ ...

วิธีการแบบเก่ากับ__init__.pyไฟล์ยังคงใช้งานได้เหมือนใน Python 2


10
ฉันจะอ่านเอกสาร แต่มันก็ค่อนข้างยาว เป็นไปได้หรือไม่ที่จะสรุปได้อย่างรวดเร็ว? คุณช่วยบอกฉันหน่อยได้ไหมว่า: มันยังรองรับinit .py หรือไม่สนใจเลย? ถ้ามันรองรับพวกมันอะไรคือความแตกต่างของฟังก์ชั่นและทำไมคู่นี้?
wujek

3
ดังนั้นควรมีการปรับปรุงบทช่วยสอน มีการเปิดเอกสารข้อผิดพลาดหรือไม่
Michel Samia

4
ฉันยังคงอารมณ์เสียว่าสิ่งนี้ท้าทายZen Of Python บรรทัดที่ 2: Explicit is better than implicit.....
JayRizzo

5
@ JayRizzo แต่: "แม้ว่าการปฏิบัติจริงชนะความบริสุทธิ์"
Mike Müller

19
@ JayRizzo IMO มันชัดเจนยิ่งขึ้น บางครั้งมันก็เกิดขึ้นกับสิ่งที่เริ่มต้นใน__init__.pyบางครั้งไม่ได้ ใน Python 3 เมื่อฉันต้องการสิ่งเหล่านี้ฉันสร้างใหม่__init__.pyด้วยรหัสเฉพาะมิฉะนั้นฉันไม่ต้องการ สิ่งนี้มีประโยชน์ที่จะรู้ด้วยสายตาว่าแพ็คเกจใดมี init ที่กำหนดเอง ใน python 2 ฉันต้องวาง__init__.py(มักจะว่างเปล่า) สร้างจำนวนมากและในที่สุดก็ยากที่จะจำตำแหน่งที่คุณวางโค้ดเริ่มต้นของคุณ สิ่งนี้ควรสอดคล้องกับ "ควรมีอย่างใดอย่างหนึ่ง - และดีกว่าเพียงวิธีเดียว - วิธีที่ชัดเจนที่จะทำ"
เปาโล

148

สำคัญ

@ คำตอบของไมค์นั้นถูกต้อง แต่ก็ไม่แน่ชัด เป็นความจริงที่ว่า Python 3.3+ รองรับแพ็คเกจเนมสเปซโดยนัยที่อนุญาตให้สร้างแพ็คเกจโดยไม่มี__init__.pyไฟล์

อย่างไรก็ตามสิ่งนี้ใช้ได้กับไฟล์ที่ว่าง__init__.pyเท่านั้น ดังนั้นไฟล์EMPTY__init__.pyจึงไม่จำเป็นอีกต่อไปและสามารถละไว้ได้ หากคุณต้องการเรียกใช้สคริปต์การเริ่มต้นเฉพาะเมื่อมีการนำเข้าแพ็คเกจหรือโมดูลหรือแพ็คเกจย่อยใด ๆ คุณยังต้องใช้__init__.pyไฟล์ นี่เป็นคำตอบที่ดีสำหรับStack Overflowสำหรับสาเหตุที่คุณต้องการใช้__init__.pyไฟล์ในการเริ่มต้นเพิ่มเติมในกรณีที่คุณสงสัยว่าทำไมสิ่งนี้ถึงมีประโยชน์

ตัวอย่างโครงสร้างไดเรกทอรี:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

ตัวอย่าง

ตัวอย่างด้านล่างแสดงให้เห็นถึงวิธีการดำเนินการสคริปต์เริ่มต้นเมื่อchild_packageหรือหนึ่งในโมดูลที่นำเข้า

ตัวอย่างที่ 1 :

from parent_package import child_package  # prints "from parent"

ตัวอย่างที่ 2 :

from parent_package.child_package import child1  # prints "from parent"

2
สมมติว่าฉันมีrun_script.pydir เดียวกันparent_packageดังนั้นฉันจะสามารถนำเข้าfrom parent_package.child_package import child1โดยไม่ต้องได้__init__.pyหรือไม่
mrgloom

จุดประสงค์นี้คือเพื่อให้คุณสามารถเขียน child_package.some_function แม้ว่า some_function ถูกกำหนดใน childX.py? อีกนัยหนึ่งคือหลีกเลี่ยงการให้ผู้ใช้ทราบเกี่ยวกับไฟล์ต่างๆใน child_package? ?
johnbakers

ใช่ฉันไม่ได้รับเหตุผลที่คุณจะทำให้child1.py, child2.pyแทนเพียงแค่ใส่รหัสของพวกเขาเข้าด้วยกันเป็น__init__.py โดยตรง
binki

ไม่ควรนำเข้างบใน__init__การนำเข้าที่เกี่ยวข้องเช่นfrom . import child1? การนำเข้าแบบสัมบูรณ์ให้ฉันModuleNotFoundError(ใน Python 3.6)
Halbeard

5
จากประสบการณ์ของฉันถึงแม้จะใช้ python 3.3+ แต่__init__.pyก็ยังจำเป็นต้องใช้ค่าว่างบางครั้งเช่นเมื่อคุณต้องการอ้างถึงโฟลเดอร์ย่อยเป็นแพ็คเกจ ตัวอย่างเช่นถ้าฉันเรียกใช้python -m test.fooมันจะไม่ทำงานจนกว่าฉันจะสร้างว่างเปล่า__init__.pyภายใต้โฟลเดอร์ทดสอบ และฉันกำลังพูดถึงเวอร์ชั่น 3.6.6 ที่นี่!
Prahlad Yeri

7

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

แพ็คเกจจะรับรู้ได้ก็ต่อเมื่อมี__init__.pyไฟล์อยู่ด้วย

UPD : ถ้าคุณต้องการใช้แพ็คเกจเนมสเปซโดยปริยายโดยที่__init__.pyคุณไม่จำเป็นต้องใช้find_namespace_packages()แทน

เอกสาร


1

ฉันจะบอกว่าใครควรละเว้น__init__.pyแต่ถ้าใครอยากจะมีแพคเกจ namespace โดยปริยาย หากคุณไม่ทราบว่ามันแปลว่าอะไรคุณอาจไม่ต้องการมันดังนั้นคุณควรใช้งานต่อไป__init__.pyใน Python 3

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