Sự khác biệt giữa mô-đun Python và gói Python là gì?


576

Sự khác biệt giữa mô-đun Python và gói Python là gì?

Xem thêm: Sự khác biệt giữa "gói" và "mô-đun" (đối với các ngôn ngữ khác)


9
Tôi có thể sai nhưng đối với tôi: một mô-đun về cơ bản là một tệp python. Một gói là một thư mục với một loạt các mô-đun (tệp python).
lc2817

36
Để được coi là một gói, thư mục đó phải chứa một __init__.pytệp.
Giulio Piancastelli

@ lc2817: đây là trường hợp phổ biến nhất nhưng không cần thiết phải tải mô-đun từ hệ thống tệp, ví dụ: xem from plumbum.cmd import lstriển khai
jfs

4
@GiulioPiancastelli: Trong Python 3.3+, các gói không gian tên không sử dụng__init__.py
jfs

Làm thế nào để cộng đồng phân biệt giữa các gói Python và các gói được sử dụng để phân phối các thành phần Python như PyPI / bánh xe / vv? Cả hai dường như là những ứng dụng khác nhau của từ "gói" đối với tôi.
davidA

Câu trả lời:


373

Một mô-đun là một tệp (hoặc tệp) được nhập theo một lần nhập và sử dụng. ví dụ

import my_module

Một gói là một tập hợp các mô-đun trong các thư mục cung cấp một hệ thống phân cấp gói.

from my_package.timing.danger.internets import function_of_love

Tài liệu cho các mô-đun

Giới thiệu về gói


54
Khi bạn nói: "Mô-đun là một tệp (hoặc tệp) được nhập trong một lần nhập", bạn có thể giải thích tình huống trong đó mô-đun có nhiều hơn một tệp không? Hay tôi đang đọc sai ý của bạn?
Người dùng

5
Bạn không cần một tệp để tạo mô-đun, ví dụ: bạn có thể nhập mô-đun từ tệp zip. Tương tự cho các gói. Chỉ có một lớp cho các mô-đun / gói trong Python. Gói chỉ là một mô-đun với một __path__thuộc tính.
jfs

33
Gói là mô-đun quá . Chúng chỉ được đóng gói khác nhau; chúng được hình thành bởi sự kết hợp của một thư mục cộng với __init__.pytập tin. Chúng là các mô-đun có thể chứa các mô-đun khác.
Martijn Pieters

15
@Jacquot chắc chắn, xem Hệ thống nhập trong tài liệu tham khảo: Điều quan trọng cần lưu ý là tất cả các gói đều là mô-đun .
Martijn Pieters

6
@Jacquot: và thuật ngữ về “gói” : Một mô-đun Python có thể chứa submodules hoặc đệ quy, các gói con. Về mặt kỹ thuật, một gói là một mô-đun Python có __path__thuộc tính.
Martijn Pieters

556

Bất kỳ tệp Python nào cũng là một mô-đun , tên của nó là tên cơ sở của tệp mà không có .pyphần mở rộng. Một gói là một tập hợp các module Python: trong khi một module là một file Python duy nhất, một gói là một thư mục của module Python chứa thêm __init__.pytập tin, để phân biệt một gói từ một thư mục mà chỉ xảy ra để chứa một loạt các kịch bản Python. Các gói có thể được lồng vào bất kỳ độ sâu nào, miễn là các thư mục tương ứng chứa riêng chúng__init__.py tệp .

Sự khác biệt giữa mô-đun và gói dường như chỉ giữ ở cấp hệ thống tệp. Khi bạn nhập một mô-đun hoặc một gói, đối tượng tương ứng được tạo bởi Python luôn có kiểu module. Tuy nhiên, lưu ý, khi bạn nhập một gói, chỉ các biến / hàm / lớp trong __init__.pytệp của gói đó được hiển thị trực tiếp, không phải các gói phụ hoặc mô-đun. Ví dụ, xem xét xmlgói trong thư viện chuẩn Python: thư mục của nó xmlchứa một __init__.pytệp và bốn thư mục con; thư mục con etreechứa một __init__.pytệp và trong số các ElementTree.pytệp khác. Xem điều gì xảy ra khi bạn cố gắng tương tác nhập gói / mô-đun:

