8. 複合ステートメント—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.6/reference/compound stmts
移動先:案内検索

8.8。 複合ステートメント

複合ステートメントには、他のステートメント(のグループ)が含まれます。 それらは、何らかの方法でそれらの他のステートメントの実行に影響を与えるか、または制御します。 一般に、複合ステートメントは複数の行にまたがりますが、単純な化身では、複合ステートメント全体が1行に含まれる場合があります。

ifwhile 、および for ステートメントは、従来の制御フロー構造を実装します。 try は、ステートメントのグループの例外ハンドラーやクリーンアップコードを指定し、 with ステートメントは、コードブロックの周囲で初期化および終了コードを実行できます。 関数とクラスの定義も構文的に複合ステートメントです。

複合ステートメントは、1つ以上の「句」で構成されます。 句は、ヘッダーと「スイート」で構成されます。 特定の複合ステートメントの句ヘッダーはすべて同じインデントレベルにあります。 各句ヘッダーは、一意に識別するキーワードで始まり、コロンで終わります。 スイートは、句によって制御されるステートメントのグループです。 スイートは、ヘッダーのコロンに続く、ヘッダーと同じ行にある1つ以上のセミコロンで区切られた単純なステートメントにすることも、後続の行にある1つ以上のインデントされたステートメントにすることもできます。 ネストされた複合ステートメントを含めることができるのは、後者の形式のスイートのみです。 以下は違法です。これは主に、後続の else 句がどの if 句に属するかが明確でないためです。

if test1: if test2: print(x)

また、このコンテキストではセミコロンがコロンよりも緊密にバインドされるため、次の例では、 print()呼び出しがすべて実行されるか、まったく実行されないことに注意してください。

if x < y < z: print(x); print(y); print(z)

要約:

  Compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | async_with_stmt
                   | async_for_stmt
                   | async_funcdef
スイート         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
声明     ::=  stmt_list NEWLINE | compound_stmt
  stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

ステートメントは常にNEWLINEで終わり、その後にDEDENTが続く可能性があることに注意してください。 また、オプションの継続句は常にステートメントを開始できないキーワードで始まるため、あいまいさはありません(Pythonでは、ネストされた if ステートメントを要求することで「ぶら下がり else 」の問題が解決されます)インデントされます)。

次のセクションの文法規則のフォーマットでは、わかりやすくするために各句を別々の行に配置しています。

8.1。 NS もしも声明

if ステートメントは、条件付き実行に使用されます。

  if_stmt ::=  "if" expression ":" suite
             ("elif" expression ":" suite)*
             ["else" ":" suite]

1つがtrueであることが判明するまで、式を1つずつ評価することにより、スイートの1つを正確に選択します(trueとfalseの定義については、セクションブール演算を参照してください)。 次に、そのスイートが実行されます( if ステートメントの他の部分は実行または評価されません)。 すべての式がfalseの場合、 else 句のスイートが存在する場合は実行されます。


8.2。 NS その間声明

while ステートメントは、式が真である限り、繰り返し実行するために使用されます。

  while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

これは式を繰り返しテストし、それがtrueの場合、最初のスイートを実行します。 式がfalseの場合(初めてテストされる場合があります)、 else 句のスイートが存在する場合は実行され、ループが終了します。

最初のスイートで実行された break ステートメントは、 else 句のスイートを実行せずにループを終了します。 最初のスイートで実行された continue ステートメントは、スイートの残りの部分をスキップして、式のテストに戻ります。


8.3。 NS にとって声明

for ステートメントは、シーケンスの要素(文字列、タプル、リストなど)またはその他の反復可能なオブジェクトを反復処理するために使用されます。

  for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

式リストは1回評価されます。 反復可能なオブジェクトを生成する必要があります。 expression_listの結果に対してイテレータが作成されます。 次に、スイートは、イテレータによって提供されたアイテムごとに、イテレータによって返された順序で1回実行されます。 次に、各アイテムは、割り当ての標準ルールを使用してターゲットリストに割り当てられ(割り当てステートメントを参照)、スイートが実行されます。 アイテムが使い果たされると(シーケンスが空になるか、イテレータが StopIteration 例外を発生させるとすぐに)、 else 句のスイートが実行され、ループが終了します。

最初のスイートで実行された break ステートメントは、 else 句のスイートを実行せずにループを終了します。 最初のスイートで実行された continue ステートメントは、スイートの残りの部分をスキップして次のアイテムに進みます。次のアイテムがない場合は、 else 句に進みます。

forループは、ターゲットリスト内の変数に割り当てを行います。 これにより、forループのスイートで行われたものを含め、これらの変数への以前のすべての割り当てが上書きされます。

