PythonモジュールとPythonパッケージの違いは何ですか?
"package"と "module"の違いは何ですか (他の言語の場合)
モジュールは、1回のインポートでインポートされ使用される単一のファイルです。例えば.
import my_module
パッケージは、パッケージ階層を与えるディレクトリ内のモジュールの集まりです。
from my_package.timing.danger.internets import function_of_love
どのPythonファイルも モジュール であり、その名前はファイルの.py
拡張子を除いた基本名です。 パッケージ はPythonモジュールの集まりです。モジュールは単一のPythonファイルですが、パッケージは追加の__init__.py
ファイルを含むPythonモジュールのディレクトリです。たまたまたくさんのPythonスクリプトが入っているディレクトリとパッケージを区別するため。対応するディレクトリに独自の__init__.py
ファイルが含まれている場合、パッケージは任意の深さにネストできます。
モジュールとパッケージの違いは、ファイルシステムレベルでのみ成り立つようです。モジュールまたはパッケージをインポートすると、Pythonによって作成された対応するオブジェクトは常にmodule
型になります。ただし、パッケージをインポートすると、そのパッケージの__init__.py
ファイル内の変数/関数/クラスのみが直接表示されます。notサブパッケージまたはモジュールは表示されません。例として、Python標準ライブラリのxml
パッケージを考えてみましょう。そのxml
ディレクトリには、__init__.py
ファイルと4つのサブディレクトリがあります。サブディレクトリ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にはCで書かれたsys
のような組み込みモジュールもありますが、あなたが質問の中でそれらを考慮するつもりはないと思います。
すべてのパッケージがモジュールであることを覚えておくことは重要ですが、すべてのモジュールがパッケージであるわけではありません。言い換えれば、パッケージは単なる特別な種類のモジュールです。特に、
__path__
属性を含むモジュールはすべてパッケージと見なされます。
my-file.py
のように名前にダッシュが入っているPythonファイルは、単純なimport
ステートメントではインポートできません。コード的には、import my-file
はimport my - file
と同じで、例外が発生します。そのようなファイルはスクリプトとしてよりよく特徴付けられますが、インポート可能なファイルはモジュールです。
まず、その正確な定義では、モジュールはPythonインタープリターのメモリ内のオブジェクトであり、多くの場合、ディスクから1つ以上のファイルを読み取ることによって作成されることに注意してください。 a/b/c.py
などのディスクファイルを非公式に「モジュール」と呼ぶこともありますが、実際には、他のいくつかのソース(sys.path
など)からの情報と組み合わせてモジュールオブジェクトを作成するまで1つになりません。
(たとえば、sys.path
およびその他の設定に応じて、異なる名前の2つのモジュールを同じファイルからロードできることに注意してください。これは、python -m my.module
に続いてimport my.module
インタープリターには、2つのモジュールオブジェクト__main__
とmy.module
があり、両方ともディスク上の同じファイルmy/module.py
から作成されます。
パッケージは、サブモジュール(サブパッケージを含む)を持つ可能性のあるモジュールです。すべてのモジュールがこれを実行できるわけではありません。例として、小さなモジュール階層を作成します。
$ 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/
がディレクトリであることがわかり、名前空間パッケージa
が作成され、a/b.py
がPythonソースファイルであり、ロードして作成に使用されます(非パッケージ)モジュールa.b
。この時点では、a.b.c
はパッケージではないため、サブモジュールを持つことはできないため、モジュールa.b
を使用することはできません。
また、パッケージモジュールa
には__path__
属性がありますが(パッケージにはこれが必要です)、非パッケージモジュールa.b
にはないことがわかります。
もう一つの定義、遅い答えです。
パッケージは、自己完結型モジュール、またはサブディレクトリ構造内の一連のモジュールの最上位エンティティとしての
__init__.py
特殊モジュールのいずれかである可能性があるインポートされた最上位エンティティによって表されます。
したがって、物理的にはパッケージは1つ以上のモジュールを提供する配布単位です。