Python プロジェクトをエンジニアリングするためのベスト プラクティスのガイド

Python エンジニアリングの統一された仕様やプロジェクト管理計画はありません。これはおそらく、Python の急速な普及が比較的短期間であり、大規模なプロジェクトを開発する企業が少ないためです。そこで、内部学生が Python エンジニアリングの問題をより適切に解決し、個人の開発習慣やコード管理のアイデアを共有できるようにするために、この記事を書きました。

依存関係の管理

PEP 518 と pyproject.toml が導入される前。プロジェクトは、pip のようなツールに、どのビルド ツールをビルドする必要があるかを伝えることができません。現在、setuptools には、プロジェクトのビルドに必要なものを指定するための setup_require パラメーターがありますが、setuptools がインストールされていない限り、その設定を読み取ることはできません。つまり、setuptools で設定を読み取るために setuptools が必要であると宣言することはできません。鶏が先か卵が先かの問題は、なぜ virtualenv のようなツールがデフォルトで setuptools をインストールするのか、また、明示的にインストールするかどうかに関係なく、setup.py の実行時に pip が常に setuptools と Wheel を挿入するのはなぜかということです。バージョンを指定する方法がないため、プロジェクトをビルドするために setuptools の特定のバージョンに依存しようとさえすべきではありません。ユーザーがたまたまインストールしたものに従う必要があります。

PEP 518 以降では、ビルド ツールと必要なバージョンを宣言できます。

これまでは、プロジェクトに必要な依存関係を保存するために、requirements.txt などのファイルをよく使用していましたが、運用環境、開発環境、テスト環境で必要な依存関係を区別する良い方法がありませんでした。いくつかの新しいビルド ツールを使用すると問題を解決できることを複数のファイルに分割する必要があります。また、requirements.txt だけでは、必要な Python のバージョンやシステム環境などを宣言できません。

この社内プロジェクト開発では、次世代の Python パッケージ管理ツールを目指すPDMを選択しました。もともとは個人的な興味から生まれました。pipenvが本当に優れていると感じたりpoetry、使用したりしており、新しいパッケージ マネージャーを導入したくない場合は、そのまま使用してください。ただし、これらのツールでサポートされていないものを見つけた場合は、おそらく で見つけることができますpdm

Pipenv や PDM と同様に、Poetry は Python 仮想環境および依存関係管理ツールであり、パッケージ化や公開などのパッケージ管理機能も提供します。これは、Pipenv や Flit などのツールのスーパーセットと考えることができます。Poetry を使用して Python ライブラリと Python プログラムの両方を管理できるようになります。

PDM または Poetry を使用している場合は、virtualenv 経由でプロジェクト ディレクトリに .venv などのフォルダーを作成してください。PEP582 ではなく virtualenv を推奨するのはなぜですか? 多くのシステムは、デフォルトの Python バージョンに依存しています。PEP582 が使用されている場合、システムに付属の Python バージョンがデフォルトで使用されます。そうでない場合は、必要な Python バージョンに対応する仮想環境を追加で生成する必要があります。その後、現在 vscode が実行します。それをサポートしません。

これらのビルド ツールを使用すると、開発環境、テスト環境、運用環境の依存関係を分離できます。

サービスを開始するための start コマンドやテストのための test コマンドなど、pyproject.toml にツールを構築するための追加コマンドを追加することもできます。PDM スクリプトで説明されているものと同様ですビルド ツールを使用してサービスを開始すると、パッケージの場所に関する問題が効果的に解決され、すべてのパッケージの実行ディレクトリがプロジェクトのルート ディレクトリになるように強制できます。

プロジェクト構造

推奨されるプロジェクト構造は次のとおりです。

Dockerfile

このファイルは主に Docker 用のイメージを構築するために使用されます。運用環境にデプロイする場合は、Docker を介してデプロイすることをお勧めします。

ドキュメント

文書を保存するための専用フォルダーです。

ライセンス

これがオープン ソース プロジェクトの場合、このファイルは通常、使用されるオープン ソース プロトコルを配置するために使用されます。