for i in range(10):
    print(i)
    i = 5             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

ターゲットリスト内の名前は、ループの終了時に削除されませんが、シーケンスが空の場合、ループによってまったく割り当てられていません。 ヒント:組み込み関数 range()は、Pascalのfor i := a to b doの効果をエミュレートするのに適した整数のイテレーターを返します。 たとえば、list(range(3))はリスト[0, 1, 2]を返します。

ノート

シーケンスがループによって変更されている場合は微妙です(これは、可変シーケンスでのみ発生する可能性があります。 リスト)。 内部カウンターは、次に使用されるアイテムを追跡するために使用され、これは反復ごとに増分されます。 このカウンターがシーケンスの長さに達すると、ループは終了します。 これは、スイートがシーケンスから現在の(または前の)アイテムを削除した場合、次のアイテムはスキップされることを意味します(すでに処理された現在のアイテムのインデックスを取得するため)。 同様に、スイートが現在のアイテムの前にシーケンス内のアイテムを挿入した場合、現在のアイテムは次回ループを介して再度処理されます。 これは厄介なバグにつながる可能性があり、シーケンス全体のスライスを使用して一時的なコピーを作成することで回避できます。

for x in a[:]:
    if x < 0: a.remove(x)

8.4。 NS 試す声明

try ステートメントは、ステートメントのグループの例外ハンドラーやクリーンアップコードを指定します。

  try_stmt  ::=  try1_stmt | try2_stmt
  try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
  try2_stmt ::=  "try" ":" suite
               "finally" ":" suite

exception 句は、1つ以上の例外ハンドラーを指定します。 try 句で例外が発生しない場合、例外ハンドラーは実行されません。 try スイートで例外が発生すると、例外ハンドラーの検索が開始されます。 この検索では、例外に一致するものが見つかるまで、except句が順番に検査されます。 式のないexcept句が存在する場合は、最後にする必要があります。 すべての例外に一致します。 式を含むexcept句の場合、その式が評価され、結果のオブジェクトが例外と「互換性がある」場合、句は例外と一致します。 オブジェクトが例外オブジェクトのクラスまたは基本クラスであるか、例外と互換性のある項目を含むタプルである場合、そのオブジェクトは例外と互換性があります。

例外に一致するexcept句がない場合、例外ハンドラーの検索は、周囲のコードと呼び出しスタックで続行されます。 1

例外句のヘッダーにある式の評価で例外が発生した場合、ハンドラーの元の検索はキャンセルされ、周囲のコードと呼び出しスタックで新しい例外の検索が開始されます(全体として扱われます)。 try ステートメントで例外が発生しました)。

一致するexcept句が見つかると、そのexcept句の as キーワードの後に指定されたターゲットに例外が割り当てられ、存在する場合は、except句のスイートが実行されます。 句を除くすべての句には、実行可能ブロックが必要です。 このブロックの終わりに達すると、tryステートメント全体の後で通常どおり実行が続行されます。 (これは、同じ例外に対して2つのネストされたハンドラーが存在し、例外が内部ハンドラーのtry句で発生した場合、外部ハンドラーは例外を処理しないことを意味します。)

as targetを使用して例外が割り当てられた場合、例外句の最後で例外がクリアされます。 これはまるで

except E as N:
    foo

に翻訳されました

except E as N:
    try:
        foo
    finally:
        del N

つまり、except句の後で例外を参照できるようにするには、例外を別の名前に割り当てる必要があります。 例外は、トレースバックがアタッチされた状態でスタックフレームとの参照サイクルを形成し、次のガベージコレクションが発生するまでそのフレーム内のすべてのローカルを存続させるためにクリアされます。

例外句のスイートが実行される前に、例外に関する詳細が sys モジュールに格納され、 sys.exc_info()を介してアクセスできます。 sys.exc_info()は、例外クラス、例外インスタンス、およびプログラム内のポイントを識別するトレースバックオブジェクト(セクション標準タイプ階層を参照)で構成される3タプルを返します。例外が発生しました。 sys.exc_info()の値は、例外を処理した関数から戻るときに、(呼び出し前の)以前の値に復元されます。

オプションの else 句は、制御フローが try スイートを離れ、例外が発生せず、 returnContinue 、または break ステートメントが実行されました。 else 句の例外は、先行する exception 句では処理されません。

最終的にが存在する場合は、「クリーンアップ」ハンドラーを指定します。 try 句が実行されます。これには、および else 句を除くすべての句が含まれます。 いずれかの句で例外が発生し、処理されない場合、例外は一時的に保存されます。 finally 句が実行されます。 保存された例外がある場合は、 finally 句の最後で再発生します。 finally 句で別の例外が発生した場合、保存された例外が新しい例外のコンテキストとして設定されます。 finally 句が return または break ステートメントを実行すると、保存された例外は破棄されます。

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

