
こんにちは、Habrahabr。 今日、私は別の翻訳を翼に持ち込みました(Google スタイルガイドの PDFがレイアウトされています)。 ただし、誰かがこの作品を高く評価しているなら、おそらく続編が登場するでしょう。 ある日、狭いサークルでよく知られている私の同僚の同僚は、 リソース-Python へのヒッチハイクガイドを読むことを提案しました! と呼ばれます。 このリソースが気に入りました。 そこで出されたヒントが気に入りました。 私は物語の概要が好きで、一般的に著者の考えの方向が好きでした。 そして、あなたの好みに合ったものがあれば、口コミで伝える必要があります:)それで、このリソースを翻訳することにしました。 しかし、すべてがそうすぐにあるわけではありません-最初に、habrasocietyの「応答への」トライアル記事があります。 このテーマやプレゼンテーションのような尊敬されるオタクであれば、新しいパーツのリリースを試みます。 最初の「応答」については、「 優れたコードの記述 」というセクションを選択し、その中の2つのサブ項目「構造が重要」と「モジュール」を選択しました。 カットの下で対応しましょう。
しかし、あなたが最愛のPythonについて他の人の考えに真っ向から飛び込む前に、リソースの著者自身を紹介する必要があります。 彼の名前はケネスライツです。 収集した情報から理解できるように、彼はプロの写真家であり(彼の個人的なWebサイトで確認できます)、Python言語の伝道者であり、さまざまな開発の第一人者です。 彼は現在、Herokuで働いています(未確認の報告による)。 また、 githubで彼のプロジェクトを分岐するよう全員に呼びかけます。
ケネス写真
PyCon AustraliaでのKenneth Reitz(2012)

