モジュール(およびパッケージ)は、プログラムを個別の名前空間に分割するための優れたPythonの方法です。これは、この質問の暗黙の目標のようです。確かに、私はPythonの基本を学んでいたので、ブロックスコープ機能がないことに不満を感じました。しかし、Pythonモジュールを理解すると、ブロックスコープを必要とせずに以前の目標をよりエレガントに実現できました。
動機として、そして人々を正しい方向に向けるために、私はいくつかのPythonのスコープ構成の明示的な例を提供することは有用だと思います。最初に、Pythonクラスを使用してブロックスコープを実装する試みの失敗について説明します。次に、Pythonモジュールを使用して、さらに便利な方法を実現した方法を説明します。最後に、データのロードとフィルタリングへのパッケージの実用的なアプリケーションについて概説します。
クラスでブロックスコープを試す
しばらくの間、クラス宣言内にコードを貼り付けることでブロックスコープを達成したと思いました。
x = 5
class BlockScopeAttempt:
x = 10
print(x) # Output: 10
print(x) # Output: 5
残念ながら、これは関数が定義されている場合に機能しなくなります。
x = 5
class BlockScopeAttempt:
x = 10
print(x) # Output: 10
def printx2():
print(x)
printx2() # Output: 5!!!
これは、クラス内で定義された関数がグローバルスコープを使用するためです。これを修正する最も簡単な(唯一ではありませんが)方法は、クラスを明示的に指定することです。
x = 5
class BlockScopeAttempt:
x = 10
print(x) # Output: 10
def printx2():
print(BlockScopeAttempt.x) # Added class name
printx2() # Output: 10
クラスに含まれているかどうかに応じて関数を異なる方法で記述する必要があるため、これはそれほどエレガントではありません。
Pythonモジュールでより良い結果
モジュールは静的クラスに非常に似ていますが、モジュールは私の経験でははるかにきれいです。モジュールで同じことを行うにはmy_module.py
、現在の作業ディレクトリに次の内容で呼び出されるファイルを作成します。
x = 10
print(x) # (A)
def printx():
global x
print(x) # (B)
次に、メインファイルまたはインタラクティブ(例:Jupyter)セッションで、
x = 5
import my_module # Output: 10 from (A)
my_module.printx() # Output: 10 from (B)
print(x) # Output: 5
説明として、各Pythonファイルは独自のグローバル名前空間を持つモジュールを定義します。モジュールをインポートすると、この名前空間の変数に.
構文でアクセスできます。
インタラクティブセッションでモジュールを使用している場合は、最初にこれらの2行を実行できます。
%load_ext autoreload
%autoreload 2
モジュールは、対応するファイルが変更されると自動的に再ロードされます。
データのロードとフィルタリングのためのパッケージ
パッケージの概念は、モジュールの概念を少し拡張したものです。パッケージは、__init__.py
インポート時に実行される(おそらく空白の)ファイルを含むディレクトリです。このディレクトリ内のモジュール/パッケージには、.
構文でアクセスできます。
データ分析では、大きなデータファイルを読み取ってから、さまざまなフィルターをインタラクティブに適用する必要があります。ファイルの読み取りには数分かかるので、1回だけ行いたいと思います。私はオブジェクト指向プログラミングについて学校で学んだことを基に、以前はクラスのメソッドとしてフィルタリングとロードのコードを書くべきだと信じていました。このアプローチの主な欠点は、フィルターを再定義すると、クラスの定義が変更されるため、データを含むクラス全体を再ロードする必要があることです。
最近のPythonでは、およびmy_data
という名前のサブモジュールを含むというパッケージを定義しています。内部では相対インポートを行うことができます:load
filter
filter.py
from .load import raw_data
私が変更した場合filter.py
、そのautoreload
変更を検出します。再読み込みしないload.py
ので、データを再読み込みする必要はありません。このようにして、Jupyterノートブックでフィルタリングコードのプロトタイプを作成し、関数としてラップして、ノートブックから直接に貼り付けfilter.py
ます。これを理解することは私のワークフローに革命をもたらし、私を懐疑論者から「Pythonの禅」への信者へと変えました。
One purpose (of many) is to improve code readability
-正しく記述された(つまり、zen of pythonに従って)Pythonコードは、そのような飾りが読みやすくなる必要はありません。実際、それは私がPythonについて気に入っている(多くの)ことの1つです。