「The Python Tutorial」では、コアライブラリについてもう少しサンプルを取り上げて紹介している。こちらもPythonのコアライブラリ(コアモジュール、コアパッケージ)がどういった機能を提供しているのかの一端を知る上で重要なので、もう少し触れておきたいと思う。
urllibモジュール
Pythonはインターネットを経由してやり取りを行うためにさまざまなプロトコルに対応している。チュートリアルでは、最もシンプルな例としてurllibモジュールからurlopen()を使ってコンテンツを取得する例を紹介している。次のようなサンプルだ。
>>> from urllib.request import urlopen
>>> with urlopen('http://www.example.com/') as response:
... for line in response:
... line = line.decode('utf-8') # Decoding the binary data to text.
... print(line)
...
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 50px;
background-color: #fff;
border-radius: 1em;
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
body {
background-color: #fff;
}
div {
width: auto;
margin: 0 auto;
border-radius: 0;
padding: 1em;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents. You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
>>>
urlopen()でURLを指定してレスポンスを取得し、それをfor制御構文で回しながら中身を出力するといった内容になっている。上記のサンプルを見るとわかるように、出力結果にはレスポンスヘッダは含まれていない。プロトコルの基本的なやり取り部分を隠蔽しつつ、比較的簡単に、かつベースとなっている仕組みを壊すことなくストレートな抽象化が行われていることがわかる。
チュートリアルではもう1つの例としてメールを送信する方法も紹介している。シンプルな方法だが、Pythonがどのような考え方でプロトコルを隠蔽しているか知ることができて興味深い。
datetimeモジュール
日付データは何かと処理する必要が多いデータの1つだ。Pythonではdatetimeモジュールにこれらの機能がまとまっている。
>>> # dates are easily constructed and formatted
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2019, 5, 7)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'05-07-19. 07 May 2019 is a Tuesday on the 07 day of May.'
>>>
>>> # dates support calendar arithmetic
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
20003
>>>
ほかの多くの主要なプログラミング言語がそうであるように、Pythonは日付データの生成と演算、それにフォーマットを指定した出力などを行えることがわかる。ログデータの分析や日付データを含む売上データな集計データの分析などに使うことが多く、かなり重要度の高いモジュールとなっている。
zlibモジュール
データの圧縮や展開、ハッシュ値の計算などはzlibモジュールにまとまっている。特定のフォーマットやアルゴリズムであれば、zlibモジュールを使ってデータの作成や展開が可能だ。
>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41
>>>
>>> t = zlib.compress(s)
>>> len(t)
37
>>>
>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979
>>>
>>> s
b'witch which has which witches wrist watch'
>>> t
b'x\x9c+\xcf,I\xceP(\xcf\xc8\x04\x92\x19\x89\xc5PV9H4\x15\xc8+\xca,.Q(O\x04\xf2\x00D?\x0f\x89'
>>>
サンプルに掲載されているように、データの圧縮や展開も簡単に処理できる。
timeitモジュール
プログラムでは処理にかかった時間を計測して性能とすることがよくあるが、PythonではtimeitモジュールのTimer()を使うことで簡単に実行時間の計測ができるようになっている。
>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.026792650984134525
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.026966486999299377
>>>
Timer()を使うことでどこの処理に時間がかかっているかを簡単に調べることができる。
テストコードの実行 - doctestモジュールとunittestモジュール
コーディングにおいては、試験用のコードをどのように織り交ぜていくかが、ソースコードのクオリティやエンバグを発見する方法として重要になってくる。テスト方法に関してはさまざまな方法論や実装方法が存在しているが、Pythonのチュートリアルではdoctestモジュールを使う方法とunittestモジュールを使う方法を紹介している。
■doctestモジュールの使用サンプル
>>> def average(values):
... """Computes the arithmetic mean of a list of numbers.
...
... >>> print(average([20, 30, 70]))
... 40.0
... """
... return sum(values) / len(values)
...
>>> import doctest
>>> doctest.testmod() # automatically validate the embedded tests
TestResults(failed=0, attempted=1)
>>>
■unittestモジュールの使用サンプル
>>> import unittest
>>>
>>> class TestStatisticalFunctions(unittest.TestCase):
... def test_average(self):
... self.assertEqual(average([20, 30, 70]), 40.0)
... self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
... with self.assertRaises(ZeroDivisionError):
... average([])
... with self.assertRaises(TypeError):
... average(20, 30, 70)
...
>>> unittest.main() # Calling from the command line invokes all tests
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
doctestモジュールはコメントに試験用コードを書いておく方法、unitestはそれ専用にテストメソッドを実装する方法だ。この辺りはどういった方法論を採用するかで使うモジュールやツールが変わってくるのだが、とりあえず「モジュールとしてデフォルトで機能が提供されている」ということは知っておくとよいだろう。
小さいツールを作って利用する程度であれば、ユニットテストなどについて気にかける必要はない。だが、小さいツールであってもある程度の数を作成するとか、規模の大きなツールを作成するとなると、ユニットテストを使うことも考えておきたい。仕様としても機能するし、互換性を確保するという観点からも重要になってくる。
「電池を含める」という考え方
Pythonには「Batteries Included(電池を含める)」という考え方があり、それが巨大なパッケージに現れている。これは「デフォルトの状態でそのまま使えるものを提供しよう」という考え方で、実はある程度のことはデフォルトのパッケージだけでもできるようになっているのである。
全てを紹介していくとキリがないのでやらないが、Pythonはプログラミング言語としては簡単で学習しやすい。さらに、Pythonがデフォルトで提供しているパッケージで最初からかなりのことができてしまったりする。連載の長い回数を使ってPythonの説明を行っているのはこのためだ。PythonはLinuxを使っていく上で強力なツールになってくれる。ほかのプログラミング言語と比較してそれほど学習は苦にならないはずなので、先行投資として学んでおいて損はない。
・ The Python Tutorial