Pythonの標準ライブラリ:前半（Python学習メモ⑧）

## OSインターフェース

オペレーティングシステムとやりとりする関数

```python
import os

os.getcwd() # カレントディレクトリ取得

os.system('mkdir today') # システム側のシェルでコマンド実行
```

ファイルやディレクトリの管理には`shutil`モジュールが便利

```python

import shutil

shutil.copyfile('data.db', 'archive.db')

shuti.move('/build/executables', 'installdir')

```

## ファイルのワイルドカード

globモジュールはディレクトリ内をワイルドカード検索してファイルのリストを返す

```python

import glob
glob.glob('*.py')
#.pyが末尾につくファイルのリストが返却される

```


## コマンドライン引数

pythonをコマンド実行した際に渡した引数は`sys.argv`に格納される

```python
import sys
print(sys.argv)
# 引数リストを取得
# 0番目の要素はファイル名になる
```

他にも引数を扱うモジュールとして以下がある

* getopt
* argparse

## エラー出力のリダイレクトとプログラムの終了

`sys`モジュールのstdin, stdout, stderrを使用する

`stderr`は`stdout`がリダイレクトされている際もメッセージを表示するのに便利

## 文字列パターンマッチング

正規表現などは`re`モジュールを使用して実装できる

```python

import re

print(re.findall(r'\bf[a-z]*', 'whitch foot or hand fell fastest'))

# ['foot', 'fell', 'fastest']

print(re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat'))

# cat in the hat

```


## 数学

mathモジュール

```python
import math

math.cos(math.pi / 4)
# 0.7071067811865476

math.log(1024, 2)
# 10.0
```

randomモジュール

```python

import random

random.choice(['apple', 'pear', 'banana'])
# リストからランダムにチョイス
# 'apple'

random.sample(range(100), 10)
# range(100)から10個抽出(重複無し)
# [48, 5, 42, 15, 23, 78, 55, 72, 39, 1]

random.random()
# ランダムな浮動小数点数
# 0.2785335302723758

random.randrange(6)
# range(6)からランダムに選んだ整数
# 0
```

statisticsモジュール - 統計量を求める

```python
import statistics

data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]

statistics.mean(data) # 平均
# 1.6071428571428572

statistics.median(data) # 中央値
# 1.25

statistics.variance(data) # 分散
# 1.3720238095238095
```

他の数値計算用モジュールはSciPyプロジェクトを参照

https://www.scipy.org/

## インターネットへのアクセス

* urllib.request - URLにあるリソースを取得する

```python
from urllib.request import urlopen

with urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl') as response:
    for line in response:
        line = line.decode('utf-8') # バイナリデータをテキストにデコード
        if 'EST' in line or 'EDT' in line: # 東部標準時を探す
            print(line)

```


* smtplib - メールを送る

```python

import smtplib

server = smtplib.SMTP('localhost')
server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
    """To: jcaesar@example.org
    From: soothsayer@example.org

    Beware the Ideas of March.
    """
)

server.quit()
```

## 日付と時間

```python

from datetime import date

now = date.today()

print(now)
# 2019-12-09

print(now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B."))
# 12-09-19. 09 Dec 2019 is a Monday on the 09 day of December.

birthday = date(1964, 7, 31)
age = now - birthday
print(age.days)
# 20219
```

## パフォーマンス計測

変数の交換でのパフォーマンス差を測ってみる

```python

from timeit import Timer

time1 = Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
time2 = Timer('a,b = b,a', 'a=1; b=2').timeit()

print(time1)
# 0.020502762
print(time2)
# 0.018866841999999995
```

他にも`profile`や`pstats`モジュールは大きめのコードブロックに対して計測するのに適している

## 品質管理

関数を書くときにテストも一緒に書いておき、開発中にテストを実行する

`doctest`モジュールは、モジュールをスキャンし、docstringに埋め込まれたテストを検証する

テストは一般的なコールとその結果を`docstring`に記載する

```python
def average(values):
    """数値のリストから算術平均を計算
    
    >>> print(average([20, 30, 70]))
    40.0
    """
    return sum(values) / len(values)

import doctest

doctest.testmod()
# 埋め込まれたテストを自動で検証する


```

`unittest`モジュールはより包括的な一連のテストを別ファイルに持つことができる


```python
import unittest
from doctest_sample import average


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()

```