pyproject.toml

PEP518仕様に基づいた設定ファイルには、プロジェクトの紹介、作成者の連絡先情報、依存パッケージ、使用したビルドツールなどが保存されます。

README.md

主にプロジェクトの紹介や使用説明などのMarkDownドキュメントに使用されます。

{プロジェクト名}

実際のプロジェクト コードが配置されるフォルダーには任意の名前を選択できますが、依存する他のサードパーティ パッケージの名前と重複しないようにする必要があります。src を使用しない理由は、テスト ケースを作成したり、他のプロジェクトの Python パッケージとして使用したりするのに便利だからです。

{project_name}-スタブ

{project_name}-stubs の project_name は、上記のフォルダーの名前と同じである必要があり、その後 splice -stubs となります。たとえば、プロジェクトの名前が andy の場合、このフォルダーは andy-stubs と呼ばれます。プロジェクトが Python ライブラリの場合、mypy によって生成された型記述ファイルをこのフォルダーに保存できます。mypy はこのプロジェクトの型記述を自動的に読み取ってくれるので、型判定に便利です。詳細については、mypy のドキュメントを参照してください。

テスト

単体テスト用のフォルダなど。

tox.ini

tox 設定ファイル。

.gitignore

どのファイルを無視する必要があるかを git に指示するために使用されます。

モジュールリファレンス

Python モジュールは主要な抽象化レイヤーの 1 つであり、おそらく最も自然なものです。抽象化レイヤーを使用すると、コードをさまざまな部分に分割でき、各部分には関連するデータと関数が含まれます。

たとえば、プロジェクトでは、1 つの層がユーザー操作関連のインターフェイスを制御し、もう 1 つの層が基礎となるデータ操作を処理します。これら 2 つの層を分離する最も自然な方法は、すべての機能インターフェイスを 1 つのファイルに再編成し、すべての低レベル操作を別のファイルにカプセル化することです。この場合、インターフェイス ファイルは、基礎となる操作をカプセル化するファイルをインポートする必要があります。これは、ステートメントimportfrom ... importステートメントを使用して実行できます。import ステートメントを使用すると、このモジュールを使用できるようになります。これは、os や sys を含む組み込みモジュール、インストールされているサードパーティ モジュール、またはプロジェクト内のモジュールにすることができます。

スタイル ガイドに準拠するには、モジュール名を短くし、小文字を使用し、ドット (.) や疑問符 (?) などの特殊記号を避けてください。そのようなmy.spam.py名前は使用してはなりません。このように名前を付けると、Python のモジュール検索機能が妨げられます。my.spam.py の場合、Python はmyフォルダー内でファイルが見つかることを期待しますspam.pyが、そうではありません。必要に応じてモジュールに の名前を付けることができますmy_spam.pyが、モジュール名にアンダースコアを使用することはお勧めできません。ただし、モジュール名に他の文字 (スペースまたはハイフン) を使用するとインポートが妨げられるため (- は減算演算子)、単語を区切る必要がないようにモジュール名を単純にするようにしてください。最も重要なことは、アンダースコア名前空間を使用せず、代わりにサブモジュールを使用することです。

# OK
import library.plugin.foo
# not OK
import library.foo_plugin
复制代码

上記の命名制限に加えて、Python ファイルをモジュールにするための特別な要件はありませんが、この概念を合理的に使用して問題を回避するには、インポートの原理メカニズムを理解する必要があります。具体的には、import moduこのステートメントは適切なファイル、つまりmodu.py呼び出しディレクトリ内のファイルが存在する場合はそのファイルを検索します。ファイルが見つからない場合、Python インタープリターは「PYTHONPATH」環境変数でファイルを再帰的に検索します。それでも見つからない場合は、ImportError 例外がスローされます。

モジュールが見つかるとmodu.py、Python インタープリターは分離されたスコープでモジュールを実行します。他の参照も含め、すべてのトップレベルのステートメントが実行されます。メソッドとクラスの定義はモジュールの辞書に保存されます。このモジュールの変数、メソッド、クラスは、名前空間を通じて呼び出し元に公開されます。これは、Python の特に便利で強力な中心概念です。