>>> 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>

Trong Python cũng có các mô-đun tích hợp, chẳng hạn như sys, được viết bằng C, nhưng tôi không nghĩ bạn có ý định xem xét những điều đó trong câu hỏi của bạn.


9
Cảm ơn đã đề cập rõ ràng rằng đối tượng tương ứng được tạo bởi Python luôn là kiểu module. Tôi đang trong quá trình viết một trình gỡ lỗi và lo lắng rằng trình gỡ lỗi của tôi không chính xác khi nói rằng các gói của tôi là modules.
ArtOfWarfare

8
@jolvi Các tệp Python có tên tệp chứa dấu gạch ngang vẫn có thể được nhập dưới dạng mô-đun, không phải với importcâu lệnh thông thường , vì dấu gạch ngang không được phép trong mã định danh Python. Sử dụng importlib.import_module()thay thế.
Giulio Piancastelli

2
@jolvi Tôi không có. Bạn đang đọc nó ở đâu? Tôi chỉ nói rằng, nếu bạn tình cờ có hoặc vấp phải một tệp Python có dấu gạch ngang trong tên của nó, bạn vẫn có thể nhập nó dưới dạng một mô-đun. Tôi không đưa ra tuyên bố về cách đặt tên tệp Python ưa thích. Tôi chắc chắn rằng bạn có thể tìm thấy điều đó ở một nơi khác: thường được khuyến cáo nên tránh các dấu gạch ngang có lợi cho dấu gạch dưới.
Giulio Piancastelli

3
Là người mới đối với Python, các gói phụ hoặc mô-đun không có sẵn theo mặc định khi nhập gói cha là điều khiến tôi vấp ngã. Có một lý do đặc biệt cho điều đó? Và có một mô hình chung làm thế nào để làm cho các gói phụ hoặc mô-đun có sẵn (thông qua tên đầy đủ của chúng) khi nhập gói cha?
sschuberth

2
@sschuberth Chỉ cần nhập các gói phụ trong init .py của gói cha.
Anna

33

Từ bảng chú giải Python :

Điều quan trọng cần nhớ là tất cả các gói là các mô-đun, nhưng không phải tất cả các mô-đun là các gói. Hoặc nói cách khác, các gói chỉ là một loại mô-đun đặc biệt. Cụ thể, bất kỳ mô-đun có chứa một __path__thuộc tính được coi là một gói.

Các tệp Python có dấu gạch ngang trong tên, như my-file.py, không thể được nhập bằng một importcâu lệnh đơn giản . Code-khôn ngoan, import my-filegiống như import my - filesẽ đưa ra một ngoại lệ. Các tệp như vậy được đặc trưng tốt hơn như các tập lệnh trong khi các tệp có thể nhập được là các mô-đun .


23

Trước tiên, hãy nhớ rằng, theo định nghĩa chính xác của nó, mô-đun là một đối tượng trong bộ nhớ của trình thông dịch Python, thường được tạo bằng cách đọc một hoặc nhiều tệp từ đĩa. Mặc dù chúng tôi có thể gọi một cách chính thức một tệp đĩa như a/b/c.py"mô-đun", nhưng nó không thực sự trở thành một tệp cho đến khi nó kết hợp với thông tin từ một số nguồn khác (chẳng hạn như sys.path) để tạo đối tượng mô-đun.

(Lưu ý, ví dụ, hai mô-đun có tên khác nhau có thể được tải từ cùng một tệp, tùy thuộc vào sys.pathcác cài đặt khác. Đây chính xác là những gì xảy ra với python -m my.modulemột import my.moduletrình thông dịch theo sau; sẽ có hai đối tượng mô-đun __main__my.modulecả hai được tạo từ cùng một tệp trên đĩa , my/module.py.)

