- HOME
- 本当に誰でも読める!! Pythonソースコードの読み方講座(第6回) ソースコードに現れる「単語」を読む
2022年4月 6日 18:40
本記事は当社が発行しているシミュレーションメールマガジンVol.6の記事です。
シミュレーションメールマガジンの詳細・購読申込はこちら
のサポートページから
- Pythonソースコードの読み方講座(第1回) Pythonコードの構成要素
- Pythonソースコードの読み方講座(第2回) classにまつわるコードの読み方
- Pythonソースコードの読み方講座(第3回) キーワード編 1:構文に関するキーワード
- Pythonソースコードの読み方講座(第4回) キーワード編 2:続・構文に関するキーワード
- Pythonソースコードの読み方講座(第5回) 関数にまつわるコードの読み方
- Pythonソースコードの読み方講座(第6回) ソースコードに現れる「単語」を読む
- Pythonソースコードの読み方講座(第7回)キーワード編 3:Pythonの生命線?import文について
- Pythonソースコードの読み方講座(第8回)Python コードを俯瞰する 1:コードの領域分割と実行順序
- Pythonソースコードの読み方講座(第9回)Python コードを俯瞰する 2:コードの領域間の「見え方」について
- Pythonソースコードの読み方講座(第10回)Python コードを俯瞰する 3:関数内の関数について
- Pythonソースコードの読み方講座(第11回)yield 文とジェネレータ
- Pythonソースコードの読み方講座(第12回)yield 文とジェネレータ 2
プログラマにもノン・プログラマにも読んでいただきたい「Pythonコードの読み方」講座の第6回です。 今回は一旦初心に帰り、第1回の続きとしてソースコードに現れる「単語」について整理します。コードを読んでいると、正体のわからない「単語」に出くわすことがあると思います。そのような場合に、その正体を明らかにするための手順や必要な知識を整理していきます。
例文
あくまでコードの読み方の説明のためのものですので、どのような機能を持つかについては考えていただく必要はありません。
import sys import pandas as pd import my_module from my_module2 import something from my_module3 import * FOO = 1 BAR = None def function(a,b,c): v = 10 return v+a+b+c+FOO def main(): v0 = 1 v1 = 2 v2 = 3 res = sum((v0,v1,v2)) res2 = function(v0,v1,v2) assert res==res2 my_module.do_something(res) something(res) unknown_function(res) if __name__=="__main__": main()
単語の分類
今回は単語を次の6つに分類します。それぞれの概要と例文中での出現例は以下のようになります:
分類 | 概要 | 例 |
---|---|---|
キーワード | Pythonの言語機能 | import, if, def |
モジュール | import (=他所で作った機能の取り込み) をしたもの | sys, pd, my_module, something |
組み込みの単語 | Pythonの言語機能 | None, sum, __name__ |
グローバル変数 | 外側で定義したもの | FOO, BAR, function, main |
ローカル変数 | 内側で定義したもの | functionの中の v, a, b, c, mainの中のv0, v1, v2 など |
リテラル | 値を直接記述したもの | 1, 10, "__main__" |
以下、これらを概説いたします。
キーワード
Python の言語が規定している、構文をつくったり機能を呼び出すための特殊な単語です。本連載でも第3回, 第4回で扱いましたのでご参照ください。 エディタでコードを読んでいればハイライトされるので、キーワードである事自体はすぐに分かると思います。その意味を都度調べて覚えていけばよいでしょう。
モジュール
例文では冒頭に import キーワードを使った行があります。このキーワードは外で作られたプログラムを取り込んで使えるようにするためのものです。ここでは sys, pd, my_module, something の4つが読み込まれ、使えるようになっています。
今回のところは「import の行にかかれている単語は外の機能を取り込んだもの」という理解で大丈夫ですが、細かく述べると、モジュールは次のように分類できます:
- 標準モジュール (sys)
最初から import できる、Pythonが用意している外部機能。
公式ドキュメント に一覧があります。 - サードパーティモジュール(pandas)
別途インストールすることで使えるようになる、専門的な機能を備えた外部機能。最近では数値計算や機械学習・データ解析・可視化関連のサードパティモジュールが充実しており、Pythonが科学技術計算分野で良く用いられる理由のひとつになっています。 - 自作モジュール(my_module)
自分で用意したソースコードを読み込んだものです。基本的にはスクリプト名の.py以前の名称を指定します。
import したものがこれらのどれにあたるかは、別途判断が必要です。よく使われる標準モジュールやサードパーティモジュールや、ソースコードの構成を把握しておくと良いでしょう。
例文では main 関数の中で
my_module.do_something(res) something(res)
のように記述されています。my_module, something の正体は最初に import した外部モジュールだった、というわけです。do_something が何かはこのコードだけではわからないので、my_module を定義したソースコードを確認しにいく必要があります。
組み込みの単語
Python が提供している特別な単語があり、これらは特に準備なしで呼び出すことができます。キーワード同様、エディタが Python に対応していればハイライトされるので特別なものであることはわかると思います。 細かくは以下のように分けることができます:
- 組み込み定数 (None)
決まった値を持つ特殊な単語です。他には True, False などがあります。これらはキーワードでもあります。 - 組み込み関数 (sum)
決まった機能を持つ関数たちです。例の sum は数値などの合計を求める関数です。その他、よく使うものとしてはソートする sorted や最大・最小を求める max, min があります。公式ドキュメントに一覧があります。 - 特殊属性 (__name__)
モジュールに付与された特殊な属性になります。__name__ はモジュールの名称で、他には __file__ などがあります。
ハイライトされている単語があれば都度ドキュメントで調べ、少しずつ覚えていくと良いでしょう。
グローバル変数
ソースコードの一番外側(グローバル領域といいます)で用意した変数のことを言います。この例では最初に
FOO = 1 BAR = None
のように FOO, BAR を定義しているため、これらの変数はソースコードのどこからでも用いることができます。また、その次に定義している関数そのものも、グローバル領域に用意されますので同様にどこからでも用いることができます。
function 内の FOO:
return v+a+b+c+FOO
main 内の function:
res2 = function(v0,v1,v2)
などがグローバル変数の参照にあたります。
ローカル変数・リテラル
これらは「その場で用意したもの」と解釈できます。例えば main 内の
v0 = 1 v1 = 2 v2 = 3 res = sum((v0,v1,v2)) res2 = function(v0,v1,v2)
における v0, v1, v2, res, res2 がローカル変数に該当します。 右辺の値 1, 2, 3 のように、値を直接書き込んだものをリテラルと言います。リテラルにはこのような整数値の他に、浮動小数点値や文字列があります。
また、盲点になりがちですが関数の引数もローカル変数になります。
def function(a,b,c): v = 10 return v+a+b+c+FOO
における a, b, c は関数定義の行で定義されたローカル変数だと思えば良いです。実際の値が何になるかは呼び出し方によって決まります(今回の場合、それぞれ v0, v1, v2 が入るので値としては 1, 2, 3 となりますね)。
それでも分からないもの
これまでの説明でほとんどの単語にはimport されている、ローカル変数として定義されている、など何らかの説明がつきます。それでも分からないものが一つだけ残っています。それが main の最後の unknown_function です。 これは何でしょう?実はこの答えは5行目の import 文にあります:
from my_module3 import *
この import 文は「my_module3のすべてのモジュールを読み込む」という動作をします。したがって出所が不明なものはこの * によって外部から取り込まれたものだ、と推測することができます。
また、Pythonの組み込みの exec 関数を用いるなど、ソースコードに陽に現れない特殊な方法で変数を定義することも可能です。
今回は消去法で unknown_function の出どころを特定することができましたが、例えば import * を複数箇所で行っていた場合はどこからきたのか推定不可能になってしまいます。このような書き方はソースコードを解読する上で大きな障害となるため、原則として行うべきではありません。
まとめ: 単語の出所を特定するには
以上の知識をふまえれば、クリーンなコードにおいて単語がどこから来たのかを特定することは必ず可能です。 正体不明の単語が出てきた場合、以下のような順で辿っていくのがよいでしょう
- 直近で定義されていないか(ローカル変数ではないか)?
- 代入文で値が指定されていないか探す
- 関数の引数を見てみる
- Python言語が提供しているものではないか(組み込み語ではないか)?
- 組み込み関数などのドキュメントを参照する
- エディタのハイライトに注意
- グローバル変数ではないか?
- 関数の外をみてみる
- 外部から取り込んだモジュールではないか?
- スクリプト上部の import を確認してみる
これらを行ってもなお不明な場合、
- import * や exec などの特殊な方法で定義された変数である
- 実はタイポで、そのような変数は存在しない(実行するとエラーとなる)
といった可能性が考えられます。いずれにしてもそのようなソースコードの取り扱いには注意が必要となるでしょう。
以上をふまえて、快適な Python コードリーディングライフ(?)をお送りください!
S4 Simulation System の開発のほか、機械学習・シミュレーション・数理最適化を幅広く扱い、分野を横断した問題解決に取り組んでいる。
入社後に競技プログラミングをはじめ、PGBATTLE2023にて企業の部団体3位入賞。
著書: 「XAI(説明可能なAI)──そのとき人工知能はどう考えたのか?」リックテレコム
趣味: 合唱