Pythonでのメイン関数の定義

Pythonでのメイン関数の定義

多くのプログラミング言語には、オペレーティングシステムがプログラムの実行を開始したときに自動的に実行される特別な機能があります。 この関数は通常main()と呼ばれ、言語標準に従って特定の戻り値の型と引数を持っている必要があります。 一方、Pythonインタープリターはファイルの先頭からスクリプトを実行し、Pythonが自動的に実行する特定の機能はありません。

それにもかかわらず、プログラムの実行のために定義された開始点を持つことは、プログラムの動作を理解するのに役立ちます。 Pythonプログラマーは、この開始点を定義するためのいくつかの規則を考案しました。

この記事の終わりまでに、あなたは理解するでしょう:

  • 特別な__name__変数とは何か、そしてPythonがそれをどのように定義するか

  • Pythonでmain()を使用する理由

  • Pythonでmain()を定義するための規則は何ですか

  • main()にどのコードを入れるかについてのベストプラクティスは何ですか

Free Bonus:Click here to get access to a chapter from Python Tricks: The Bookは、Pythonのベストプラクティスと、より美しい+ Pythonicコードをすぐに適用できる簡単な例を示しています。

基本的なPython main()

一部のPythonスクリプトでは、次の例のような関数定義と条件ステートメントが表示される場合があります。

def main():
    print("Hello World!")

if __name__ == "__main__":
    main()

このコードには、Pythonインタープリターが実行するときにフレーズHello World!を出力するmain()という関数があります。 __name__の値をチェックし、それを文字列"__main__"と比較する条件付き(またはif)ステートメントもあります。 ifステートメントがTrueと評価されると、Pythonインタープリターはmain()を実行します。 条件文の詳細については、Conditional Statements in Pythonを参照してください。

このコードパターンは、executed as a scriptおよびimported in another moduleにしたいPythonファイルでは非常に一般的です。 このコードがどのように実行されるかを理解するには、まず、コードの実行方法に応じてPythonインタープリターが__name__を設定する方法を理解する必要があります。

Pythonの実行モード

Pythonインタープリターにコードを実行または使用するよう指示できる主な方法は2つあります。

  1. コマンドラインを使用して、Pythonファイルをscriptとして実行できます。

  2. あるPythonファイルから別のファイルまたはインタラクティブインタプリタにコードをimportすることができます。

これらのアプローチの詳細については、How to Run Your Python Scriptsを参照してください。 使用しているコードの実行方法に関係なく、Pythonは、コードの使用方法に応じて値が異なる文字列を含む__name__という特別な変数を定義します。

execution_methods.pyとして保存されたこのサンプルファイルを使用して、コンテキストに応じてコードの動作がどのように変化するかを調べます。

print("This is my file to test Python's execution methods.")
print("The variable __name__ tells me which context this file is running in.")
print("The value of __name__ is:", repr(__name__))

このファイルには、print()への3つの呼び出しが定義されています。 最初の2つは、導入フレーズを印刷します。 3番目のprint()は、最初にフレーズThe value of __name__ isを出力し、次にPythonの組み込みrepr()を使用して__name__変数の表現を出力します。

Pythonでは、repr()はオブジェクトの印刷可能な表現を表示します。 この例では、repr()を使用して、__name__の値が文字列であることを強調しています。 Python documentationrepr()の詳細を読むことができます。

この記事全体で使用されているfilemodule、およびscriptという単語が表示されます。 実際には、それらの間に大きな違いはありません。 ただし、コードの目的を強調する意味にはわずかな違いがあります。

  1. File:通常、Pythonファイルはコードを含む任意のファイルです。 ほとんどのPythonファイルの拡張子は.pyです。

  2. Script: Pythonスクリプトは、タスクを実行するためにコマンドラインから実行する予定のファイルです。

  3. Module: Pythonモジュールは、別のモジュールまたはスクリプト内から、あるいは対話型インタープリターからインポートする予定のファイルです。 モジュールの詳細については、Python documentationを参照してください。

この区別については、How to Run Your Python Scriptsでも説明されています。

コマンドラインから実行する

このアプローチでは、コマンドラインからPythonスクリプトを実行します。

スクリプトを実行すると、Pythonインタープリターが実行しているコードをインタラクティブに定義できなくなります。 コマンドラインからPythonを実行する方法の詳細は、この記事の目的にとってそれほど重要ではありませんが、下のボックスを展開して、Windows、Linux、macOSのコマンドラインの違いについて詳しく読むことができます。

