อะไรคือความแตกต่างระหว่างโมดูล Python และแพ็คเกจ Python?
ดูเพิ่มเติม: "แพคเกจ" และ "โมดูล" แตกต่างกันอย่างไร (สำหรับภาษาอื่น ๆ )
__init__.pyไฟล์
from plumbum.cmd import lsการติดตั้ง
__init__.py
อะไรคือความแตกต่างระหว่างโมดูล Python และแพ็คเกจ Python?
ดูเพิ่มเติม: "แพคเกจ" และ "โมดูล" แตกต่างกันอย่างไร (สำหรับภาษาอื่น ๆ )
__init__.pyไฟล์
from plumbum.cmd import lsการติดตั้ง
__init__.py
คำตอบ:
โมดูลเป็นไฟล์เดียว (หรือไฟล์) ที่นำเข้าภายใต้การนำเข้าและใช้งานครั้งเดียว เช่น
import my_module
แพคเกจคือชุดของโมดูลในไดเรกทอรีที่ให้ลำดับชั้นของแพคเกจ
from my_package.timing.danger.internets import function_of_love
__path__แอตทริบิวต์
__init__.pyไฟล์ พวกเขาเป็นโมดูลที่สามารถมีโมดูลอื่น ๆ
__path__คุณสมบัติ
ไฟล์ Python ใด ๆ เป็นโมดูลชื่อของมันคือชื่อฐานของไฟล์โดยไม่มี.pyนามสกุล แพคเกจคือชุดของโมดูลหลาม: ในขณะที่โมดูลเป็นไฟล์หลามเดียวแพคเกจเป็นไดเรกทอรีของโมดูลหลามที่มีการเพิ่ม__init__.pyไฟล์ที่จะแยกแยะแพคเกจจากไดเรกทอรีที่เพิ่งเกิดขึ้นจะมีพวงของงูหลามสคริปต์ที่ แพคเกจสามารถซ้อนในระดับความลึกใด ๆ โดยมีเงื่อนไขว่าไดเรกทอรีที่เกี่ยวข้องมี__init__.pyไฟล์ของตนเอง
ความแตกต่างระหว่างโมดูลและแพ็กเกจน่าจะอยู่ที่ระดับระบบไฟล์ เมื่อคุณนำเข้าโมดูลหรือแพ็คเกจวัตถุที่สอดคล้องกันที่สร้างขึ้นโดย Python จะเป็นประเภทmoduleเสมอ หมายเหตุอย่างไรก็ตามเมื่อคุณนำเข้าแพคเกจเฉพาะตัวแปร / ฟังก์ชั่น / คลาสใน__init__.pyไฟล์ของแพ็คเกจนั้นจะสามารถมองเห็นได้โดยตรงไม่ใช่แพ็กเกจย่อยหรือโมดูล เป็นตัวอย่างให้พิจารณาxmlแพ็คเกจในไลบรารีมาตรฐาน Python: xmlไดเรกทอรีประกอบด้วย__init__.pyไฟล์และไดเรกทอรีย่อยสี่ไดเรกทอรี ไดเรกทอรีย่อยetreeมี__init__.pyไฟล์และอื่น ๆ ในกลุ่มเป็นElementTree.pyไฟล์ ดูว่าเกิดอะไรขึ้นเมื่อคุณพยายามนำเข้าแพ็คเกจ / โมดูลแบบโต้ตอบ:
>>> import xml
>>> type(xml)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'etree'
>>> import xml.etree
>>> type(xml.etree)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'ElementTree'
>>> import xml.etree.ElementTree
>>> type(xml.etree.ElementTree)
<type 'module'>
>>> xml.etree.ElementTree.parse
<function parse at 0x00B135B0>
ใน Python มีโมดูลในตัวเช่นsysที่เขียนด้วยภาษา C แต่ฉันไม่คิดว่าคุณควรจะพิจารณาสิ่งเหล่านั้นในคำถามของคุณ
moduleเสมอ ฉันกำลังอยู่ในขั้นตอนการเขียนดีบักเกอร์และเป็นห่วงว่าดีบักเกอร์ของฉันไม่ถูกต้องในการบอกว่าแพ็คเกจของฉันเป็นmoduleของ
importคำสั่งปกติเนื่องจากไม่อนุญาตให้ใช้เครื่องหมายขีดกลางในตัวระบุ Python ใช้importlib.import_module()แทน
จากอภิธานศัพท์ Python :
โปรดทราบว่าแพ็กเกจทั้งหมดเป็นโมดูล แต่ไม่ใช่ทุกโมดูลเป็นแพ็กเกจ หรือใส่อีกวิธีหนึ่งแพ็คเกจเป็นเพียงโมดูลชนิดพิเศษ โดยเฉพาะโมดูลใด ๆ ที่มี
__path__แอตทริบิวต์ถือเป็นแพคเกจ
ไฟล์ Python ที่มีเครื่องหมายขีดกลางในชื่อmy-file.pyไม่สามารถนำเข้าด้วยimportคำสั่งแบบง่าย รหัสฉลาดimport my-fileเหมือนกับimport my - fileที่จะยกข้อยกเว้น ไฟล์ดังกล่าวมีลักษณะดีเป็นสคริปต์ในขณะที่ไฟล์ importable เป็นโมดูล
อันดับแรกโปรดจำไว้ว่าในคำจำกัดความที่แม่นยำโมดูลนั้นเป็นวัตถุในหน่วยความจำของตัวแปล Python ซึ่งมักจะสร้างขึ้นโดยการอ่านไฟล์อย่างน้อยหนึ่งไฟล์จากดิสก์ แม้ว่าเราอาจเรียกไฟล์ดิสก์อย่างไม่เป็นทางการเช่นa/b/c.py"โมดูล" แต่มันจะไม่กลายเป็นไฟล์จริงจนกว่าจะรวมกับข้อมูลจากแหล่งอื่น ๆ (เช่นsys.path) เพื่อสร้างวัตถุโมดูล
(หมายเหตุเช่นโมดูลสองตัวที่มีชื่อแตกต่างกันสามารถโหลดได้จากไฟล์เดียวกันทั้งนี้ขึ้นอยู่กับsys.pathการตั้งค่าอื่น ๆ นี่คือสิ่งที่เกิดขึ้นพร้อมกับpython -m my.moduleตามด้วยimport my.moduleล่ามในนั้นจะมีสองโมดูลวัตถุ__main__และmy.moduleทั้งสองสร้าง จากไฟล์เดียวกันบนดิสก์, my/module.py.)
แพคเกจเป็นโมดูลที่อาจมี submodules (รวมถึงแพ็กเกจย่อยบริการ) บางโมดูลไม่สามารถทำสิ่งนี้ได้ ตัวอย่างเช่นสร้างลำดับชั้นของโมดูลขนาดเล็ก:
$ mkdir -p a/b
$ touch a/b/c.py
ตรวจสอบให้แน่ใจว่าไม่มีไฟล์อื่น ๆ aภายใต้ เริ่มล่าม Python 3.4 หรือใหม่กว่า (เช่นด้วยpython3 -i) และตรวจสอบผลลัพธ์ของข้อความสั่งต่อไปนี้:
import a
a ⇒ <module 'a' (namespace)>
a.b ⇒ AttributeError: module 'a' has no attribute 'b'
import a.b.c
a.b ⇒ <module 'a.b' (namespace)>
a.b.c ⇒ <module 'a.b.c' from '/home/cjs/a/b/c.py'>
โมดูลaและa.bแพ็กเกจ (อันที่จริงแพคเกจบางชนิดเรียกว่า "แพ็คเกจเนมสเปซ" แม้ว่าเราจะไม่กังวลเกี่ยวกับสิ่งนี้) อย่างไรก็ตามโมดูลa.b.cไม่ใช่แพ็กเกจ เราสามารถสาธิตสิ่งนี้ได้โดยเพิ่มไฟล์อื่นa/b.pyเข้าไปในโครงสร้างไดเรกทอรีด้านบนและเริ่มล่ามสด:
import a.b.c
⇒ ImportError: No module named 'a.b.c'; 'a.b' is not a package
import a.b
a ⇒ <module 'a' (namespace)>
a.__path__ ⇒ _NamespacePath(['/.../a'])
a.b ⇒ <module 'a.b' from '/home/cjs/tmp/a/b.py'>
a.b.__path__ ⇒ AttributeError: 'module' object has no attribute '__path__'
Python รับประกันว่าโมดูลหลักทั้งหมดจะถูกโหลดก่อนที่จะโหลดโมดูลย่อย ข้างต้นนั้นพบว่าa/เป็นไดเรกทอรีและเพื่อสร้างแพคเกจใน namespace aและที่a/b.pyเป็นแฟ้มแหล่งที่มาหลามที่มันโหลดและการใช้ประโยชน์ในการสร้าง (ไม่ใช่แพ็คเกจ) a.bโมดูล ณ จุดนี้คุณไม่สามารถมีโมดูลได้a.b.cเนื่องจากa.bไม่ใช่แพ็คเกจดังนั้นจึงไม่มีโมดูล
คุณสามารถดูได้ที่นี่ว่าโมดูลแพ็กเกจaมี__path__แอตทริบิวต์ (แพ็คเกจต้องมีสิ่งนี้) แต่โมดูลที่ไม่ใช่แพ็กเกจa.bไม่มี
คำตอบที่ล่าช้า แต่มีคำจำกัดความอื่น:
แพคเกจถูกแสดงโดยเอนทิตีบนสุดที่นำเข้าซึ่งอาจเป็นโมดูลที่มีอยู่ในตัวเองหรือ
__init__.pyโมดูลพิเศษเป็นเอนทิตี้อันดับต้น ๆ จากชุดของโมดูลภายในโครงสร้างไดเรกทอรีย่อย
ดังนั้นแพคเกจทางกายภาพคือหน่วยการกระจายซึ่งมีโมดูลหนึ่งโมดูลขึ้นไป
__init__.pyภายในโมดูล แต่ถ้าคุณพูดคุยเกี่ยวกับหน่วยจำหน่าย (ปกติผ่าน PyPI) แล้วนี้เป็นอีกประเภทหนึ่งของแพคเกจทั้งหมด (โดยปกติจะกำหนดโดยการดำรงอยู่ของsetup.py) ฉันพบว่าการใช้คำทั้งสองนี้packageทำให้เกิดความสับสนและฉันได้พูดกับผู้เริ่มต้น Python บางคนที่พบว่ามันทำให้สับสนอย่างที่สุด
แพคเกจนี้ยังเป็นโมดูลที่สามารถมีโมดูลอื่น ๆ 'โมดูลไฟล์ที่ใช้งานง่ายและแพ็คเกจ (แพ็คเกจย่อย)' รหัสที่เกี่ยวข้องกับประเภทแพคเกจของโมดูลเข้าไปใน__init__.pyไฟล์
import pack1
print(type(pack1))
ในขณะที่โมดูลเป็นไฟล์ง่าย ๆ ที่สามารถมีฟังก์ชั่น, คลาส, รหัสที่รันได้ ฯลฯ หลังจากนำเข้าโมดูลมันจะทำงานเหมือนวัตถุที่คุณสามารถเข้าถึงตัวระบุที่กำหนดไว้ในโมดูล