次は記事そのものです。 (いつものようにエラーを見つけたら、すぐにそれらについて叫んでください!エラーを修正する必要があります。)
プロジェクトを構築する
構造とは、プロジェクトがその目標をどのように達成できるかに関してあなたが下した決定を意味します。 クリーンで効率的なコードを記述するために、Python言語の機能的特徴をどのように使用するのが最善かを考慮する必要があります。 実用的な観点から、「構造」の概念は、論理と依存関係がファイルシステム内のファイルとフォルダーの編成と同じくらい明確な場合に、クリーンな作成(書き込み)を意味します。
どの機能をどのモジュールに移動する必要がありますか? データはプロジェクトをどのように流れますか? グループ化して分離できる機能は何ですか? このような質問に答えることで、完成品の外観を計画することができます。
このセクションでは、Pythonのモジュールとインポートシステムを詳しく見ていきます。 これらは、プロジェクトの構造化を保証する中心的な要素です。 次に、拡張して確実にテストできるコードを構築する方法に関するさまざまな観点について説明します。
構造が決定する
インポートとモジュールはPythonで処理されるため、この言語で書かれたプロジェクトを構築するのは比較的簡単です。 このコンテキストで「単純」という言葉は、不要な制限を作成しないこと、およびインポートされたモジュールのモデルが理解しやすいことを意味します。 したがって、純粋にアーキテクチャ上のタスク、つまりプロジェクトのさまざまな部分の作成とその相互作用に集中する必要があります。
単純な構造化プロジェクト-不十分な構造化プロジェクトを作成することもできます。 不十分な構造のプロジェクトの兆候:
- 複数のダーティな循環依存。 質問
table.isdoneby()
に回答するためにTable
とChair
クラスがworkers.py
モジュールからCarpenter
クラスをインポートする必要がある場合、またはその逆の場合、Carpenter
クラスがCarpenter
質問に回答するためにTable
クラスとChair
クラスをインポートする必要がある場合carpenter.whatdo()
-循環依存関係を取得します。 この場合、メソッドまたは関数内でimportステートメントを使用するなど、トリッキーなトリックに頼らなければなりません。 - 非表示の接続。
Table
クラスのすべての変更は、無関係のテストで20のテストに失敗します。Carpenter
クラスコードの実行をゆがめるため、外科的に微妙な適応コードの変更が必要です。 これは、Carpenter
クラスのコード内のTableクラスに関する「規約」が多すぎること、またはその逆を意味します。 - グローバルな名前空間またはコンテキストの集中的な使用。
Table
クラスとCarpenter
クラスを使用して(高さ、幅、タイプ、ツリー)変数を相互に明示的に渡す代わりに、異なる「仲間」によってオンザフライで変更および変更できるグローバル変数に依存します。 これらのグローバル変数にアクセスできるすべての場所を注意深く調べて、長方形のテーブルが正方形になった理由を理解し、テーブルのサイズを変更することでこのコンテキストでリモートコードも変更されていることを確認する必要があります。 - スパゲッティコード。 スパゲッティコードと呼ばれる、多数の繰り返しコードを持ち、セグメント化をまったく行わない、ネストされた
if
構造とfor
ループのいくつかのページ。 Pythonの重要なインデント(最も議論されている機能の1つ)のおかげで、このようなコードをこの言語で記述することは非常に困難です。 良いニュースがあります-そのようなコードを頻繁に観察することはありません。 - ラビオリのコード。 このようなコードは、Pythonでより一般的です。 それは、適切な構造化のない何百もの同一の(または互いに類似した)ロジック、クラス、またはオブジェクトで構成されています。
FurnitureTable
、AssetTable
、Table
、またはAssetTable
を使用して問題を解決しないことを覚えていない場合は、ラビオリコードを使用します。
モジュール
Pythonのモジュールは、利用可能な抽象化の主要なレイヤーの1つであり、おそらく言語の最もネイティブなものです。 抽象化レベルにより、コードを対応するデータを処理する部分に分割し、機能を含めることができます。
たとえば、1つのプロジェクトレイヤーでユーザーの操作を処理し、もう1つのプロジェクトレイヤーで低レベルのデータ操作を処理できます。 これら2つのレベルを分離する最も自然な方法は、すべての機能を1つのファイルに入れ、すべての低レベルの操作を別のファイルに入れることです。 この場合、インターフェイスファイルは、低レベルの機能を備えたファイルをインポートする必要があります。 これは、
import
および
from ... import
式を使用して行われます。
importステートメントの使用を開始するとすぐに、モジュールの使用を開始します。 これらは、
os
や
sys
などの組み込みモジュール、環境にインストールしたサードパーティモジュール、またはプロジェクトの内部モジュールです。
リーダーシップスタイルを順守するには、小文字のみを含むモジュールに短い名前を付け、ピリオド(。)や疑問符(?)などの特殊文字を使用しないようにしてください。 ファイル名はmy.spam.pyに似ているため、避ける必要があります。 このように命名すると、Pythonがモジュールを検索できなくなります。
この例では、Pythonは、存在しない「
my
」という名前のフォルダーで「
spam.py
」を見つけることを想定しています。 Pythonドキュメントでドット表記を使用する方法の例があります。
必要に応じて、ファイルに
my_spam.py
という名前を付けることができますが、友人であるUnderlineでさえモジュール名に頻繁に使用しないでください。
いくつかの命名制限に加えて、ファイルはPythonモジュールになるために他に何も必要としませんが、この概念を適切に使用し、いくつかの問題を回避するためにインポートメカニズムを理解する必要があります。
率直に言って、importステートメントは、インポートするファイルと同じディレクトリで対応するmodule.pyファイルを探します。 見つからない場合、Pythonインタープリターは変数「
path
」で
ImportError
再帰的に
ImportError
、後者が見つからない場合は
ImportError
例外をスローします。
module.py
が見つかると、Pythonインタープリターは分離されたスコープでモジュールを実行します。
module.py
最上位の宣言が実行されます(ネストされたインポートがある場合)。 関数とクラスの宣言はモジュール辞書に保存されます。
次に、モジュール変数、関数、およびクラスは、モジュール名前空間を介して呼び出すことができます。これは、Pythonで特に強力で便利なプログラミングの中心概念です。
多くの言語では、ファイルはプリプロセッサを使用して直接インクルードされ、ファイル内のすべてのコードが検索され、呼び出しモジュールのコードに「コピー」されます。 これは、モジュールのスコープ内でプラグインコードが分離されるPython言語の動作とは異なります。つまり、同じ名前の既存の関数をオーバーライドするなど、コードを含めると望ましくない結果が生じる可能性があることを心配する必要はありません。
これにより、式import:
from module import *
の特別な構文を使用して、より標準的な動作をモデル化できます。 これは通常、悪い習慣と見なされます。 「
import *
」を使用すると、コードが読みにくくなり、依存関係の断片化が少なくなります。
from module import func
を使用すると、インポートしてグローバルスコープに入れる関数を特定できます。 また、コードは「
import *
」よりも害が少ないため、 ここでは、グローバルスコープにインポートされるものが明確に示されています。インポートモジュールエントリをより単純にする利点は、キーストロークを保存することです。
# Very bad [...] from modu import * [...] x = sqrt(4) # Is sqrt part of modu? A builtin? Defined above? # Better from modu import sqrt [...] x = sqrt(4) # sqrt may be part of modu, if not redefined in between # Best import modu [...] x = modu.sqrt(4) # sqrt is visibly part of modu's namespace
スタイルのセクションで述べたように、読みやすさはPythonの主要な機能の1つです。 可読性とは、コード内での無駄なテキストコンテンツや混乱の使用を回避することを意味するため、通常、ある程度のコードの簡潔さを達成するためにある程度の努力が費やされます。 しかし、簡潔性と単純さには、コード削減を停止すべき特定の制限があります。
module.func
のイデオロギーのように、特定のクラスまたは関数がどこから始まるのかをすぐに知ることができるため、1つのファイル内の最も単純でほとんどのスタンドアロンプロジェクトを
module.func
、コードの読みやすさとその透明性が大幅に向上します。