S-JIS[2018-01-04/2018-01-13] 変更履歴
Python3.6.4の文のメモ。
Pythonの「文(statement)」は構文的には単純文と複合文に分かれているらしい。
複合文は他の(複数の)文を入れることが出来る文(例えばifやwhile)で、単純文はその文のみで完結している文(例えばreturnやbreak)。
if 条件: 他の文 else: 他の文
while 条件: 他の文
Pythonはインデントに意味がある言語であり、ひとかたまりの複数の文を複数行に記述する場合は同一のインデントにしなければならない。
「#」から行末までがコメントとなる。
(C言語やJavaの/* */のような複数行コメントは無い)
# コメント
a = 1 # コメント
特別な構文として、スクリプトの1行目か2行目にエンコード宣言を書く(ファイルのエンコーディングを指定する)ことが出来る。
# -*- coding: utf-8 -*-
# -*- coding=utf-8 -*-
厳密には「-*-」は必要無いが、そう書くことが推奨されている。
明示的に行を継続させるには、行末に「\」を付けて改行し、続きを書く。
(この場合、改行後のインデントはどうでもいい。が、1行目と同じにしておいた方が分かりやすいか)
if a == 1 \ or a == 2 \ or a == 3: print(a)
「\」の後ろにコメントを書くことは出来ない。
なお、括弧の中(式の優先度を表す丸括弧や関数の引数、tuple・list・set・dictのリテラル)は明示的に「\」を書かなくても行が継続される。
v = (1 + 2 + 3 + 4)
f(1, 2, 3, 4)
t = (1, "2", 3.0)
a = [1, 2, 3, 4]
s = {1, 2, 3, 4}
d = {"a": 1, "b": 2, "c": 3}
インデント(行の先頭の空白(スペースやタブ))はインデントレベルを計算するのに使われる。
インデントレベルが同一である(複数の)行はひとかたまりの文として扱われる。
インデントの慣例としては1回につきスペース4個らしい。
タブも使う事ができ、スペース8個として扱われるらしいが、個人的にはタブは使用せずスペースのみにする。
def f(a, b): print(a) for i in a: print(i) print(b) for i in b: print(i)
ちなみにインデント(INDENT)の反対はDEDENTと言うようだ。
(もしかして、increment-dent、decrement-dentが語源だったりするのだろうか?dentは「凹み」だそうで)
構文的には、ひとかたまりの文が終わってインデントレベルが1段下がる(1つ前のインデントレベルに戻る)のがDEDENTの役割。
C言語やJavaやScalaでは波括弧で囲むとひとかたまりの文(ブロック・複文)とすることが出来る。
そういった言語では、例えば関数定義の途中で波括弧で囲んでローカルスコープを持つ変数を使うことが出来るが、
Pythonではそういう使い方は出来ない。
// Javaの場合 void f(int a, int b) { System.out.println(a); System.out.println(b); { int sum = a + b; System.out.println(sum); } }
# Pythonの場合はIndentationErrorになる def f(a, b): print(a) print(b) sum = a + b print(sum)
Pythonの構文的に複数の文を書ける場所は、文法定義上は「suite」と定義されている。
スイートは、組・ひとかたまりといった意味らしい。
複数の文を1行で書く場合は文をセミコロン「;
」で区切る。(末尾にセミコロンが1個だけあっても良い。2つ以上あると駄目)
def f(a, b, c): print(1); print(2); print(3)
def f(a, b, c): print(1); print(2); print(3);
def f(a, b, c): print(1); print(2); print(3);; ←エラー
また、改行して新しいインデントレベル(前のインデントよりスペースの個数が多い必要がある)で続きの文を書いてもよい。
同一のインデントの間は同一のスイート内として認識される。
空行は(インデントの有無に関わらず)無視される。
def f(a, b, c): print(a) print(b) print(c)
インデントレベルが下がる(インデントのスペースの個数が減る)とスイート(複数の文)の終わり(DEDENT)として解釈される。
(なお、インデントレベルが下がる場合は、必ず以前の(いずれかのインデントレベルの)インデントと同じインデント(スペースの個数が同じ)になる必要がある)
Pythonでは式も文になる。
(C言語やScalaも文として式を書ける。Javaは式を書けず、コンパイルエラーになる)
つまり、文を書く箇所にただ単に式を書くことが出来る。
def f(): 123 # 式文 return 456
ただ、普通は単に式だけ書いても意味は無い^^;
関数(例えばprint)を呼び出すのは、構文上は式文ということなのだろう。
また、Pythonではクラスや関数の本体の最初の文に文字列リテラルをただ書くことがある(ドキュメント(そのクラスや関数の説明)という扱いになる→ドキュメンテーション文字列)のだが、構文としては式文になる。
変数に値を入れる文。
変数1 =〔変数2 = …〕値 変数1, 変数2, … = イテレート可能オブジェクト (変数1, 変数2, …) = イテレート可能オブジェクト [変数1, 変数2, …] = イテレート可能オブジェクト
イテレート可能オブジェクトとは、主にシーケンス(すなわちリストやタプル等)のこと。
v = 123 v1 = v2 = v3 = 123 l = [1, 2, 3] a, b, c = l
※Pythonで代入先をカンマ区切りにした場合、リスト等のオブジェクトの各要素をそれぞれ代入する構文である。
※Pythonで代入先の変数をカンマ区切りで複数並べると、丸括弧が省略されていると認識される。すなわち、タプル扱いである。
※Scalaの場合、「var a, b, c = 123
」の様に書くと、a,b,cそれぞれが123になる(一括して同じ値で初期化される)。
これを同じことをするPythonの構文は「a = b = c = 123
」である。
変数は、事前にglobalやnonlocal宣言されていない限り、ローカル変数になる。
変数には再代入可能。(再代入不可の構文(JavaのfinalやScalaのvalに当たるもの)は無い)
「+=」「*=」等は累算代入文と呼ぶらしい。
変数に注釈(アノテーション)を付けることが出来る。
変数: 注釈 〔= 値〕
クラススコープやモジュールスコープの変数で注釈(何らかの値)を付けると、__annotations__に「変数名をキーとする値(注釈)」が追加される。
注釈(アノテーション)と呼ばれているようだが、要するに変数の型名を書く。[2018-01-13]
(Pythonでは型(クラス)もオブジェクトなので、値として書くことが出来る)
n: int = 123 s: str = "abc"
ただしあくまで「アノテーションが付けられる」というだけで、型チェックが行われるわけではない。
(型チェックを行うツールもあるらしい)
assertは、デバッグ用のアサーションを指定する文。(Javaのassert相当)
assert 条件 〔, 値〕
条件を満たさない場合、AssertionErrorが発生する。
値を指定しておくと、AssertionErrorの引数(メッセージ)にその値が入る。
assert a == 1 assert a == 1, "aが1ではありません" assert a == 1, a assert a == 1, f"aが1ではありません(a={a})"
passは、何もしない文。
「構文としては何らかの文が必要だが、何も実行する処理は無い」という場合に有用。
class C: pass
def f(): pass
ちなみに、Scalaには???という関数が用意されており、「def
f() = ???
」の様に書けるが、これを実行するとNotImplementedErrorという例外が発生する。つまり、未実装(これから実装するTODO)という位置付け。
これに対し、
Pythonのpassは実行しても何も起きない。
delは、オブジェクトを削除する文。(C++のdelete相当?)
del 変数〔, 変数…〕
(変数にNone(Javaのnull相当)を代入しただけだとその変数は残るが、del文を使うと、その変数自体が消える(後続処理で(新たに値を代入せずに)使おうとするとエラーになる))
returnは、関数(やメソッド)から値を返す。
return 〔値〕
値を指定すると、その値が返る。
値を指定しない場合はNoneが返る。
カンマ区切りで複数の値を指定できる…が、これはタプルの丸括弧を省略した形式である。
yield文はreturn文の代わりに使用し、ジェネレーターを返す。
raiseは、例外を発生(送出)させる文。(Javaのthrow相当)
(C++やJavaでは例外をthrowする(スローする・投げる)と言うが、Pythonはraiseする(送出する)と言うらしい)
raise 〔例外 〔from 例外〕〕
raise
ただ単に「raise」のみ書くと、現在有効になっている例外が再送出される。
有効になっている例外が無い場合はRuntimeErrorが送出される。
raise BaseException("メッセージ")
raiseの後ろに送出する例外オブジェクトを指定する。
try: ... except Exception as e: raise BaseException("メッセージ") from e
from節は、発生元例外を指定する。(例外の連鎖)
(from節で指定した発生元例外は、受け取った側で__cause__によって取得できる)
ちなみにJavaの場合、例外を連鎖させる場合は例外のコンストラクターで発生元例外を指定する。「new BaseException(e)
」の様になる。
breakは、forやwhileループから抜け出す。
break
forやwhileにelseがあった場合、そのelseは実行されない。
for i in range(10): print(i) if i == 5: break else: print("else")
※Javaでは二重ループの外側にラベルを定義しておき、breakでそのラベルを指定することで二重ループから抜け出すことが出来るのだが、Pythonではそういう指定では出来ない。
continueは、forやwhileループの次の周期の処理へ移る。
continue
for i in range(10): if i == 5: continue print(i)
importは、モジュールをロードし、その名前を定義する(その名前のオブジェクトとして使用できるようになる)。
import モジュール 〔as 別名〕〔, モジュール…〕 from モジュール import オブジェクト名 〔as 別名〕〔, …〕 from モジュール (import オブジェクト名 〔as 別名〕〔, …〕) from モジュール import *
from節を使う書き方は、モジュール内のオブジェクトをインポートする。(Javaのstaticインポート相当?)
globalは、グローバル変数を宣言する。
global 変数名〔, 変数名…〕
def f(): global x print(x) # 1が表示される x = 2 x = 1 f() print(x) # 2が表示される
通常は、関数の中で変数を定義すると、その変数はローカル変数となる。
変数を使う前にglobal宣言しておくと、その変数はグローバル変数になる。
nonlocalは、(グローバル以外で)ひとつ外側の関数スコープの変数を参照するようにする。
nonlocal 変数名〔, 変数名…〕
def f(): a = 1 b = 1 print(a, b) # 1 1 def g(): nonlocal a a = 2 # nonlocalにより、aはg()の外側で定義された変数を指すことになる b = 2 # bはnonlocal宣言されていないので、普通のローカル変数 print(a, b) # 2 2 g() print(a, b) # 1 2
if文は、条件に応じて処理を分岐する。
if 条件: 複文 〔elif 条件: 複文 …〕 〔else: 複文〕
条件は、真偽値に変換できる値であれば、どんな型でもよい。
if a == 1: print(11) else: print("else")
if a == 1: print(11) else: print("else")
if a == 1: print(11) elif a == 2: print(22) else: print("else")
→if式
while文は、条件を満たす間ループする。
while 条件: 複文 〔else: 複文〕
条件を満たさなくなった時、elseが(もしあれば)実行される。
最初から条件を満たさないときでもelseは実行される。
処理本体からbreakで抜けるときはelseは実行されない。
for文は、シーケンス(主にリスト)やset, dict等(イテレート可能オブジェクト)の各要素を順番に処理する。
for 変数 in イテレート可能オブジェクト: 複文 〔else: 複文〕
イテレート(反復処理)が終了した時、elseが(もしあれば)実行される。
最初から空の場合でもelseは実行される。
処理本体からbreakで抜けるときはelseは実行されない。
for文のループに使用した変数は、for文を抜けた後でも使用可能で、最後に代入された値が残っている。
すなわち、正常に終了した場合はイテレート可能オブジェクトの一番末尾の値が入っている。(elseの有無は無関係)
breakで抜けた場合はそのときの値が入っている。
(Javaの場合はfor文の変数はfor文の中のみで使用できるローカル変数という扱いになるので、for文が終了した後では使用できない)
for i in [1, 2, 3]: print(i)
for i in [1, 2, 3]: print(i)
for i in [1, 2, 3]: print(i) else: print("else")
指定回数繰り返したい場合はrangeがよく使われる。
for i in range(5): # [0, 1, 2, 3, 4]と同等 print(i)
タプルのシーケンスも処理することが出来る。
for (s, n) in [("a", 1), ("b", 2), ("c", 3)]: print(s, n)
Pythonのタプルは丸括弧を省略できるので、以下のように書くことも出来る。
for s, n in [("a", 1), ("b", 2), ("c", 3)]: print(s, n)
シーケンスの各要素の値にインデックス(要素の順番)も加えて扱いたい場合は、enumerateを使うのが便利。
enumerateコンストラクターは、シーケンス等のイテレート可能オブジェクトに連番を付加したタプル(インデックスと値の組)のイテレート可能オブジェクトを返す。
for i, s in enumerate(["a", "b", "c"]): print(i, s)
↓実行結果
0 a 1 b 2 c
※ScalaのzipWithIndex相当。「for((s, i) <- Seq("a", "b", "c").zipWithIndex)
println(i, s)
」
try文は、例外を処理する。
try: 複文 except 〔例外クラス名〔as 変数〕〕: 複文 … 〔else: 複文〕 〔finally: 複文〕
try: 複文 finally: 複文
exceptがあると、tryで発生した例外を(excpetで指定した例外クラスとマッチしていたら)処理する。
exceptで受け取った例外をそのまま再度外側へ送出したい場合は「raise」を書けばよい。(Javaだと「throw e;
」と書くところだが、Pythonのraise文は引数なしだと現在の例外を再送出してくれる)
elseは、tryで例外が発生しなかったときに実行される。
(tryの末尾に文を書くと、そこで発生した例外はexceptで捕捉する対象となるが、elseで発生した例外はexceptの対象外)
finallyは(tryで例外が発生してもしなくても)必ず最後に実行される。
→例外を自分で発生させるのはraise文
→Javaのtry-with-resources構文に当たるのはPythonではwith文
try: print("try") ... except BaseException as e: print(e) print(e.args) print(e.__cause__) # raise文のfrom節で指定された例外オブジェクト else: print("else") finally: print("final")
with文は、リソースの生成・解放を行う。(Javaのtry-with-resources相当)
try-finallyをカプセル化したもの。
with オブジェクト〔as 別名〕〔, …〕: 複文
withで指定されたオブジェクトは、__enter__メソッドが呼ばれ、with文が終了するときに__exit__メソッドが呼ばれる。(これらのメソッドが無いとエラーになる)
(Javaだと、tryに指定できるオブジェクトはAutoCloseableインターフェースを実装している必要があり、tryが終了するときにcloseメソッドが呼ばれる)
例 | 説明 | Java相当 |
---|---|---|
r = R() |
R r = new R(); |
|
with R() as r: |
try (R r = new R()) { |
|
with R1() as r1: |
複数リソース指定 | try (R1 r1 = new R1()) { |
with R1() as r1, R2() as r2: |
try (R1 r1 = new R1(); R2 r2 = new R2()) { |
with文に指定できるクラスを自作する場合は以下のような感じにする。
class C: def __enter__(self): print("enter") def __exit__(self, exc_type, exc_value, traceback): print("exit")
exc_typeは例外クラス、exc_valueは例外オブジェクト、tracebackはトレース情報。
これらはwith文の本体で例外が発生した場合に値がセットされる。(例外が発生しなかった場合はNone)
関数はdef文で定義する。
クラス定義の中でdef文を書くとメソッド定義になる。
def 関数名(〔引数名〔= 初期値〕〔, 引数…〕〕)〔-> 戻り値の型〕: 複文
クラスはclass文で定義する。
class クラス名〔(親クラス名, …)〕: 複文
ふつう、hogeという名前のメソッドを指すときは「hogeメソッド」、hogeという関数なら「hoge関数」と書く。
特に「呼び出す」という使い方をする場合は「hogeメソッドを呼び出す」「hoge関数を呼び出す」で違和感無い。
が、例えばrangeは、使い方は「range(10)」の様に関数呼び出しに見えるが、実際はrangeクラスのインスタンス生成である。
この場合、「range関数」というものは無いので、呼び出すという表現が使えない。「rangeオブジェクトの生成」ではあるが「rangeオブジェクトを呼び出す」のはおかしい。
なので、当ウェブページでは(仕方なく)「rangeコンストラクターを呼び出す」と書くことにした。
例えば引数について語りたい場合、「rangeオブジェクトの第1引数」はおかしいが、「rangeコンストラクターの第1引数」なら間違っていないだろう。