มี__init__.py
ไว้สำหรับอะไรในไดเรกทอรีแหล่ง Python
มี__init__.py
ไว้สำหรับอะไรในไดเรกทอรีแหล่ง Python
คำตอบ:
มันเคยเป็นส่วนที่จำเป็นของแพคเกจ ( เก่า pre-3.3 "แพ็คเกจปกติ"ไม่ใช่3.3+ "แพ็คเกจเนมสเปซ" ที่ใหม่กว่า )
Python กำหนดแพ็คเกจสองประเภทแพ็คเกจปกติและแพ็คเกจเนมสเปซ แพ็คเกจปกติเป็นแพ็คเกจแบบดั้งเดิมเนื่องจากมีอยู่ใน Python 3.2 และรุ่นก่อนหน้า โดยทั่วไปแพคเกจปกติจะใช้งานเป็นไดเรกทอรีที่มี
__init__.py
ไฟล์ เมื่อนำเข้าแพคเกจปกติ__init__.py
ไฟล์นี้จะถูกดำเนินการโดยปริยายและวัตถุที่กำหนดจะถูกผูกไว้กับชื่อในเนมสเปซของแพคเกจ__init__.py
ไฟล์สามารถมีรหัสหลามเดียวกันกับที่โมดูลอื่น ๆ สามารถมีและงูหลามจะเพิ่มคุณลักษณะบางอย่างเพิ่มเติมไปยังโมดูลเมื่อมันถูกนำเข้า
แต่เพียงแค่คลิกที่ลิงค์แล้วมันมีตัวอย่างเช่นข้อมูลเพิ่มเติมและคำอธิบายของแพคเกจ namespace __init__.py
ชนิดของแพคเกจโดยไม่ต้อง
sys.path.insert(0, '/path/to/datetime')
แทนที่เส้นทางนั้นด้วยเส้นทางไปยังไดเรกทอรีใด ๆ ที่คุณเพิ่งทำ from datetime import datetime;datetime.now()
ตอนนี้พยายามบางอย่างเช่น คุณควรรับ AttributeError (เพราะมันกำลังนำเข้าไฟล์เปล่าของคุณตอนนี้) หากคุณต้องทำซ้ำขั้นตอนเหล่านี้โดยไม่สร้างไฟล์ init ว่างเปล่าสิ่งนี้จะไม่เกิดขึ้น นั่นคือสิ่งที่ตั้งใจจะป้องกัน
from datetime import datetime
โดยไม่มีข้อผิดพลาด มันดีไปตลอดทางจนถึงเวอร์ชั่น 2.3!
builtins
แสดงรายการฟังก์ชั่นและคลาสในตัวไม่ใช่โมดูลในตัว (cf. docs.python.org/3/tutorial/modules.html#the-dir-function ) หากคุณต้องการแสดงรายการโมดูลในตัวให้ทำimport sys; print(sys.builtin_module_names)
(cf. docs.python.org/3/library/sys.html#sys.builtin_module_names )
ไฟล์ที่__init__.py
มีชื่อถูกใช้เพื่อทำเครื่องหมายไดเรกทอรีบนดิสก์เป็นไดเรกทอรีแพคเกจ Python หากคุณมีไฟล์
mydir/spam/__init__.py
mydir/spam/module.py
และmydir
อยู่ในเส้นทางของคุณคุณสามารถนำเข้ารหัสmodule.py
เป็น
import spam.module
หรือ
from spam import module
หากคุณลบ__init__.py
ไฟล์ Python จะไม่ค้นหา submodules ในไดเรกทอรีนั้นอีกต่อไปดังนั้นความพยายามที่จะนำเข้าโมดูลจะล้มเหลว
__init__.py
ไฟล์มักจะว่างเปล่า แต่สามารถนำมาใช้เพื่อการส่งออกส่วนที่เลือกของแพคเกจภายใต้ชื่อสะดวกมากขึ้นถือฟังก์ชั่นอำนวยความสะดวกอื่น ๆ ได้รับตัวอย่างข้างต้นเนื้อหาของโมดูล init ที่สามารถเข้าถึงได้เป็น
import spam
ตามนี้
__init__.py
นี้จำเป็นต้องใช้ภายใต้ Python 2.X และยังจำเป็นต้องใช้ภายใต้ Python 2.7.12 (ฉันทดสอบ) แต่ไม่จำเป็นต้องใช้จาก (ถูกกล่าวหาว่า) Python 3.3 เป็นต้นไปและไม่จำเป็นต้องใช้ภายใต้ Python 3.4.3 (I ทดสอบแล้ว) ดูstackoverflow.com/questions/37139786สำหรับรายละเอียดเพิ่มเติม
__init__.py
ใช้เพียงแค่
setup.py
และคุณfind_packages()
จำเป็นต้องมี__init__.py
ทุกไดเรกทอรี ดูstackoverflow.com/a/56277323/7127824
นอกเหนือไปจากการติดฉลากไดเรกทอรีเป็นแพคเกจหลามและการกำหนด__all__
, __init__.py
ช่วยให้คุณสามารถกำหนดตัวแปรใด ๆ ในระดับแพคเกจ การทำเช่นนั้นมักจะสะดวกถ้าแพ็คเกจกำหนดสิ่งที่จะนำเข้าบ่อยๆในรูปแบบ API รูปแบบนี้ส่งเสริมการยึดมั่นในปรัชญา "แบนดีกว่าซ้อน" Pythonic
นี่คือตัวอย่างจากหนึ่งในโครงการของฉันซึ่งฉันมักจะนำเข้าsessionmaker
ชื่อSession
เพื่อโต้ตอบกับฐานข้อมูลของฉัน ฉันเขียนแพ็คเกจ "ฐานข้อมูล" ด้วยโมดูลบางส่วน:
database/
__init__.py
schema.py
insertions.py
queries.py
ฉัน__init__.py
มีรหัสต่อไปนี้:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
เนื่องจากฉันกำหนดไว้Session
ที่นี่ฉันสามารถเริ่มเซสชันใหม่โดยใช้ไวยากรณ์ด้านล่าง รหัสนี้จะเป็นรหัสเดียวกันจากภายในหรือภายนอกไดเรกทอรีแพ็คเกจ "ฐานข้อมูล"
from database import Session
session = Session()
แน่นอนว่านี่เป็นความสะดวกสบายขนาดเล็กทางเลือกอื่นคือการกำหนดSession
ในไฟล์ใหม่เช่น "create_session.py" ในแพ็คเกจฐานข้อมูลของฉันและเริ่มเซสชันใหม่โดยใช้:
from database.create_session import Session
session = Session()
มีเธรด reddit ที่น่าสนใจครอบคลุมการใช้ที่เหมาะสม__init__.py
ที่นี่:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
ความคิดเห็นส่วนใหญ่ดูเหมือนว่า__init__.py
ไฟล์ควรจะบางมากเพื่อหลีกเลี่ยงการละเมิดปรัชญา "ชัดเจนดีกว่าโดยปริยาย"
engine
, sessionmaker
, create_engine
และos
สามารถทั้งหมดนอกจากนี้ยังนำเข้ามาจากdatabase
ตอนนี้ ... ดูเหมือนว่าคุณได้ทำระเบียบของ namespace ว่า
__all__ = [...]
เพื่อ จำกัด import *
สิ่งที่ได้รับนำเข้าด้วย แต่นอกจากนั้นใช่แล้วคุณจะเหลือเนมสเปซระดับบนสุดยุ่ง ๆ
มี 2 เหตุผลหลักคือ __init__.py
เพื่อความสะดวก: ผู้ใช้รายอื่นไม่จำเป็นต้องทราบตำแหน่งที่แน่นอนของฟังก์ชันในลำดับชั้นแพ็คเกจของคุณ
your_package/
__init__.py
file1.py
file2.py
...
fileN.py
# in __init__.py
from file1 import *
from file2 import *
...
from fileN import *
# in file1.py
def add():
pass
จากนั้นบุคคลอื่นสามารถโทรเพิ่ม () โดย
from your_package import add
ไม่ทราบ file1 เช่น
from your_package.file1 import add
หากคุณต้องการบางสิ่งบางอย่างที่จะเริ่มต้น; ตัวอย่างเช่นการบันทึก (ซึ่งควรใส่ในระดับบนสุด):
import logging.config
logging.config.dictConfig(Your_logging_config)
__init__.py
อาจมีประโยชน์บางครั้ง แต่ไม่ทุกครั้ง
__init__.py
ไฟล์ดังกล่าวทำให้ Python จัดการกับไดเรกทอรีที่บรรจุเป็นโมดูล
นอกจากนี้ไฟล์นี้เป็นไฟล์แรกที่จะโหลดในโมดูลดังนั้นคุณสามารถใช้เพื่อเรียกใช้งานโค้ดที่คุณต้องการรันในแต่ละครั้งที่โหลดโมดูลหรือระบุ submodules ที่จะส่งออก
ตั้งแต่ Python 3.3 __init__.py
ไม่จำเป็นต้องกำหนดไดเรกทอรีเป็นแพ็กเกจ Python ที่สามารถนำเข้าได้อีกต่อไป
ตรวจสอบPEP 420: แพ็คเกจเนมสเปซโดยนัย :
การสนับสนุนดั้งเดิมสำหรับไดเรกทอรีแพ็คเกจที่ไม่ต้องใช้
__init__.py
ไฟล์ทำเครื่องหมายและสามารถขยายส่วนของเส้นทางหลายส่วนโดยอัตโนมัติ (ได้รับแรงบันดาลใจจากวิธีการของบุคคลที่สามที่หลากหลายในแพ็คเกจเนมสเปซตามที่อธิบายในPEP 420 )
นี่คือการทดสอบ:
$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
การอ้างอิง:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
คือ __init__ ไม่ต้องการ py สำหรับแพ็คเกจใน Python 3 ใช่ไหม
ใน Python นิยามของแพ็คเกจนั้นง่ายมาก เช่นเดียวกับ Java โครงสร้างลำดับชั้นและโครงสร้างไดเรกทอรีเหมือนกัน แต่คุณต้องมี__init__.py
ในแพ็คเกจ ฉันจะอธิบาย__init__.py
ไฟล์ด้วยตัวอย่างด้านล่าง:
package_x/
|-- __init__.py
|-- subPackage_a/
|------ __init__.py
|------ module_m1.py
|-- subPackage_b/
|------ __init__.py
|------ module_n1.py
|------ module_n2.py
|------ module_n3.py
__init__.py
สามารถว่างเปล่าได้ตราบใดที่มีอยู่ มันบ่งชี้ว่าไดเรกทอรีควรถือเป็นแพคเกจ แน่นอน,__init__.py
สามารถตั้งค่าเนื้อหาที่เหมาะสม
หากเราเพิ่มฟังก์ชั่นใน module_n1:
def function_X():
print "function_X in module_n1"
return
หลังจากทำงาน:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
จากนั้นเราติดตามแพคเกจลำดับชั้นและเรียกว่า module_n1 ฟังก์ชั่น เราสามารถใช้__init__.py
ใน subPackage_b ดังนี้:
__all__ = ['module_n2', 'module_n3']
หลังจากทำงาน:
>>>from package_x.subPackage_b import *
>>>module_n1.function_X()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named module_n1
ดังนั้นการใช้ * การนำเข้าแพคเกจโมดูลอาจมี__init__.py
เนื้อหา
from package_x.subPackage_b.module_n1 import function_X
ถึงแม้ว่า Python จะทำงานโดยไม่มี__init__.py
ไฟล์ แต่คุณก็ควรรวมไว้ด้วย
มันระบุแพคเกจควรได้รับการปฏิบัติเป็นโมดูลดังนั้นจึงรวมถึงมัน (แม้ว่าจะว่างเปล่า)
นอกจากนี้ยังมีกรณีที่คุณอาจใช้__init__.py
ไฟล์จริง:
ลองนึกภาพคุณมีโครงสร้างไฟล์ต่อไปนี้:
main_methods
|- methods.py
และmethods.py
มีสิ่งนี้:
def foo():
return 'foo'
หากต้องการใช้foo()
คุณจะต้องมีสิ่งใดสิ่งหนึ่งต่อไปนี้:
from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()
อาจมีคุณต้องการ (หรือต้องการ) เพื่อเก็บไว้methods.py
ข้างในmain_methods
(ตัวอย่างเช่น runtimes / dependencies) แต่คุณต้องการนำเข้าmain_methods
เท่านั้น
หากคุณเปลี่ยนชื่อเป็นmethods.py
เป็น__init__.py
คุณสามารถใช้foo()
เพียงนำเข้าmain_methods
:
import main_methods
print(main_methods.foo()) # Prints 'foo'
ใช้งานได้เพราะ__init__.py
ถือว่าเป็นส่วนหนึ่งของแพ็คเกจ
แพ็กเกจ Python บางตัวทำสิ่งนี้จริง ตัวอย่างคือกับJSONโดยที่การรันกำลังimport json
นำเข้า__init__.py
จากjson
แพ็คเกจจริง ( ดูโครงสร้างไฟล์แพ็คเกจที่นี่ ):
รหัสแหล่งที่มา:
Lib/json/__init__.py
__init__.py
จะถือว่าไดเรกทอรีมันเป็นโมดูลที่โหลดได้
สำหรับคนที่ชอบอ่านรหัสฉันใส่ความคิดเห็นของนักเล่นแร่แปรธาตุ Two-Bitที่นี่
$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$
$ rm /tmp/mydir/spam/__init__.py*
$
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>>
มันอำนวยความสะดวกในการนำเข้าไฟล์หลามอื่น ๆ เมื่อคุณวางไฟล์นี้ในไดเรกทอรี (พูดสิ่ง) ที่มีไฟล์ py อื่น ๆ จากนั้นคุณสามารถทำสิ่งต่าง ๆ เช่นนำเข้า stuff.other
root\
stuff\
other.py
morestuff\
another.py
หากไม่มีสิ่งนี้__init__.py
ภายในเนื้อหาของไดเรกทอรีคุณจะไม่สามารถนำเข้า other.py เนื่องจาก Python ไม่ทราบว่าซอร์สโค้ดของสิ่งนั้นอยู่ที่ไหนและไม่สามารถรับรู้ได้ว่าเป็นแพคเกจ
__init__.py
ไฟล์ทำให้การนำเข้าง่าย เมื่อมี__init__.py
อยู่ในแพ็คเกจฟังก์ชั่นa()
สามารถนำเข้าจากไฟล์b.py
ดังนี้:
from b import a
ไม่ว่าอย่างไรก็ตามคุณจะไม่สามารถนำเข้าโดยตรง คุณต้องแก้ไขเส้นทางของระบบ:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a