finally 句の実行中は、プログラムは例外情報を利用できません。

returnbreak または continue ステートメントが、 try try スイートで実行された場合] finally ステートメント、 finally 句も '途中で'実行されます。 continue ステートメントは finally 句では無効です。 (理由は、現在の実装に問題があるためです。この制限は将来解除される可能性があります)。

関数の戻り値は、最後に実行された return ステートメントによって決定されます。 finally 句は常に実行されるため、 finally 句で実行される return ステートメントは常に最後に実行されます。

>>> def foo():
...     try:
...         return 'try'
...     finally:
...         return 'finally'
...
>>> foo()
'finally'

例外に関する追加情報はセクション Exceptions にあり、 raise ステートメントを使用して例外を生成する方法に関する情報はセクション raiseステートメントにあります。


8.5。 NS と声明

with ステートメントは、コンテキストマネージャーによって定義されたメソッドでブロックの実行をラップするために使用されます(セクション Withステートメントコンテキストマネージャーを参照)。 これにより、一般的な tryexceptfinally の使用パターンをカプセル化して、再利用しやすくなります。

  with_stmt ::=  "with" with_item ("," with_item)* ":" suite
  with_item ::=  expression ["as" target]

1つの「アイテム」を含む with ステートメントの実行は、次のように進行します。

  1. コンテキスト式( with_item で指定された式)は、コンテキストマネージャーを取得するために評価されます。

  2. コンテキストマネージャの__exit__()は、後で使用するためにロードされます。

  3. コンテキストマネージャの__enter__()メソッドが呼び出されます。

  4. with ステートメントにターゲットが含まれている場合、__enter__()からの戻り値がターゲットに割り当てられます。

    ノート

    with ステートメントは、__enter__()メソッドがエラーなしで返される場合、__exit__()が常に呼び出されることを保証します。 したがって、ターゲットリストへの割り当て中にエラーが発生した場合、スイート内で発生したエラーと同じように扱われます。 以下のステップ6を参照してください。

  5. スイートが実行されます。

  6. コンテキストマネージャの__exit__()メソッドが呼び出されます。 例外によってスイートが終了した場合、そのタイプ、値、およびトレースバックが引数として__exit__()に渡されます。 それ以外の場合は、3つの None 引数が指定されます。

    例外が原因でスイートが終了し、__exit__()メソッドからの戻り値がfalseの場合、例外が再発生します。 戻り値がtrueの場合、例外は抑制され、 with ステートメントに続くステートメントから実行が続行されます。

    例外以外の理由でスイートが終了した場合、__exit__()からの戻り値は無視され、実行は、実行された種類の終了の通常の場所で続行されます。

複数のアイテムがある場合、コンテキストマネージャーは、複数の with ステートメントがネストされているかのように処理されます。

with A() as a, B() as b:
    suite

と同等です

with A() as a:
    with B() as b:
        suite

バージョン3.1で変更:複数のコンテキスト式のサポート。


も参照してください

PEP 343 -「with」ステートメント
Python with ステートメントの仕様、背景、および例。


8.6。 関数の定義

関数定義は、ユーザー定義の関数オブジェクトを定義します(セクション標準型階層を参照)。

funcdef                 ::=  [decorators] "def" funcname "(" [parameter_list] ")"
                             ["->" expression] ":" suite
デコレータ              ::=  decorator+
デコレータ               ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
  dotted_name             ::=  identifier ("." identifier)*
  parameter_list          ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                             | parameter_list_starargs
  parameter_list_starargs ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                             | "**" parameter [","]
パラメータ               ::=  identifier [":" expression]
defparameter            ::=  parameter ["=" expression]
funcname                ::=  identifier

関数定義は実行可能ステートメントです。 その実行により、現在のローカル名前空間の関数名が関数オブジェクト(関数の実行可能コードのラッパー)にバインドされます。 この関数オブジェクトには、関数が呼び出されたときに使用されるグローバル名前空間として、現在のグローバル名前空間への参照が含まれています。

関数定義は関数本体を実行しません。 これは、関数が呼び出されたときにのみ実行されます。 2

関数定義は、1つ以上のデコレータ式でラップできます。 デコレータ式は、関数が定義されたときに、関数定義を含むスコープで評価されます。 結果は、関数オブジェクトを唯一の引数として呼び出される呼び出し可能である必要があります。 戻り値は、関数オブジェクトではなく関数名にバインドされます。 複数のデコレータがネストされた方法で適用されます。 たとえば、次のコード

