はじめに
もし大きなプログラムを書く場合、一番上のレベルで独立したファイルの大きなコレクションとして整理するのはあまり望ましくありません。このセクションでは、パッケージの概念を紹介します。
もし大きなプログラムを書く場合、一番上のレベルで独立したファイルの大きなコレクションとして整理するのはあまり望ましくありません。このセクションでは、パッケージの概念を紹介します。
どの Python ソースファイルもモジュールです。
## foo.py
def grok(a):
...
def spam(b):
...
import 文はモジュールを読み込み、そして 実行 します。
## program.py
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
より大きなコードのコレクションの場合、モジュールをパッケージに整理するのが一般的です。
## これから
pcost.py
report.py
fileparse.py
## これにする
porty/
__init__.py
pcost.py
report.py
fileparse.py
名前を選んでトップレベルのディレクトリを作成します。上の例では porty です(明らかにこの名前を選ぶことが一番重要な最初のステップです)。
ディレクトリに __init__.py ファイルを追加します。これは空でもかまいません。
ソースファイルをディレクトリに配置します。
パッケージはインポートの名前空間として機能します。
これは、今では階層的なインポートが可能になることを意味します。
import porty.report
port = porty.report.read_portfolio('portfolio.csv')
インポート文には他にもバリエーションがあります。
from porty import report
port = report.read_portfolio('portfolio.csv')
from porty.report import read_portfolio
port = read_portfolio('portfolio.csv')
このアプローチには主に二つの問題があります。
ですから、基本的にすべてが機能しなくなります。でも、それ以外は機能します。
同じパッケージ内のファイル間でのインポートでは、インポートにパッケージ名を含める必要があります。構造を覚えておいてください。
porty/
__init__.py
pcost.py
report.py
fileparse.py
修正されたインポートの例。
from porty import fileparse
def read_portfolio(filename):
return fileparse.parse_csv(...)
すべてのインポートは 絶対的 であり、相対的ではありません。
import fileparse ## エラーになります。fileparse が見つかりません
...
パッケージ名を直接使用する代わりに、. を使って現在のパッケージを参照することができます。
from. import fileparse
def read_portfolio(filename):
return fileparse.parse_csv(...)
構文:
from. import modname
これにより、パッケージ名を変更することが簡単になります。
パッケージのサブモジュールをメインスクリプトとして実行するとエラーになります。
$ python porty/pcost.py ## エラーになります
...
理由:単一のファイルで Python を実行しているため、Python はパッケージ構造の残りの部分を正しく認識できません(sys.pathが間違っています)。
すべてのインポートがエラーになります。これを修正するには、-m オプションを使用して、別の方法でプログラムを実行する必要があります。
$ python -m porty.pcost ## 正常に動作します
...
__init__.py ファイルこれらのファイルの主な目的は、モジュールをまとめることです。
例:関数の統合
## porty/__init__.py
from.pcost import portfolio_cost
from.report import portfolio_report
これにより、インポート時に名前が トップレベル に表示されます。
from porty import portfolio_cost
portfolio_cost('portfolio.csv')
階層的なインポートを使う代わりに。
from porty import pcost
pcost.portfolio_cost('portfolio.csv')
前述の通り、パッケージ内のスクリプトを実行するには、-m package.module を使用する必要があります。
$ python3 -m porty.pcost portfolio.csv
別の方法もあります。新しいトップレベルのスクリプトを書きます。
#!/usr/bin/env python3
## pcost.py
import porty.pcost
import sys
porty.pcost.main(sys.argv)
このスクリプトはパッケージの 外側 にあります。たとえば、ディレクトリ構造を見ると:
pcost.py ## トップレベルのスクリプト
porty/ ## パッケージディレクトリ
__init__.py
pcost.py
...
コードの組織化とファイル構造は、アプリケーションの保守性にとって重要です。
Python には「万能」のアプローチはありません。ただし、多くの問題に対応できる構造の 1 つは、次のようなものです。
porty-app/
README.txt
script.py ## スクリプト
porty/
## ライブラリコード
__init__.py
pcost.py
report.py
fileparse.py
トップレベルの porty-app は、その他のすべてのもの(ドキュメント、トップレベルのスクリプト、サンプルなど)のコンテナです。
再び、トップレベルのスクリプト(あれば)はコードパッケージの外に存在する必要があります。1 階層上に。
#!/usr/bin/env python3
## porty-app/script.py
import sys
import porty
porty.report.main(sys.argv)
この時点で、いくつかのプログラムが含まれるディレクトリがあります。
pcost.py ## ポートフォリオのコストを計算する
report.py ## レポートを作成する
ticker.py ## リアルタイムの株価チェッカーを生成する
他の機能を持つさまざまなサポートモジュールがあります。
stock.py ## 株式クラス
portfolio.py ## ポートフォリオクラス
fileparse.py ## CSV解析
tableformat.py ## フォーマットされたテーブル
follow.py ## ログファイルを追跡する
typedproperty.py ## 型付きのクラスプロパティ
このチャレンジでは、コードを整理して共通のパッケージに入れます。
porty/ というディレクトリを作成し、上記のすべての Python ファイルをその中に入れます。さらに空の __init__.py ファイルを作成し、それを同じディレクトリに置きます。以下のようなファイルのディレクトリができるはずです。
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
ディレクトリにある __pycache__ ファイルを削除します。これには以前の事前コンパイル済みの Python モジュールが含まれています。新しく始めましょう。
パッケージのいくつかのモジュールをインポートしてみましょう。
>>> import porty.report
>>> import porty.pcost
>>> import porty.ticker
これらのインポートが失敗した場合は、適切なファイルに移動して、モジュールインポートを修正して、パッケージ相対インポートを含めます。たとえば、import fileparse のようなステートメントは、次のように変更される場合があります。
## report.py
from. import fileparse
...
from fileparse import parse_csv のようなステートメントがある場合は、コードを次のように変更します。
## report.py
from.fileparse import parse_csv
...
すべてのコードを「パッケージ」に入れるだけでは、アプリケーションには不十分なことが多いです。時にはサポートファイル、ドキュメント、スクリプト、その他のものが必要です。これらのファイルは、上で作成した porty/ ディレクトリの外に存在する必要があります。
porty-app という新しいディレクトリを作成します。チャレンジ 9.1 で作成した porty ディレクトリをそのディレクトリに移動させます。portfolio.csv と prices.csv のテストファイルをこのディレクトリにコピーします。さらに、自分に関する情報を含む README.txt ファイルを作成します。あなたのコードは現在、次のように整理されるはずです。
porty-app/
portfolio.csv
prices.csv
README.txt
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
コードを実行するには、トップレベルの porty-app/ ディレクトリで作業していることを確認する必要があります。たとえば、ターミナルから:
$ cd porty-app
$ python3
>>> import porty.report
>>>
以前のいくつかのスクリプトをメインプログラムとして実行してみましょう。
$ cd porty-app
$ python3 -m porty.report portfolio.csv prices.csv txt
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
$
python -m コマンドを使用すると、ときどき少々奇妙な感じがします。パッケージの不具合を単純に処理するトップレベルのスクリプトを書きたい場合があります。上記のレポートを生成する print-report.py というスクリプトを作成します。
#!/usr/bin/env python3
## print-report.py
import sys
from porty.report import main
main(sys.argv)
このスクリプトをトップレベルの porty-app/ ディレクトリに置きます。その場所で実行できることを確認しましょう。
$ cd porty-app
$ python3 print-report.py portfolio.csv prices.csv txt
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
$
最終的なコードは、現在、次のような構造になっているはずです。
porty-app/
portfolio.csv
prices.csv
print-report.py
README.txt
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
おめでとうございます!あなたはパッケージの実験を完了しました。あなたのスキルを向上させるために、LabEx でさらに多くの実験を行って練習してください。