他の多くの言語では、include fileディレクティブは、ファイル内のすべてのコードを取得し、呼び出し元のコードに「コピー」するためにプリプロセッサによって使用されます。Python は異なります。インクルード コードはモジュール名前空間に独立して配置されます。つまり、インクルード コードが同じ名前のメソッドをオーバーロードするなどの悪影響を引き起こす可能性があることを通常は心配する必要はありません。

from modu import *特別な形式の import ステートメントを使用して、より標準的な動作をエミュレートすることもできます。しかし、import *一般的には悪い習慣だと考えられています。使用しているコードfrom modu import *は読みにくく、依存関係の独立性が不十分です。from modu import funcインポートするメソッドを特定し、グローバル名前空間に配置するために使用します。from modu import *グローバル名前空間にインポートされるメソッドが明示的に示されるため、より優れています。唯一import moduの利点は、後でメソッドを使用するときに入力が少なくて済むことです。

import modu
[...]
x = modu.sqrt(4)
复制代码

次に、自分のプロジェクトのモジュールを参照し、my という名前のプロジェクトと modu という名前のモジュールを追加する場合、これを参照として使用することはお勧めできません。使用することを強くお勧めしfrom my import moduますfrom . import modu

__init__.py次に、他のモジュールのいくつかのクラスを参照する必要がある場合は、このモジュールでそれらを公開し、一部の言語でエクスポートを置き換えるために as を追加することをお勧めします。

from .config import Config as Config
复制代码

__init__.py  また、大量のコードを配置することはまったく推奨されません。エクスポートを置き換えることのみが推奨されます。

に追加されるコードが多__init__.pyすぎると、プロジェクトの複雑さが増すにつれて、ディレクトリ構造がますます深くなり、サブパッケージやより深くネストされたサブパッケージが表示される場合があります。この場合、複数レベルのネストされたサブパッケージ内のコンポーネントをインポートするには、__init__.pyパス内で見つかったすべてのファイルを実行する必要があります。パッケージ内のモジュールとサブパッケージにコード共有要件がない場合は、空の__init__.pyファイルを使用するのが通常、または推奨事項です。

型チェック

Python は動的言語です。多くの場合、関数のパラメータの型や戻り値の型がわからないことがあります。一部の型には指定されたメソッドがない可能性が非常に高いです。しばらくコードを書いてからコードを見直すと、書いたことを忘れている可能性があります。関数がどのようなパラメータを渡す必要があり、どのような種類の結果を返す必要があるかについては、コードの具体的な内容を読み取る必要があるため、読み取り速度が低下します。タイピング モジュールはこの問題を解決できます。結構。

python3.5 以降、PEP484 では Python の型アノテーション (型ヒント) が導入されました。

Mypy は Python の静的型チェッカーです。Mypy には、型推論、ジェネリックス、呼び出し可能型、タプル型、共用体型、構造サブタイプなどの多くの優れた機能を備えた強力で使いやすい型システムがあります。型チェック ツールとして mypy を使用することをお勧めします。各メソッドはパラメーター、パラメーターの型、および戻り値の型を明確に宣言する必要があります。

def register(
    self, factory: Optional[PooledObjectFactory] = None, name: Optional[str] = None
) -> None:

	pass
复制代码

パラメーターまたは戻り値が空である可能性がある場合は、オプションとしてマークするか、構文タイプ 3.11 | None を使用する必要があります。PooledObjectFactory | None など。

vscode では、mypy プラグインをインストールできるため、型チェックを vscode で直接行うことができます。

コードのフォーマットとスタイルのチェック

開発者がコード スタイルを統一できるようにするために、Python コミュニティは PEP8 コード コーディング スタイルを提案しましたが、これは誰もがそれに従う必要はなく、Python はコード スタイルが PEP8 に準拠しているかどうかを確認するツール (pep8 とも呼ばれます) を正式に開始しました。

Black は自らを「妥協のないコードフォーマッタ」と呼んでいます。