@f1(arg)
@f2
def func(): pass

とほぼ同等です

def func(): pass
func = f1(arg)(f2(func))

ただし、元の関数は一時的にfuncという名前にバインドされていません。

1つ以上のパラメータパラメータ = の形式である場合、関数は「デフォルトのパラメータ値」を持っていると言われます。 デフォルト値のパラメーターの場合、対応する引数を呼び出しから省略できます。その場合、パラメーターのデフォルト値が置き換えられます。 パラメータにデフォルト値がある場合、「*」までの後続のすべてのパラメータにもデフォルト値が必要です。これは、文法で表現されていない構文上の制限です。

デフォルトのパラメーター値は、関数定義の実行時に左から右に評価されます。これは、関数が定義されたときに式が1回評価され、同じ「事前計算」値がに使用されることを意味します。各呼び出し。 これは、デフォルトのパラメータがリストや辞書などの可変オブジェクトである場合を理解するために特に重要です。関数がオブジェクトを変更する場合(例: リストに項目を追加することにより)、デフォルト値は事実上変更されます。 これは一般的に意図されたものではありません。 これを回避する方法は、デフォルトとしてNoneを使用し、関数の本体で明示的にテストすることです。例:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

関数呼び出しのセマンティクスについては、呼び出しのセクションで詳しく説明しています。 関数呼び出しは、位置引数、キーワード引数、またはデフォルト値のいずれかから、パラメーターリストに記載されているすべてのパラメーターに常に値を割り当てます。 「*identifier」という形式が存在する場合は、余分な位置パラメーターを受け取るタプルに初期化され、デフォルトで空のタプルになります。 「**identifier」という形式が存在する場合、過剰なキーワード引数を受け取る新しい順序付きマッピングに初期化され、デフォルトで同じタイプの新しい空のマッピングになります。 「*」または「*identifier」の後のパラメーターはキーワードのみのパラメーターであり、使用済みのキーワード引数でのみ渡すことができます。

パラメータには、パラメータ名の後に「: expression」という形式の注釈を付けることができます。 *identifierまたは**identifierの形式の場合でも、どのパラメーターにも注釈を付けることができます。 関数には、パラメータリストの後に「-> expression」という形式の「return」注釈が付いている場合があります。 これらのアノテーションは任意の有効なPython式にすることができ、関数定義が実行されるときに評価されます。 注釈は、ソースコードに表示される順序とは異なる順序で評価される場合があります。 アノテーションが存在しても、関数のセマンティクスは変更されません。 注釈値は、関数オブジェクトの__annotations__属性のパラメーター名でキー設定されたディクショナリの値として使用できます。

式ですぐに使用できるように、無名関数(名前にバインドされていない関数)を作成することもできます。 これは、セクション Lambdas で説明されているラムダ式を使用します。 ラムダ式は単純化された関数定義の省略形にすぎないことに注意してください。 「 def 」ステートメントで定義された関数は、ラムダ式で定義された関数と同じように、受け渡したり、別の名前に割り当てたりすることができます。 「 def 」フォームは、複数のステートメントと注釈を実行できるため、実際にはより強力です。

プログラマーのメモ:関数はファーストクラスのオブジェクトです。 関数定義内で実行される「def」ステートメントは、返されるか、渡されることができるローカル関数を定義します。 ネストされた関数で使用される自由変数は、defを含む関数のローカル変数にアクセスできます。 詳細については、セクション命名とバインディングを参照してください。

も参照してください

PEP 3107 -関数の注釈
関数アノテーションの元の仕様。


8.7。 クラス定義

クラス定義はクラスオブジェクトを定義します(セクション標準タイプ階層を参照):

classdef    ::=  [decorators] "class" classname [inheritance] ":" suite
継承 ::=  "(" [argument_list] ")"
クラス名   ::=  identifier

クラス定義は実行可能なステートメントです。 継承リストは通常、基本クラスのリストを提供します(より高度な使用法については、メタクラスを参照)。したがって、リスト内の各項目は、サブクラス化を許可するクラスオブジェクトに評価される必要があります。 継承リストのないクラスは、デフォルトで、基本クラス object から継承します。 したがって、

class Foo:
    pass

と同等です

class Foo(object):
    pass