Một gói là một mô-đun có thể có các mô hình con (bao gồm cả các gói con). Không phải tất cả các mô-đun có thể làm điều này. Ví dụ, tạo một hệ thống phân cấp mô-đun nhỏ:

$ mkdir -p a/b
$ touch a/b/c.py

Đảm bảo rằng không có tệp nào khác bên dưới a. Bắt đầu trình thông dịch Python 3.4 trở lên (ví dụ: với python3 -i) và kiểm tra kết quả của các câu lệnh sau:

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'>

Các mô-đun aa.blà các gói (trên thực tế, một loại gói nhất định được gọi là "gói không gian tên", mặc dù chúng tôi không lo lắng về điều đó ở đây). Tuy nhiên, mô-đun a.b.ckhông phải là một gói. Chúng tôi có thể chứng minh điều này bằng cách thêm một tệp khác a/b.pyvào cấu trúc thư mục ở trên và bắt đầu một trình thông dịch mới:

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 đảm bảo rằng tất cả các mô đun mẹ được tải trước khi mô đun con được tải. Ở trên nó thấy rằng đó a/là một thư mục và do đó tạo ra một gói không gian tên avà đó a/b.pylà một tệp nguồn Python mà nó tải và sử dụng để tạo ra một mô-đun (không phải gói) a.b. Tại thời điểm này, bạn không thể có một mô-đun a.b.ca.bkhông phải là một gói và do đó không thể có các mô-đun con.

Bạn cũng có thể thấy ở đây mô-đun gói acó một __path__thuộc tính (các gói phải có điều này) nhưng mô-đun a.bkhông gói không có.


1
Nếu bạn chưa có, hãy quay lại và làm việc thông qua các ví dụ trong câu trả lời này.
Donal Lafferty

2

Một câu trả lời muộn, nhưng một định nghĩa khác:

Một gói được đại diện bởi một thực thể hàng đầu được nhập khẩu, có thể là một mô-đun độc lập hoặc __init__.pymô-đun đặc biệt là thực thể hàng đầu từ một tập hợp các mô-đun trong cấu trúc thư mục con.

Vì vậy, vật lý một gói là một đơn vị phân phối, cung cấp một hoặc nhiều mô-đun.


1
Tôi cảm thấy rằng có hai định nghĩa cho gói trong Python và chúng là khác biệt. Câu trả lời của bạn dường như kết hợp chúng lại với nhau. Nói một cách chính xác, gói python là một thư mục có __init__.pymô-đun bên trong, nhưng nếu bạn nói về các đơn vị phân phối (thường thông qua PyPI) thì đây là một loại gói hoàn toàn khác (thường được xác định bởi sự tồn tại của setup.py). Tôi thấy hai cách sử dụng thuật ngữ này packagegây nhầm lẫn và tôi đã nói chuyện với một số người mới bắt đầu Python, người thấy nó hoàn toàn hoang mang.
davidA

@davidA, đó không chỉ là cảm giác của bạn. Nó được hệ thống hóa: packaging.python.org/glossary/#term-distribution-package (Cảm ơn để làm rõ, quá!)
Lorem Ipsum

0

Gói cũng là một mô-đun có thể chứa các mô-đun khác, 'mô-đun dựa trên tệp đơn giản và gói (gói phụ)'. Mã liên quan đến loại gói mô-đun đi vào __init__.pytệp.

import pack1
print(type(pack1))

trong khi các mô-đun là một tệp đơn giản có thể chứa các hàm, các lớp, mã có thể chạy được, v.v. sau khi nhập một mô-đun, nó hoạt động giống như một đối tượng mà bạn có thể truy cập các định danh được xác định trong mô-đun.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.