きっかけ
ある日、「プログラマー脳〜優れたプログラマーになるための認知科学に基づくアプローチ〜」という本を読んだ。
そこで紹介されていたのは、“コードを読む力”を育てるために、自分の好きな言語でコードを要約してみようというアプローチ。
なるほど、読むことからすべてが始まるのか。
ということで、いざ実践!

今回のターゲット
せっかくなので、Pythonの標準ライブラリから選ぶことにした。
選ばれたのは、datetime
モジュール。
GitHubで開かれているdatetime.pyのソースコードは、コメント含めて約2.5KL(キロライン!)あるが……
さすがに全部は無理。
そこで、今回はこの関数を読んでみることにした:
def _name_from_offset(delta):
if not delta:
return 'UTC'
if delta < timedelta(0):
sign = '-'
delta = -delta
else:
sign = '+'
hours, rest = divmod(delta, timedelta(hours=1))
minutes, rest = divmod(rest, timedelta(minutes=1))
seconds = rest.seconds
microseconds = rest.microseconds
if microseconds:
return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
f'.{microseconds:06d}')
if seconds:
return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
return f'UTC{sign}{hours:02d}:{minutes:02d}'
なんか名前からして、UTCまわりの何かをやってそうな気がするぞ?
読んでみたら、こうなった
1. 関数名をじっと見る
まずは関数名と引数名。_name_from_offset
。ふむふむ。
「オフセットから名前を作る」らしい。名前? どの名前? 地名? 時間名?芸名?
しかも先頭にアンダースコアがあるから内部用っぽい。
引数のdelta
も気になる。何が入ってくるんだ、これ?
まぁ考えてても始まらないので中を読んでみる。
2. 最初のif not delta:
にひっかかる
if not delta:
return 'UTC'
おぉ、いきなりのnot
。
「deltaが“ない”ときは’UTC’を返す」のか。なるほど。
でもちょっと待って。deltaって何型?
文字列? 数値? まさかのNone??
「notって、何に使えるんだっけ…?」とふと不安になったので、Pythonのnot
演算子を調べてみた。
not
は真偽値を反転します。TrueならFalseに、FalseならTrueに。
はい、これは知ってた。けど、文字列とか数値でもいけるの?
気になったら、試すしかない。
a = ''
print(not a) # True
a = 'aaa'
print(not a) # False
よし、空文字はFalseとみなされる!ということは、delta
が空っぽなら’UTC’を返すんだな。納得。
3. 負の時間?そんなのアリか
次に出てきたのがこれ:
if delta < timedelta(0):
sign = '-'
delta = -delta
なるほど、負の時間が来たら、マイナス記号をつける処理か。
そもそもtimedelta(0)
ってなんだ?
調べればわかるけど、ここは“あえて”想像力でカバーするフェーズ。
引数が0ってことは、「ゼロ時間」を意味してるんだろうな。
つまり、delta
がマイナスなら、sign
に-
をセットして、絶対値に直すってことか。
4. divmod
、お前は誰だ
hours, rest = divmod(delta, timedelta(hours=1))
minutes, rest = divmod(rest, timedelta(minutes=1))
seconds = rest.seconds
microseconds = rest.microseconds
見たことない関数が出てきた。divmod
って何者!?
名前的にはdiv(割り算)+mod(あまり)。たぶん、「商」と「あまり」を同時に返してくれる便利やつ。
たしかに、時間の分解にはぴったりだ。
「まずは1時間で割って、残りで1分を割って、さらにそのあまりから秒とマイクロ秒を…」という処理なんだな。
しかも、rest
って名前も良い。残り物感が出てて好き。
5. 最後の仕上げは文字列フォーマット
if microseconds:
return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
f'.{microseconds:06d}')
if seconds:
return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
return f'UTC{sign}{hours:02d}:{minutes:02d}'
なるほど、マイクロ秒があるならフルで表示。
なければ秒まで。さらに何もなければ分まで、という三段階表示方式。
ちなみに{hours:02d}
みたいな書き方は、2桁でゼロ埋めってやつですね。UTC+09:00
みたいな、よく見るあの形を作ってるのか。
まとめ:コードを読むと、世界がちょっと広がる
ここまで読んでわかったこと:
delta
がなければ'UTC'
を返す- 負のオフセットなら符号をつけて絶対値に
- 時間を分・秒・マイクロ秒単位で分解
- 可能な限り詳細な表記で返す
つまりこの関数は、時差情報をいい感じのUTC表記に変換してくれるやつだったのだ。
そして静かに感動する
自分がいつも何気なく見ていたUTC+09:00
みたいな表示、
あれ、こんなふうに作られていたのか。
知らなかったものが、ちょっとだけわかるようになる。
そんな一歩が、コードを読む楽しさかもしれない。
おまけ:今後の自分へ
もしまたdivmod
に出会ったときは、「お、君か!」と声をかけてあげよう。
そしてrest
には、そっと敬意を払いたい。

コメント