オープンソースカンファレンス2021 Fukuoka
2021/11/20 nikkie
ふだんPython書いてますか?
ガッツリ書いている
入門済み
これから入門
顔出し 推奨👨💼
質問・リアクション、お気軽に どうぞ💬
Zoomのチャット中心に拾います
10/15, 16開催の Py thon Con ference JP 2021の座長🇨🇭でした
=PyCon JP 2021の開催に責任を持つ人
PyCon JP Associationはイベント PyCon JP 20XXをその年の 座長に委託
座長はスタッフを集めて、イベントを開催
Associationにもスタッフがいます
2019 Python言語最新情報
Pythonのアップデート情報の整理(例:Python 3.7~ dataclass)
2020 Python開発環境の整え方
Pythonのインストール、venvなど
PyCon JPのスタッフが様々なテーマで発表
https://pyconjp.blogspot.com/2021/03/pycamp-caravan-osc-online-spring-2021.html
「PyCon JPのスタッフ活動の中でこんなふうにPython使ってます」nikkie
「Python(Dash/Cytoscape)を使ったNetwork Auto Visualization」稲森さん
「本番運用を想定したDjango settings.pyの書き方入門」(筒井さん)(Online/Fall でも)
「あなたの街でもPython広めませんか?」(塚本さん)
「文に立ち返って再入門するPython」(nikkie)
「パッケージ管理ツール poetry が依存関係を解決するアルゴリズムについて」(村上さん)
Pythonを学ぶときに誰しもif文、for文、関数定義(def)を学ぶと思います。入門書執筆を機にこれらの見方が変わったことを共有します。「文」という観点から再入門しませんか?(概要より)
プログラミング言語Pythonの情報収集を目的としている人
プログラミング言語についての基礎的な知識
if
文などの突っ込んだ話ですPython入門済みの方は「へ〜🤩」くらいで大丈夫です
Pythonを知らない方は自分の使っている言語と比較して面白い🤩と思ってもらえたら嬉しいです
文という観点はニッチだと思うので、キョトンとした場合は、先ほどのリンク集をどうぞ!
導入として、なぜこの話をするか 共有します。
Pythonの文法を、プログラミングの入門者に説明
if
文
for
文
while
文
関数定義(def
)
if
文のサンプルプログラム
name = input("名前を入力してください: ")
if name == "ローランド":
print("俺か")
else:
print("俺以外か")
$ python3 roland.py
名前を入力してください: nikkie
俺以外か
ref: https://zenn.dev/kuramapommel/books/introduce_polymorphism/viewer/chapter2
「〇〇のときはこれこれする」のような 条件分岐 はこう書きます
if name == "ローランド": # ifの行にはコロンが必要です
print("俺か") # インデント(半角スペースを入れた字下げ)が必要です
else: # elseの行にもコロンが必要です
print("俺以外か") # インデントを忘れずに!
自分が入門したときの説明が元なので、自分の理解が上限になってしまう
少し深堀り、自分の理解を更新 した上で、入門者に分かりやすく説明したい
そうだ、言語リファレンス 読んでみよう
if
文などの見方変わった!!
ポイントは「文」
リファレンスの内容はこの発表でも語り尽くせないですが、裏側を知る楽しさが少しでも伝わったら嬉しいです
プログラムの実行
式
文
構文
プログラムの実行
式
文
構文
プログラムの実行について、処理系の動きを少しだけ深堀りします。
if
文のサンプルプログラムを実行
name = input("名前を入力してください: ")
if name == "ローランド":
print("俺か")
else:
print("俺以外か")
$ python3 roland.py
名前を入力してください: ローランド
俺か
パスで指定したファイルに書かれた プログラムが処理系に渡る
リファレンスでは 9. トップレベル要素 で説明(「完全な Python プログラム」や「ファイル入力」)
標準入力からプログラムを渡すこともできます(が、 roland.py
は input
があるのでうまく動きません)
字句解析器
パーザ
(抽象構文木やバイトコードの実行などあると思いますが、今回はスコープアウトとさせてください)
パーザへの入力は、 字句解析器 (lexical analyzer) によって生成された一連の トークン (token) からなります。 この章では、字句解析器がファイルをトークン列に分解する方法について解説します。
NEWLINE、INDENT、および DEDENT の他、以下のトークンのカテゴリ: 識別子 (identifier), キーワード(keyword), リテラル, 演算子 (operator), デリミタ (delimiter) が存在します。
字句解析器:プログラムをトークンに分解する
パーザ:トークンが入力される 👈 こちらが扱う「構文」について見ていきます
プログラムの実行
式
文
構文
「文」の前に「式」を少しだけ深堀りします。
A statement is either an expression or one of several constructs with a keyword,
文は、式または、キーワードから構成されるものです(nikkie訳)
式
キーワード(から構成されるもの)
順番に見ていきます
何かの値と評価される、一まとまりの構文 (A piece of syntax which can be evaluated to some value.)
言い換えると、式とは(中略)値を返す式の要素の積み重ねです。 (In other words, an expression is an accumulation of expression elements [...] which all return a value.)
リテラル (literals)
名前 (names)
属性アクセス (attribute access)
演算子 (operators)
関数呼び出し (function calls)
など(リファレンス 6. 式 参照)
Python では言語の全ての構成要素が式というわけではありません。 (not all language constructs are expressions.)
代入も式ではなく文です。(Assignments are also statements, not expressions.)
文の構成要素のもう一つ
いくつかのトークンがキーワードです(キーワード ⊆ 識別子 ⊆ トークン)
if
for
while
def
else
以下の識別子は、予約語、または Python 言語における キーワード (keyword) として使われ、 (The following identifiers are used as reserved words, or keywords of the language)
※「以下の識別子」として、先のスライドのキーワードも挙げられています
名前 (name)とも呼ばれる
ASCII範囲では [a-zA-Z_0-9]
(数字は先頭に使えない。 variable2 = 108
)
ASCII範囲外も使える(数 = 1231
)
通常の識別子として使うことはできません。(2.3.1. キーワード (keyword))
>>> if = 1231
File "<stdin>", line 1
if = 1231
^
SyntaxError: invalid syntax
式
キーワード(から構成されるもの)
この後は キーワードから構成される文 にフォーカスします
プログラムの実行
式
文
構文
タイトル回収、いよいよ「文」です。
A statement is part of a suite (a “block” of code).
文はスイート (コードの"ブロック") の一部です。(nikkie訳)
複合文は、一つ以上の '節 (clause)' からなります。 節は、ヘッダと 'スイート (suite)' からなります。
複合文には、他の文 (のグループ) が入ります; 複合文は、中に入っている他の文の実行の制御に何らかのやり方で影響を及ぼします。
# if文は複合文
if name == "ローランド": # 節(1つ目)
print("俺か") # 他の文が入っている
else: # 節(2つ目)
print("俺以外か") # 他の文が入っている
節は、ヘッダと 'スイート (suite)' からなります。(8. 複合文)
ヘッダ
スイート
各節のヘッダは一意に識別するキーワードで始まり、コロンで終わります。(8. 複合文)
if name == "ローランド": # ヘッダ(キーワードifで始まり、コロンで終わる)
print("俺か")
else: # ヘッダ(キーワードelseで始まり、コロンで終わる)
print("俺以外か")
スイートは、(中略)ヘッダに続く行で一つ多くインデントされた文の集まりです。
if name == "ローランド":
print("俺か") # スイート
else:
print("俺以外か") # こちらもスイート
(承前)後者(※前スライドで引用)の形式のスイートに限り、さらに複合文をネストできます
if name == "ローランド":
for _ in range(3): # スイートにfor文(複合文)を書ける
print("俺か")
else:
print("俺以外か")
if name == "ローランド": # ifの行にはコロンが必要です
print("俺か") # インデントが必要です
else: # elseの行にもコロンが必要です
print("俺以外か") # インデントを忘れずに!
# キーワードifを使った複合文、それを構成する節として見えるようになった!
if name == "ローランド": # コロンが付くのはヘッダだから
print("俺か") # インデントするのはスイートだから
else:
print("俺以外か")
節・ヘッダ・スイートで、入門書で出会った説明 + それまでPythonを書いてきた経験が 腑に落ちた (こういうことだったのか!)
さらに、文の定義(構文)は、言語リファレンスで明示されている!(次の話題)
プログラムの実行
式
文
構文
リファレンスの中の「文の定義」について共有します。
字句解析と構文に関する記述では、BNF 文法記法に手を加えたものを使っています。
各規則は name (規則によって定義されているものの名前) と ::= から始まります。
|
*
+
[]
()
"
『 』(※空白です)
|
複数の選択項目を分かち書きするときに使います
「または」
*
直前にくる要素のゼロ個以上の繰り返しを表します
+
プラス (+) は一個以上の繰り返し
*
に似て、直前に来る要素の一個以上の繰り返し
[]
角括弧 ([ ]) に囲われた字句は、字句がゼロ個か一個出現する (別の言い方をすれば、囲いの中の字句はオプションである)
()
字句のグループ化には丸括弧を使います。
"
リテラル文字列はクオートで囲われます。
空白はトークンを分割しているときのみ意味を持ちます。
前提「lc_letter は 'a' から 'z' までの何らかの文字一字」
name ::= lc_letter (lc_letter | "_")*
(lc_letter | "_")*
|
: lc_letter
またはリテラルの _``(例: ``z
, _
)
丸括弧によるグループ化
*
により、「lc_letter
またはリテラルの _
」の0個以上の繰り返し(例: z
, w_
, prq
)
lc_letter (lc_letter | "_")*
lc_letter
の後に、「lc_letter
またはリテラルの _
」が0個以上の繰り返されることを表す
例: a
, b_
, cde
この規則を name
として定義した
8. 複合文 中の定義を読んでみましょう
拡張したBNF記法に沿って読むと、簡潔な行数で、抜け漏れなく説明される 感動がありました!
if
文
while
文
for
文
関数定義(def
)
if
文if 文は、条件分岐を実行するために使われます:
if
文の構文if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]
if
文 1/3if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]
キーワード if
で始まるヘッダと続くスイートからなる節は 必須
if
文 2/3if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]
elif
の節は 0回以上 の繰り返し(ない場合もあるし、複数ある場合もある)
if
文 3/3if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]
else
の節は オプション (0回または1回繰り返し)
assignment_expression
if
節や else
節のヘッダに登場する assignment_expression
について
assignment_expression
は代入式assignment_expression ::= [identifier ":="] expression
大きな構文の一部として、変数に値を割り当てる新しい構文 := が追加されました。 この構文は セイウチの目と牙 に似ているため、「セイウチ演算子」の愛称で知られています。
https://docs.python.org/ja/3/whatsnew/3.8.html#assignment-expressions
代入式により len() 関数を二重に呼びだすことを回避しています:
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
assignment_expression ::= [identifier ":="] expression
:=
は オプション として if
文の定義に登場
:=
が使えるようになるんだくらいの理解だったが、制御フローの構文が変わるほどの 大きな変更だった ことを実感
while
文の定義にも登場します
while
文while 文は、式の値が真である間、実行を繰り返すために使われます:
while
文の構文while_stmt ::= "while" assignment_expression ":" suite ["else" ":" suite]
while
文while_stmt ::= "while" assignment_expression ":" suite ["else" ":" suite]
キーワード while
で始まるヘッダと続くスイートからなる節が 必須
オプションの else
の節
while
else
式が偽であれば (最初から偽になっていることもありえます)、 else 節がある場合にはそれを実行し、ループを終了します。
最初のスイート内で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。
else
節を使わないのがオススメ項目9 forループとwhileループの後のelseブロックは使わない
Effective Python 第2版 (誤解を生みやすいためと説明されます)
for
文for 文は、シーケンス (文字列、タプルまたはリスト) や、その他の反復可能なオブジェクト (iterable object) 内の要素に渡って反復処理を行うために使われます:
for
文の構文for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite]
for
文for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite]
キーワード for
で始まり in
を含むヘッダと、続くスイートからなる節が必須
オプションの else
の節
for
else
全ての要素を使い切ったとき(略)else 節があればそれが実行され、ループは終了します。
最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。
関数定義は、ユーザ定義関数オブジェクトを定義します
def
)funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
キーワード def
で始まり関数名 funcname
と ()
を含むヘッダと、続くスイートからなる節が必須
()
の中の仮引数 parameter_list
はオプショナル
funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
他にもオプショナルなもの
デコレータ decorators
(👉Appendix)
返り値の型を表す型ヒント -> expression
の部分
Pythonで書かれたファイル(プログラム)は、構文解析器でトークンとなり、パーザに入力される
トークンレベルで、文について見てきた
Pythonという言語は 式と文 から構成される
文の構成要素は、式、または キーワード から構成されるもの
後者の文のうち、複合文について見てきた(例: if
文)
複合文は 節 から構成される
節は ヘッダとスイート からなる(コロンやインデントの意味!)
複合文の定義はリファレンス中にあり、拡張したBNF記法で 簡潔に表されて いる(if
文をはじめとして読んでみた)
入門者への説明をきっかけに、 自分の文法理解を入門書より深めたく て、言語リファレンスに潜った
今回の内容は入門者にはアウトプットできないので、OSCでアウトプット
言語リファレンスを読むのは楽しいし、もっと深いところへ潜りたい🤩(発表内容へのフィードバック歓迎です)
Enjoy development with Python!
紹介した構文よりも、文の動きの説明を読みたい方へ
Pythonチュートリアル 4. その他の制御フローツール
python.jp ゼロからのPython入門講座
東京大学 Pythonプログラミング入門
tokenize
でトークンにしてみるtokenize モジュールはコマンドラインからスクリプトとして実行することができます
python -m tokenize [-e] [filename.py]
https://docs.python.org/ja/3/library/tokenize.html#command-line-usage
roland.py
をトークナイズ(一部抜粋)
$ python3.10 -m tokenize -e roland.py
2,0-2,2: NAME 'if'
2,3-2,7: NAME 'name'
2,8-2,10: EQEQUAL '=='
2,11-2,18: STRING '"ローランド"'
2,18-2,19: COLON ':'
2,19-2,20: NEWLINE '\n'
3,0-3,4: INDENT ' '
3,4-3,9: NAME 'print'
3,9-3,10: LPAR '('
3,10-3,14: STRING '"俺か"'
3,14-3,15: RPAR ')'
3,15-3,16: NEWLINE '\n'
2. 字句解析 の内容を紹介
字句解析と構文について拡張したBNF記法が使われますが、本編は構文だけに絞りました