Black は、妥協のない Python コード整形ツールであると主張しています。なぜ「妥協しない」のかというと、仕様に準拠していないコードスタイルを検出し、すべてを直接フォーマットしてくれるため、確認する必要がなく、直接判断する必要がありません。その代わりに、ブラックは高速な速度を提供します。黒では、最小限の差分が生成されるため、より迅速なコード レビューが可能になります。Black の使用方法は非常に簡単で、インストールが成功したら、black コマンドの後にフォーマットするファイルまたはディレクトリを指定するだけで、他のシステム コマンドと同様に使用できます。

ある意味、チーム内では、大幅にカスタマイズできるツールよりも、構成可能性が非常に低いコードのフォーマットおよび検査ツールの方が適しています。最新の IDE は通常、黒をサポートしています。

構成管理

構成を {project_name}/{project_name} フォルダーに配置し、yaml 形式で保存することをお勧めします。toml などの形式を使用しない理由は、k8s などの構成マッピング機能を使用すると利用できないことと、yaml は他のシステムとの互換性が高いためです。

構成が配置されている yaml ファイルを読み取り、それを構成オブジェクトに逆シリアル化できます。この構成オブジェクトは Python のデータクラスまたは通常のクラスにすることができ、構成の各フィールドは上で宣言されています。

設定ではフィールドの追加や削除が頻繁に行われるため、辞書のような方法で行うべきではありません。

例外管理

例外は、ほぼすべてのプログラミング言語に存在します。例外によりプログラムの問題をすぐに指摘できるため、トラブルシューティングに便利です。開発者は、状況に応じてカスタム例外をスローして、予想されるコンテンツが実際のコンテンツと一致しないことを示すこともできます。優れた例外設計と使用習慣により、プログラムの品質を向上させることができます。

ロジック内に期待を満たさないロジックが存在する可能性があり、関連する例外がスローされます。このとき、コーディング時にロジックが正常に動作するためには、ロジックを処理して例外をキャッチする必要があります。

例外をキャッチするには、try...exceptコード ブロックを使用して、例外を処理する必要があるコードをラップします。expect指定された例外タイプをキャッチし、発生した場合は対応するコード ロジックを入力します。raise例外をスローして処理したくない人もいます。

キャプチャするときは、Exception などの広範な例外基本クラスをキャプチャするのではなく、ValueError などの特定の例外をキャプチャするようにしてください。

例外を処理する場合、例外がスローされ続けない場合は、ログ情報を入力する必要があります。情報をアウトプットしなくても間違いが起こりにくくなるということを知っていなければ別ですが。項目の例外ERRORは で終わる必要があります。標準の例外の名前付けに似ています。

テスト

Python の組み込みテスト フレームワークに加えて、多くのサードパーティ テスト フレームワークがあり、一部の非テスト フレームワークにも組み込みテスト フレームワークがあります。その目的は、組み込みのテスト フレームワークに基づいていくつかの機能を追加して、テストの作成をより便利にし、テスト プロセスをよりスムーズにすることです。

テスト フレームワークがテスト ケースを見つけやすくするには、テストを作成するときに特定の仕様に従う必要があります。

  • テストモジュールは次でtest_始まります
  • テスト方法はtest_次から始める必要があります
  • テストクラス名は次でTest始まる必要があります。

テストは、tests フォルダーの下に配置されます。

Pytest は、テストをより簡単かつ柔軟にするために、unittest に基づいて多くの糖衣構文を追加します。また、他の機能の統合を容易にするプラグイン機能を備えています。

Pytest は他のほとんどのテスト フレームワークと互換性があり、強力な機能も備えているため、メインのテスト フレームワークとして Pytest を使用することをお勧めします。

tox は、汎用の仮想環境管理およびテスト コマンド ライン ツールです。tox を使用すると、同じホスト上で複数の独立した分離された Python 環境をカスタマイズできます。プロジェクトが複数の Python バージョンと互換性を持つ必要がある場合は、tox を使用することを強くお勧めします。

おすすめ

転載: blog.csdn.net/weixin_73136678/article/details/128794036