次に、クラスのスイートは、新しく作成されたローカル名前空間と元のグローバル名前空間を使用して、新しい実行フレームで実行されます(名前空間とバインディングを参照)。 (通常、スイートには主に関数定義が含まれています。)クラスのスイートが実行を終了すると、その実行フレームは破棄されますが、ローカル名前空間は保存されます。 3 次に、基本クラスの継承リストと属性ディクショナリの保存されたローカル名前空間を使用して、クラスオブジェクトが作成されます。 クラス名は、元のローカル名前空間のこのクラスオブジェクトにバインドされます。

クラス本体で属性が定義される順序は、新しいクラスの__dict__で保持されます。 これは、クラスが作成された直後、および定義構文を使用して定義されたクラスに対してのみ信頼できることに注意してください。

クラスの作成は、 metaclasses を使用して大幅にカスタマイズできます。

クラスも装飾できます。関数を装飾するときと同じように、

@f1(arg)
@f2
class Foo: pass

とほぼ同等です

class Foo: pass
Foo = f1(arg)(f2(Foo))

デコレータ式の評価ルールは、関数デコレータの場合と同じです。 結果はクラス名にバインドされます。

プログラマーのメモ:クラス定義で定義されている変数はクラス属性です。 それらはインスタンスによって共有されます。 インスタンス属性は、self.name = valueのメソッドで設定できます。 クラス属性とインスタンス属性はどちらも「self.name」という表記でアクセスできます。インスタンス属性は、この方法でアクセスすると、同じ名前のクラス属性を非表示にします。 クラス属性はインスタンス属性のデフォルトとして使用できますが、可変値を使用すると予期しない結果が生じる可能性があります。 記述子を使用して、実装の詳細が異なるインスタンス変数を作成できます。

も参照してください

PEP 3115 -Python3000のメタクラス
メタクラスの宣言を現在の構文に変更した提案、およびメタクラスを持つクラスの構築方法のセマンティクス。
PEP 3129 -クラスデコレータ
クラスデコレータを追加した提案。 関数とメソッドのデコレータは、 PEP 318 で導入されました。


8.8。 コルーチン

バージョン3.5の新機能。


8.8.1。 コルーチン関数の定義

  async_funcdef ::=  [decorators] "async" "def" funcname "(" [parameter_list] ")"
                   ["->" expression] ":" suite

Pythonコルーチンの実行は、多くの時点で一時停止および再開できます(コルーチンを参照)。 コルーチンの本体では、awaitおよびasync識別子はすべて予約済みキーワードになります。 await 式、 async for 、および async with は、コルーチン本体でのみ使用できます。

async def構文で定義された関数は、awaitまたはasyncキーワードが含まれていない場合でも、常にコルーチン関数です。

async defコルーチンでyield from式を使用するのは SyntaxError です。

コルーチン関数の例:

async def func(param1, param2):
    do_stuff()
    await some_coroutine()

8.8.2。 NS 非同期声明

  async_for_stmt ::=  "async" for_stmt

非同期イテレータイテレータ実装で非同期コードを呼び出すことができ、非同期イテレータnext メソッドで非同期コードを呼び出すことができます。

async forステートメントを使用すると、非同期イテレーターを簡単に反復できます。

次のコード:

async for TARGET in ITER:
    BLOCK
else:
    BLOCK2

意味的には次のものと同等です。

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True
while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        BLOCK
else:
    BLOCK2

詳細については、__aiter__()および__anext__()も参照してください。

async def 関数の外でasync forステートメントを使用するのは SyntaxError です。


8.8.3。 NS と非同期声明

  async_with_stmt ::=  "async" with_stmt

非同期コンテキストマネージャーは、 enter および exit メソッドで実行を一時停止できるコンテキストマネージャーです。

次のコード:

async with EXPR as VAR:
    BLOCK

意味的には次のものと同等です。

mgr = (EXPR)
aexit = type(mgr).__aexit__
aenter = type(mgr).__aenter__(mgr)

VAR = await aenter
try:
    BLOCK
except:
    if not await aexit(mgr, *sys.exc_info()):
        raise
else:
    await aexit(mgr, None, None, None)

詳細については、__aenter__()および__aexit__()も参照してください。

async def 関数の外でasync withステートメントを使用するのは SyntaxError です。

も参照してください

PEP 492 -非同期および待機構文のコルーチン
コルーチンをPythonの適切なスタンドアロンの概念にし、サポートする構文を追加した提案。


脚注

1
別の例外を発生させる finally 句がない限り、例外は呼び出しスタックに伝播されます。 その新しい例外により、古い例外が失われます。
2
関数本体の最初のステートメントとして表示される文字列リテラルは、関数の__doc__属性に変換されるため、関数の docstring に変換されます。
3
クラス本体の最初のステートメントとして表示される文字列リテラルは、名前空間の__doc__アイテムに変換されるため、クラスの docstring に変換されます。