4.4。 その他の制御フローツール
導入されたばかりの while ステートメントに加えて、Pythonは他の言語で知られている通常のフロー制御ステートメントを使用しますが、いくつかの工夫が加えられています。
4.1。 ifステートメント
おそらく最もよく知られているステートメントタイプは if ステートメントです。 例えば:
elif パーツはゼロ個以上にすることができ、 else パーツはオプションです。 キーワード「elif
」は「elseif」の略で、過度のインデントを回避するのに役立ちます。 if
…elif
…elif
…シーケンスは、他の言語で見られるswitch
またはcase
ステートメントの代わりになります。
4.2。 forステートメント
Pythonの for ステートメントは、CまたはPascalで慣れているものとは少し異なります。 Pythonのfor
ステートメントは、(Pascalのように)常に数値の等差数列を反復したり、反復ステップと停止条件の両方を定義する機能(Cとして)をユーザーに提供したりするのではなく、任意の項目を反復します。シーケンス(リストまたは文字列)、シーケンスに表示される順序。 例(しゃれは意図されていません):
同じコレクションを反復処理しながらコレクションを変更するコードは、正しく理解するのが難しい場合があります。 代わりに、通常、コレクションのコピーをループするか、新しいコレクションを作成する方が簡単です。
4.3。 NS 範囲() 関数
一連の数値を反復処理する必要がある場合は、組み込み関数 range()が便利です。 等差数列を生成します。
指定されたエンドポイントは、生成されたシーケンスの一部になることはありません。 range(10)
は、長さ10のシーケンスのアイテムの有効なインデックスである10個の値を生成します。 範囲を別の数値で開始したり、別の増分を指定したりすることができます(負の場合でも、これは「ステップ」と呼ばれることもあります)。
シーケンスのインデックスを反復処理するには、次のように range()と len()を組み合わせることができます。
ただし、このようなほとんどの場合、 enumerate()関数を使用すると便利です。ループテクニックを参照してください。
範囲を印刷するだけでは、奇妙なことが起こります。
多くの点で、 range()によって返されるオブジェクトは、リストであるかのように動作しますが、実際にはそうではありません。 これは、繰り返し処理したときに目的のシーケンスの連続するアイテムを返すオブジェクトですが、実際にはリストを作成しないため、スペースを節約できます。
このようなオブジェクトは iterable であると言います。つまり、供給がなくなるまで連続するアイテムを取得できるものを期待する関数や構成のターゲットとして適しています。 for ステートメントはそのような構成であることがわかりましたが、反復可能な関数の例は sum()です。
後で、iterablesを返し、iterablesを引数として取る関数がさらに表示されます。 最後に、範囲からリストを取得する方法に興味があるかもしれません。 解決策は次のとおりです。
データ構造の章では、 list()について詳しく説明します。
4.4。 breakとcontinueステートメント、およびelseループに関する句
break ステートメントは、Cの場合と同様に、最も内側を囲む for または while ループから抜け出します。
ループステートメントにはelse
句が含まれる場合があります。 ループがイテラブルの枯渇によって終了したとき( for を使用)または条件がfalseになったとき( while を使用)に実行されますが、ループがによって終了したときは実行されません。 ] break ステートメント。 これは、素数を検索する次のループによって例示されます。
(はい、これは正しいコードです。 よく見てください。else
句は for ループに属しており、ではなく if ステートメントに属しています。)
ループで使用する場合、else
句は、 if よりも try ステートメントのelse
句との共通点が多くなります。ステートメント: try ステートメントのelse
句は、例外が発生しないときに実行され、ループのelse
句は、break
が発生しないときに実行されます。 try
ステートメントと例外の詳細については、例外の処理を参照してください。
同じくCから借用した continue ステートメントは、ループの次の反復を続行します。
4.5。 passステートメント
pass ステートメントは何もしません。 文が構文的に必要であるが、プログラムがアクションを必要としない場合に使用できます。 例えば:
これは通常、最小限のクラスを作成するために使用されます。
pass を使用できるもう1つの場所は、新しいコードで作業するときの関数または条件付き本体のプレースホルダーとして使用できるため、より抽象的なレベルで考え続けることができます。 pass
は黙って無視されます。
4.6。 関数の定義
フィボナッチ数列を任意の境界に書き込む関数を作成できます。
キーワード def は、関数 defined を導入します。 その後に、関数名と仮パラメーターの括弧で囲まれたリストを続ける必要があります。 関数の本体を形成するステートメントは次の行から始まり、インデントする必要があります。
関数本体の最初のステートメントは、オプションで文字列リテラルにすることができます。 この文字列リテラルは、関数のドキュメント文字列、または docstring です。 (docstringの詳細については、 Documentation Strings のセクションを参照してください。)docstringを使用して、オンラインまたは印刷されたドキュメントを自動的に作成したり、ユーザーがコードをインタラクティブに参照できるようにするツールがあります。 作成するコードにdocstringを含めることをお勧めします。そのため、習慣を身に付けてください。
関数の実行は、関数のローカル変数に使用される新しいシンボルテーブルを導入します。 より正確には、関数内のすべての変数割り当ては、ローカルシンボルテーブルに値を格納します。 一方、変数参照は、最初にローカルシンボルテーブルを調べ、次にそれを囲む関数のローカルシンボルテーブルを調べ、次にグローバルシンボルテーブルを調べ、最後に組み込み名のテーブルを調べます。 したがって、グローバル変数およびそれを囲む関数の変数に、関数内で値を直接割り当てることはできません(ただし、グローバル変数の場合は global ステートメントで指定され、関数の変数の場合はで指定されます)。 ] nonlocal ステートメント)。ただし、参照される場合があります。
関数呼び出しの実際のパラメーター(引数)は、呼び出されたときに呼び出された関数のローカルシンボルテーブルに導入されます。 したがって、引数は call by value を使用して渡されます( value は常にオブジェクト reference であり、オブジェクトの値ではありません)。 1 関数が別の関数を呼び出すか、それ自体を再帰的に呼び出すと、その呼び出しに対して新しいローカルシンボルテーブルが作成されます。
関数定義は、関数名を現在のシンボルテーブルの関数オブジェクトに関連付けます。 インタプリタは、その名前が指すオブジェクトをユーザー定義関数として認識します。 他の名前も同じ関数オブジェクトを指すことができ、関数にアクセスするために使用することもできます。
他の言語から来ている場合、fib
は値を返さないため、関数ではなくプロシージャであることに異議を唱えるかもしれません。 実際、 return ステートメントのない関数でさえ、かなり退屈な値ではありますが、値を返します。 この値はNone
と呼ばれます(これは組み込みの名前です)。 値None
の書き込みは、それが書き込まれる唯一の値である場合、通常、インタープリターによって抑制されます。 print()を本当に使用したい場合は、次のように表示されます。
印刷する代わりに、フィボナッチ数列の数のリストを返す関数を作成するのは簡単です。
この例は、いつものように、いくつかの新しいPython機能を示しています。
- return ステートメントは、関数からの値を返します。 式引数のない
return
は、None
を返します。 関数の終わりから外れると、None
も返されます。 - ステートメント
result.append(a)
は、リストオブジェクトresult
のメソッドを呼び出します。 メソッドは、オブジェクトに「属する」関数であり、obj.methodname
という名前が付けられます。ここで、obj
はオブジェクト(これは式の場合があります)であり、methodname
は名前です。オブジェクトのタイプによって定義されるメソッドの。 異なるタイプは異なるメソッドを定義します。 異なるタイプのメソッドは、あいまいさを引き起こすことなく同じ名前を持つことができます。 ( classes を使用して、独自のオブジェクトタイプとメソッドを定義できます。 Classes を参照してください。)例に示すメソッドappend()
は、リストオブジェクトに対して定義されています。 リストの最後に新しい要素を追加します。 この例では、result = result + [a]
と同等ですが、より効率的です。
4.7。 関数の定義の詳細
可変数の引数を使用して関数を定義することもできます。 組み合わせることができる3つの形式があります。
4.7.1。 デフォルトの引数値
最も便利な形式は、1つ以上の引数のデフォルト値を指定することです。 これにより、定義されているよりも少ない引数で呼び出すことができる関数が作成されます。 例えば:
この関数は、いくつかの方法で呼び出すことができます。
- 必須の引数のみを与える:
ask_ok('Do you really want to quit?')
- オプションの引数の1つを与える:
ask_ok('OK to overwrite the file?', 2)
- またはすべての引数を与えることさえ:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
この例では、 in キーワードも紹介しています。 これは、シーケンスに特定の値が含まれているかどうかをテストします。
デフォルト値は、 defined スコープの関数定義の時点で評価されるため、次のようになります。
5
を印刷します。
重要な警告:デフォルト値は1回だけ評価されます。 これは、デフォルトがリスト、ディクショナリ、またはほとんどのクラスのインスタンスなどの可変オブジェクトである場合に違いを生みます。 たとえば、次の関数は、後続の呼び出しで渡された引数を累積します。
これは印刷されます
後続の呼び出し間でデフォルトを共有したくない場合は、代わりに次のような関数を記述できます。
4.7.2。 キーワード引数
関数は、kwarg=value
の形式のキーワード引数を使用して呼び出すこともできます。 たとえば、次の関数:
1つの必須引数(voltage
)と3つのオプション引数(state
、action
、およびtype
)を受け入れます。 この関数は、次のいずれかの方法で呼び出すことができます。
ただし、次のすべての呼び出しは無効になります。
関数呼び出しでは、キーワード引数は位置引数の後に続く必要があります。 渡されるすべてのキーワード引数は、関数によって受け入れられる引数の1つと一致する必要があります(例: actor
はparrot
関数の有効な引数ではなく、その順序は重要ではありません。 これには、オプションではない引数も含まれます(例: parrot(voltage=1000)
も有効です)。 引数が値を複数回受け取ることはできません。 この制限が原因で失敗する例を次に示します。
**name
形式の最終仮パラメーターが存在する場合、仮パラメーターに対応するものを除くすべてのキーワード引数を含む辞書(マッピングタイプ— dict を参照)を受け取ります。 これは、仮パラメータリスト以外の位置引数を含むタプルを受け取る*name
(次のサブセクションで説明)の形式の仮パラメータと組み合わせることができます。 (*name
は**name
の前に発生する必要があります。)たとえば、次のような関数を定義する場合:
これは次のように呼び出すことができます:
そしてもちろん、それは印刷します:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
キーワード引数が出力される順序は、関数呼び出しで指定された順序と一致することが保証されていることに注意してください。
4.7.3。 特別なパラメータ
デフォルトでは、引数は位置によって、またはキーワードによって明示的にPython関数に渡されます。 読みやすさとパフォーマンスのために、引数を渡す方法を制限して、開発者が関数定義を調べて、アイテムが位置、位置またはキーワード、またはキーワードのいずれで渡されるかを判断するだけでよいようにすることは理にかなっています。
関数定義は次のようになります。
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
ここで、/
および*
はオプションです。 使用する場合、これらの記号は、引数を関数に渡す方法によってパラメーターの種類を示します。位置のみ、位置またはキーワード、およびキーワードのみです。 キーワードパラメータは、名前付きパラメータとも呼ばれます。
4.7.3.1。 位置またはキーワードの引数
/
および*
が関数定義に存在しない場合、引数は位置またはキーワードによって関数に渡される可能性があります。
4.7.3.2。 位置のみのパラメーター
これをもう少し詳しく見ると、特定のパラメータを位置のみとしてマークすることができます。 position-only の場合、パラメーターの順序が重要であり、パラメーターをキーワードで渡すことはできません。 位置のみのパラメーターは、/
(スラッシュ)の前に配置されます。 /
は、位置のみのパラメーターを残りのパラメーターから論理的に分離するために使用されます。 関数定義に/
がない場合、位置のみのパラメーターはありません。
/
に続くパラメーターは、 position-or-keyword または keyword-only の場合があります。
4.7.3.3。 キーワードのみの引数
パラメータを keyword-only としてマークし、パラメータをキーワード引数で渡す必要があることを示すには、引数リストの最初の keywordのみパラメータの直前に*
を配置します。 。
4.7.3.4。 機能例
マーカー/
および*
に細心の注意を払って、次の関数定義の例を検討してください。
最もよく知られている形式である最初の関数定義standard_arg
は、呼び出し規約に制限を設けておらず、引数は位置またはキーワードで渡すことができます。
2番目の関数pos_only_arg
は、関数定義に/
があるため、位置パラメーターのみを使用するように制限されています。
3番目の関数kwd_only_args
は、関数定義の*
で示されているキーワード引数のみを許可します。
そして最後は、同じ関数定義で3つの呼び出し規約すべてを使用します。
最後に、位置引数name
とname
をキーとする**kwds
の間に衝突の可能性があるこの関数定義について考えてみます。
キーワード'name'
は常に最初のパラメーターにバインドされるため、True
を返す可能性のある呼び出しはありません。 例えば:
ただし、/
(位置のみの引数)を使用すると、name
を位置引数として、'name'
をキーワード引数のキーとして使用できるため、可能です。
つまり、**kwds
では、位置のみのパラメーターの名前をあいまいさなく使用できます。
4.7.3.5。 要約
ユースケースは、関数定義で使用するパラメーターを決定します。
ガイダンスとして:
- パラメータの名前をユーザーが使用できないようにする場合は、定位置のみを使用します。 これは、パラメーター名に実際の意味がない場合、関数が呼び出されたときに引数の順序を強制する場合、またはいくつかの定位置パラメーターと任意のキーワードを取得する必要がある場合に役立ちます。
- キーワードのみを使用するのは、名前に意味があり、名前を明示することで関数定義が理解しやすい場合、または渡される引数の位置にユーザーが依存しないようにする場合のみです。
- APIの場合、パラメーターの名前が将来変更された場合にAPIの変更が破損しないように、positional-onlyを使用します。
4.7.4。 任意の引数リスト
最後に、最も使用頻度の低いオプションは、任意の数の引数を使用して関数を呼び出すことができることを指定することです。 これらの引数はタプルにまとめられます(タプルとシーケンスを参照)。 可変数の引数の前に、0個以上の通常の引数が発生する場合があります。
通常、これらのvariadic
引数は、関数に渡される残りのすべての入力引数をすくい上げるため、仮パラメーターのリストの最後になります。 *args
パラメーターの後に発生する仮パラメーターは、「キーワードのみ」の引数です。つまり、位置引数ではなくキーワードとしてのみ使用できます。
4.7.5。 引数リストの解凍
逆の状況は、引数がすでにリストまたはタプルにあるが、個別の位置引数を必要とする関数呼び出しのために解凍する必要がある場合に発生します。 たとえば、組み込みの range()関数は、別々の start 引数と stop 引数を必要とします。 個別に使用できない場合は、*
演算子を使用して関数呼び出しを記述し、リストまたはタプルから引数を解凍します。
同様に、辞書は**
演算子を使用してキーワード引数を配信できます。
4.7.6。 ラムダ式
lambda キーワードを使用して、小さな無名関数を作成できます。 この関数は、lambda a, b: a+b
という2つの引数の合計を返します。 ラムダ関数は、関数オブジェクトが必要な場所ならどこでも使用できます。 それらは構文的に単一の式に制限されています。 意味的には、これらは通常の関数定義の単なる構文糖衣です。 ネストされた関数定義と同様に、ラムダ関数は含まれているスコープから変数を参照できます。
上記の例では、ラムダ式を使用して関数を返します。 もう1つの使用法は、小さな関数を引数として渡すことです。
4.7.7。 ドキュメント文字列
ドキュメント文字列の内容とフォーマットに関するいくつかの規則を次に示します。
最初の行は、常にオブジェクトの目的の短く簡潔な要約である必要があります。 簡潔にするために、オブジェクトの名前またはタイプを明示的に記述しないでください。これらは他の手段で使用できるためです(名前が関数の操作を説明する動詞である場合を除く)。 この行は大文字で始まり、ピリオドで終わる必要があります。
ドキュメント文字列にさらに行がある場合は、2行目を空白にして、要約を残りの説明から視覚的に分離する必要があります。 次の行は、オブジェクトの呼び出し規約、その副作用などを説明する1つ以上の段落である必要があります。
Pythonパーサーは、Pythonの複数行の文字列リテラルからインデントを削除しないため、ドキュメントを処理するツールは、必要に応じてインデントを削除する必要があります。 これは、次の規則を使用して行われます。 文字列の最初の行の後の最初の非空白行は、ドキュメント文字列全体のインデントの量を決定します。 (最初の行は通常、文字列の開始引用符に隣接しているため、文字列リテラルではインデントがわかりません。)このインデントに「相当する」空白は、文字列のすべての行の先頭から削除されます。 。 インデントが少ない行は発生しないはずですが、発生する場合は、先頭の空白をすべて削除する必要があります。 空白の同等性は、タブを拡張した後にテストする必要があります(通常は8スペースに)。
複数行のdocstringの例を次に示します。
4.7.8。 関数アノテーション
関数アノテーションは、ユーザー定義関数で使用されるタイプに関する完全にオプションのメタデータ情報です( PEP 3107 および PEP484を参照)詳細については)。
アノテーションは、関数の__annotations__
属性に辞書として格納され、関数の他の部分には影響しません。 パラメーター注釈は、パラメーター名の後のコロンと、それに続く注釈の値を評価する式によって定義されます。 戻りアノテーションは、リテラル->
と、それに続く式で定義され、パラメーターリストと def ステートメントの終わりを示すコロンの間にあります。 次の例には、必須の引数、オプションの引数、および注釈付きの戻り値があります。
4.8。 Intermezzo:コーディングスタイル
より長く、より複雑なPythonを作成しようとしているので、コーディングスタイルについて話す良い機会です。 ほとんどの言語は、さまざまなスタイルで書くことができます(または、より簡潔に、フォーマット)。 他のものより読みやすいものもあります。 他の人があなたのコードを読みやすくすることは常に良い考えであり、素晴らしいコーディングスタイルを採用することはそのために非常に役立ちます。
Pythonの場合、 PEP 8 が、ほとんどのプロジェクトが準拠するスタイルガイドとして登場しました。 それは非常に読みやすく、目を楽しませてくれるコーディングスタイルを促進します。 すべてのPython開発者は、ある時点でそれを読む必要があります。 ここにあなたのために抽出された最も重要なポイントがあります:
4スペースのインデントを使用し、タブは使用しません。
4つのスペースは、小さなインデント(ネストの深さを大きくすることができます)と大きなインデント(読みやすく)の間の適切な妥協点です。 タブは混乱を招き、除外するのが最善です。
79文字を超えないように行を折り返します。
これにより、小さなディスプレイを使用するユーザーが支援され、大きなディスプレイに複数のコードファイルを並べて表示できるようになります。
空白行を使用して、関数とクラス、および関数内のコードのより大きなブロックを区切ります。
可能であれば、独自の行にコメントを付けてください。
docstringを使用します。
演算子の前後とコンマの後にスペースを使用しますが、ブラケット構造のすぐ内側には使用しないでください:
a = f(1, 2) + g(3, 4)
。クラスと関数に一貫した名前を付けます。 慣例では、クラスには
UpperCamelCase
を使用し、関数とメソッドにはlowercase_with_underscores
を使用します。 最初のメソッド引数の名前として常にself
を使用します(クラスとメソッドの詳細については、クラスの最初の確認を参照してください)。コードが国際的な環境で使用されることを意図している場合は、派手なエンコーディングを使用しないでください。 Pythonのデフォルト、UTF-8、またはプレーンASCIIでさえ、どのような場合でも最適に機能します。
同様に、異なる言語を話す人々がコードを読んだり維持したりする可能性がごくわずかである場合は、識別子に非ASCII文字を使用しないでください。
脚注
- 1
- 実際には、オブジェクト参照による呼び出しの方が適切な説明になります。これは、可変オブジェクトが渡されると、呼び出し先がオブジェクトに加えた変更(リストに挿入されたアイテム)が表示されるためです。