次に示すように、コマンドラインからexecution_methods.pyスクリプトを実行する必要があります。

$ python3 execution_methods.py
This is my file to test Python's execution methods.
The variable __name__ tells me which context this file is running in.
The value of __name__ is: '__main__'

この例では、__name__の値が'__main__'であることがわかります。ここで、引用符(')は、値が文字列型であることを示しています。

Pythonでは、一重引用符(')と二重引用符(")で定義された文字列に違いがないことに注意してください。 Basic Data Types in Pythonでの文字列の定義について詳しく読むことができます。

スクリプトにshebang lineを含めて直接実行するか(./execution_methods.py)、IPythonまたはJupyter Notebookで%runマジックを使用すると、同じ出力が見つかります。

コマンドに-m引数を追加することにより、パッケージ内から実行されたPythonスクリプトを確認することもできます。 ほとんどの場合、pipを使用しているときにこれが推奨されます:python3 -m pip install package_name

-m引数を追加すると、パッケージの__main__.pyモジュールのコードが実行されます。 __main__.pyファイルの詳細については、How to Publish an Open-Source Python Package to PyPIを参照してください。

これら3つのケースすべてで、__name__の値は同じです(文字列'__main__')。

Technical detail: Pythonのドキュメントでは、__name__の値が'__main__'になる時期を具体的に定義しています。

モジュールの__name__は、標準入力、スクリプト、または対話型プロンプトから読み取られると、'__main__'と等しくなります。 (https://docs.python.org/3/library/main.html [ソース])

__name__は、__doc____package__、およびその他の属性とともに、モジュールのグローバル名前空間に格納されます。 これらの属性の詳細については、Python Data Model documentationで、特にモジュールとパッケージについては、Python Import documentationで読むことができます。

モジュールまたはインタラクティブインタープリターへのインポート

次に、Pythonインタープリターがコードを実行する2番目の方法、インポートを見てみましょう。 モジュールまたはスクリプトを開発するときは、他の誰かがすでに作成したモジュールを利用したいと思うでしょう。これは、importキーワードを使用して行うことができます。

インポートプロセス中に、Pythonは指定されたモジュールで定義されたステートメントを実行します(ただし、モジュールをインポートする時間はfirst秒のみです)。 execution_methods.pyファイルをインポートした結果を示すには、インタラクティブなPythonインタープリターを起動してから、execution_methods.pyファイルをインポートします。

>>>

>>> import execution_methods
This is my file to test Python's execution methods.
The variable __name__ tells me which context this file is running in.
The value of __name__ is: 'execution_methods'

このコード出力では、Pythonインタープリターがprint()への3つの呼び出しを実行していることがわかります。 出力の最初の2行は、最初の2行のいずれにも変数がないため、コマンドラインでスクリプトとしてファイルを実行したときとまったく同じです。 ただし、3番目のprint()からの出力には違いがあります。

Pythonインタープリターがコードをインポートするとき、__name__の値は、インポートされるモジュールの名前と同じになるように設定されます。 これは、上記の出力の3行目で確認できます。 __name__の値は'execution_methods'です。これは、Pythonのインポート元の.pyファイルの名前です。

Pythonを終了せずにモジュールをimportすると、出力がないことに注意してください。

Note: Pythonでのインポートの仕組みの詳細については、official documentationAbsolute vs Relative Imports in Pythonを確認してください。

Pythonメイン関数のベストプラクティス

Pythonがさまざまな実行モードを処理する方法の違いを確認できたので、使用するベストプラクティスを知っておくと役立ちます。 これらは、別のモジュールまたは対話型セッションでスクリプトandインポートとして実行できるコードを記述したい場合に常に適用されます。

コードが2つの目的に役立つことを確認するための4つのベストプラクティスについて学習します。

  1. ほとんどのコードを関数またはクラスに入れます。

  2. __name__を使用して、コードの実行を制御します。

  3. 実行するコードを含むmain()という関数を作成します。

  4. main()から他の関数​​を呼び出します。

ほとんどのコードを関数またはクラスに入れる

Pythonインタープリターは、モジュールをインポートするときにモジュール内のすべてのコードを実行することに注意してください。 作成するコードには、次のような副作用をユーザーに制御させる場合があります。

  • 時間がかかる計算を実行する

  • ディスク上のファイルへの書き込み

  • ユーザーの端末を混乱させる情報を印刷する

このような場合、モジュールをインポートするときにPythonインタープリターにコードを実行させるのではなく、ユーザーにこのコードの実行のトリガーを制御させます。

したがって、ベストプラクティスはinclude most code inside a function or a classにすることです。 これは、Pythonインタープリターがdefまたはclassキーワードを検出すると、後で使用するためにそれらの定義のみを保存し、指示が​​あるまで実際には実行されないためです。

このアイデアを示すために、以下のコードをbest_practices.pyというファイルに保存します。

 1 from time import sleep
 2
 3 print("This is my file to demonstrate best practices.")
 4
 5 def process_data(data):
 6     print("Beginning data processing...")
 7     modified_data = data + " that has been modified"
 8     sleep(3)
 9     print("Data processing finished.")
10     return modified_data

このコードでは、最初にtime moduleからsleep()をインポートします。

sleep()は、引数として指定した秒数の間インタプリタを一時停止し、この例では実行に長い時間がかかる関数を生成します。 次に、print()を使用して、このコードの目的を説明する文を出力します。

次に、次の5つのことを行うprocess_data()という関数を定義します。

  1. データ処理が開始されていることをユーザーに伝えるために出力を出力します

  2. 入力データを変更します

  3. sleep()を使用して実行を3秒間一時停止します

  4. 処理が終了したことをユーザーに伝えるために出力を出力します

  5. 変更されたデータを返します

コマンドラインでベストプラクティスファイルを実行する

さて、コマンドラインでこのファイルをスクリプトとして実行するとどうなりますか?

Pythonインタープリターは、関数定義の外側にあるfrom time import sleep行とprint()行を実行してから、process_data()という関数の定義を作成します。 次に、スクリプトにはprocess_data()を実行するコードがないため、スクリプトはそれ以上何もせずに終了します。

以下のコードブロックは、このファイルをスクリプトとして実行した結果を示しています。

$ python3 best_practices.py
This is my file to demonstrate best practices.

ここに表示される出力は、最初のprint()の結果です。 timeからインポートしてprocess_data()を定義すると、出力が生成されないことに注意してください。 具体的には、process_data()の定義内にあるprint()への呼び出しの出力は出力されません!

別のモジュールまたはインタラクティブインタプリタにベストプラクティスファイルをインポートする

このファイルを対話型セッション(または別のモジュール)にインポートすると、Pythonインタープリターはファイルをスクリプトとして実行するときとまったく同じ手順を実行します。

Pythonインタープリターがファイルをインポートすると、インポートしたモジュールで定義されている変数、クラス、または関数を使用できます。 これを実証するために、インタラクティブなPythonインタープリターを使用します。 インタラクティブインタプリタを起動し、import best_practicesと入力します。

>>>

>>> import best_practices
This is my file to demonstrate best practices.

best_practices.pyファイルのインポートからの唯一の出力は、process_data()の外部で定義された最初のprint()呼び出しからのものです。 コマンドラインからコードを実行したときと同じように、timeからインポートしてprocess_data()を定義しても出力は生成されません。

if __name__ == "main"を使用して、コードの実行を制御します

コマンドラインからスクリプトを実行するときにprocess_data()を実行したいが、Pythonインタープリターがファイルをインポートしたときに実行したくない場合はどうなりますか?

__name__"__main__"と等しい場合にのみ、use the if __name__ == "main" idiom to determine the execution contextおよび条件付きでprocess_data()を実行できます。 以下のコードをbest_practices.pyファイルの最後に追加します。

11 if __name__ == "__main__":
12     data = "My data read from the Web"
13     print(data)
14     modified_data = process_data(data)
15     print(modified_data)

このコードでは、__name__の値をチェックする条件ステートメントを追加しました。 この条件は、__name__が文字列"__main__"と等しい場合、Trueと評価されます。 __name__変数の"__main__"の特別な値は、Pythonインタープリターがスクリプトを実行していて、それをインポートしていないことを意味することに注意してください。

条件ブロック内に、4行のコード(行12、13、14、および15)を追加しました。

  • Lines 12 and 13: Webから取得したデータを格納する変数dataを作成し、それを印刷します。

  • Line 14:データを処理しています。

  • Line 15:変更したデータを印刷しています。

次に、コマンドラインからbest_practices.pyスクリプトを実行して、出力がどのように変化するかを確認します。

$ python3 best_practices.py
This is my file to demonstrate best practices.
My data read from the Web
Beginning data processing...
Data processing finished.
My data read from the Web that has been modified

まず、出力には、process_data()の外部でのprint()呼び出しの結果が表示されます。

その後、dataの値が出力されます。 これは、Pythonインタープリターがファイルをスクリプトとして実行するときに変数__name__の値が"__main__"であるため、条件ステートメントがTrueに評価されたために発生しました。

次に、スクリプトはprocess_data()を呼び出し、変更のためにdataを渡しました。 process_data()が実行されると、いくつかのステータスメッセージが出力に出力されます。 最後に、modified_dataの値が出力されます。

ここで、インタラクティブインタプリタ(または別のモジュール)からbest_practices.pyファイルをインポートするとどうなるかを確認する必要があります。 以下の例は、この状況を示しています。

>>>

>>> import best_practices
This is my file to demonstrate best practices.

ファイルの最後に条件文を追加する前と同じ動作になることに注意してください! これは、__name__変数の値が"best_practices"であり、条件ステートメントがFalseに評価されたため、Pythonがprocess_data()を含むブロック内のコードを実行しなかったためです。

main()と呼ばれる関数を作成して、実行するコードを含める

これで、コマンドラインからスクリプトとして実行でき、望ましくない副作用なしでインポートできるPythonコードを作成できるようになりました。 次に、他のPythonプログラマーがあなたの言っていることを簡単に理解できるようにコードを記述する方法について学びます。

C、C +、Java、およびその他のいくつかの言語などの多くの言語は、オペレーティングシステムがコンパイルされたプログラムを実行するときに自動的に呼び出す `+ main()`と呼ばれる必要がある特別な関数を定義します。 この関数は、実行がプログラムに入る場所であるため、しばしばentry pointと呼ばれます。

対照的に、Pythonには、スクリプトへのエントリポイントとして機能する特別な関数はありません。 実際には、Pythonスクリプトのエントリポイント関数に任意の名前を付けることができます!

Pythonはmain()という名前の関数に重要性を割り当てませんが、ベストプラクティスはとにかくname the entry point function main()にすることです。 そうすれば、スクリプトを読んだ他のプログラマは、この関数がスクリプトの主要なタスクを実行するコードの開始点であることをすぐに知っています。

さらに、main()には、Pythonインタープリターがファイルを実行するときに実行するコードが含まれている必要があります。 これは、ユーザーがモジュールをインポートする場合に `main()`を再利用できるため、コードを条件付きブロックに直接配置するよりも優れています。

best_practices.pyファイルを次のコードのように変更します。

 1 from time import sleep
 2
 3 print("This is my file to demonstrate best practices.")
 4
 5 def process_data(data):
 6     print("Beginning data processing...")
 7     modified_data = data + " that has been modified"
 8     sleep(3)
 9     print("Data processing finished.")
10     return modified_data
11
12 def main():
13     data = "My data read from the Web"
14     print(data)
15     modified_data = process_data(data)
16     print(modified_data)
17
18 if __name__ == "__main__":
19     main()

この例では、以前は条件付きブロック内にあったコードを含むmain()の定義を追加しました。 次に、main()を実行するように条件付きブロックを変更しました。 このコードをスクリプトとして実行するかインポートすると、前のセクションと同じ出力が得られます。

main()から他の関数​​を呼び出す

Pythonでのもう1つの一般的な方法は、タスクを実行するコードをmain()に含めるのではなく、have main() execute other functionsにすることです。 これは、独立して実行できるいくつかの小さなサブタスクから全体のタスクを構成できる場合に特に便利です。

たとえば、次のことを行うスクリプトがあるとします。

  1. データベース、ディスク上のファイル、またはWeb APIなどのソースからデータファイルを読み取ります。

  2. データを処理します

  3. 処理されたデータを別の場所に書き込みます

これらの各サブタスクを別々の機能で実装すると、自分(または別のユーザー)が簡単にいくつかの手順を再利用し、不要な手順を無視できます。 次に、main()でデフォルトのワークフローを作成し、両方の長所を活かすことができます。

このプラクティスをコードに適用するかどうかは、判断の判断になります。 作業を複数の関数に分割すると、再利用が容易になりますが、プログラムのフローのいくつかのジャンプに従う必要があるため、コードを解釈しようとする他の誰かの難易度が高くなります。

best_practices.pyファイルを次のコードのように変更します。

 1 from time import sleep
 2
 3 print("This is my file to demonstrate best practices.")
 4
 5 def process_data(data):
 6     print("Beginning data processing...")
 7     modified_data = data + " that has been modified"
 8     sleep(3)
 9     print("Data processing finished.")
10     return modified_data
11
12 def read_data_from_web():
13     print("Reading data from the Web")
14     data = "Data from the web"
15     return data
16
17 def write_data_to_database(data):
18     print("Writing data to a database")
19     print(data)
20
21 def main():
22     data = read_data_from_web()
23     modified_data = process_data(data)
24     write_data_to_database(modified_data)
25
26 if __name__ == "__main__":
27     main()

このサンプルコードでは、ファイルの最初の10行には、以前と同じ内容が含まれています。 12行目の2番目の関数定義はサンプルデータを作成して返し、17行目の3番目の関数定義は変更されたデータをデータベースに書き込むことをシミュレートします。

21行目では、main()が定義されています。 この例では、main()を変更して、データ読み取り、データ処理、およびデータ書き込み関数を順番に呼び出すようにしています。

まず、dataread_data_from_web()から作成されます。 このdataprocess_data()に渡され、modified_dataが返されます。 最後に、modified_datawrite_data_to_database()に渡されます。

スクリプトの最後の2行は、__name__をチェックし、ifステートメントがTrueの場合にmain()を実行する条件付きブロックです。

これで、以下に示すように、コマンドラインから処理パイプライン全体を実行できます。

$ python3 best_practices.py
This is my file to demonstrate best practices.
Reading data from the Web
Beginning data processing...
Data processing finished.
Writing processed data to a database
Data from the web that has been modified

この実行の出力では、Pythonインタープリターがmain()を実行し、read_data_from_web()process_data()、およびwrite_data_to_database()を実行したことがわかります。 ただし、以下に示すように、best_practices.pyファイルをインポートして、別の入力データソースにprocess_data()を再利用することもできます。

>>>

>>> import best_practices as bp
This is my file to demonstrate best practices.
>>> data = "Data from a file"
>>> modified_data = bp.process_data(data)
Beginning data processing...
Data processing finished.
>>> bp.write_data_to_database(modified_data)
Writing processed data to a database
Data from a file that has been modified

この例では、best_practicesをインポートし、このコードの名前をbpに短縮しました。

インポートプロセスにより、Pythonインタープリターはbest_practices.pyファイル内のすべてのコード行を実行したため、出力にはファイルの目的を説明する行が表示されます。

次に、Webからデータを読み取る代わりに、ファイルからデータをdataに保存しました。 次に、best_practices.pyファイルのprocess_data()+`and `+write_data_to_database()を再利用しました。 この場合、main()ですべてのロジックを定義する代わりに、コードを再利用することを利用しました。

Pythonメイン関数のベストプラクティスの概要

これが、今見たPythonのmain()に関する4つの主要なベストプラクティスです。

  1. 実行に時間がかかるコード、またはコンピューターに他の影響を与えるコードを関数またはクラスに入れて、そのコードをいつ実行するかを正確に制御できるようにします。

  2. __name__のさまざまな値を使用してコンテキストを決定し、条件ステートメントを使用してコードの動作を変更します。

  3. Pythonはmain()という名前の関数に特別な意味を割り当てていませんが、関数の意図を伝えるために、エントリポイント関数にmain()という名前を付ける必要があります。

  4. コードの機能を再利用する場合は、main()の外部の関数でロジックを定義し、main()の内部でそれらの関数を呼び出します。

結論

おめでとうございます。 これで、Pythonmain()関数を作成する方法がわかりました。

次のことを学びました。

  • __name__変数の値を知ることは、実行可能スクリプトとインポート可能なモジュールの2つの目的を果たすコードを作成するために重要です。

  • __name__は、Pythonファイルの実行方法に応じて異なる値を取ります。 __name__は次のようになります。

    • ファイルがコマンドラインから実行される場合、またはpython -mを使用して実行される場合(パッケージの__main__.pyファイルを実行する場合)の"__main__"

    • モジュールがインポートされている場合、モジュールの名前

  • Pythonプログラマーは、再利用可能なコードを開発するときに使用する一連の優れたプラクティスを開発しました。

これで、すばらしいPythonmain()関数コードを作成する準備が整いました。