อะไรคือความแตกต่างระหว่างโมดูล 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))
ในขณะที่โมดูลเป็นไฟล์ง่าย ๆ ที่สามารถมีฟังก์ชั่น, คลาส, รหัสที่รันได้ ฯลฯ หลังจากนำเข้าโมดูลมันจะทำงานเหมือนวัตถุที่คุณสามารถเข้าถึงตัวระบุที่กำหนดไว้ในโมดูล