Mae向きなブログ

Mae向きな情報発信を続けていきたいと思います。

Pythonエンジニア育成推進協会監修 Python実践レシピ(5)

Pythonエンジニア育成推進協会監修 Python実践レシピ(4) - Mae向きなブログ」の続きです。

Chapter 17 デバッグ

ipdb を使ったデバッグをするときに、同じディレクトリに以前作成したdecorator.pyがあると、これが悪さをしているようでした。decorator.pyをリネームすると動作するように。

コードの実行時間を計測する

アルゴリズムの違いによる性能差を測るときなどに使いそうなのでメモ。以下は、foo()関数を10回(number回)呼んだときにかかる時間を計測している。以下を実行すると、1.045367584と表示された。

import time
import timeit

def foo():
    time.sleep(0.1)

print(timeit.timeit('foo()', globals=globals(), number=10))

Chapter 18 暗号関連

cryptographyは、暗号化、復号を提供するライブラリである。RSAを使用する場合、より深い知識を身につけたうえで使用することが推奨されている。

Chapter 19 並行処理、並列処理

  • 逐次処理 着手したタスクを完了させてから、次のタスクに着手する
  • 並列処理 複数のタスクを同時に着手する
  • 並行処理 着手したタスクを状況に応じて中断し、次のタスクに着手する(asyncioはこれ)
並行処理の練習

1から50までの和を1~10, 11~20, 21~30, 31~40, 41~50の5つのタスクに分けて実行する。それぞれのタスクは、sec秒かかるようにしている。

import asyncio
from time import time

async def part_of_sum(f, t, sec):
    await asyncio.sleep(sec)    # 時間がかかる処理
    return sum([i for i in range(f, t+1)])

async def main():
    start = time()
    tasks = [
        asyncio.create_task(part_of_sum( 1, 10, 3)), #  1から10までの和を3秒かけて求める
        asyncio.create_task(part_of_sum(11, 20, 2)), # 11から20までの和を2秒かけて求める
        asyncio.create_task(part_of_sum(21, 30, 1)), # 以下、同様
        asyncio.create_task(part_of_sum(31, 40, 5)),
        asyncio.create_task(part_of_sum(41, 50, 4))
    ]
    results = await asyncio.gather(*tasks)
    print(f"{sum(results)}")
    print(f"time: {time() - start}")
    
asyncio.run(main())

それぞれの部分を求めるのに、3秒+2秒+1秒+5秒+4秒かかるので、逐次処理だと15秒かかることになるが、実行してみると5秒で実行できていることから、並行処理ができている。

1275
time: 5.002140998840332

奔流の海

こんなことは現実ではあり得ないというストーリーですが、だからこそ小説を読む楽しみがあるんだろうと思います。最後はいい感じで物語を終えることができたので読後感は良かったですが、本作品を通して、虐待の問題など考えなければならないですね。

Pythonエンジニア育成推進協会監修 Python実践レシピ(4)

Pythonエンジニア育成推進協会監修 Python実践レシピ(3) - Mae向きなブログ」の続きです。

Chapter 14 インターネット上のデータを扱う

RequestsはPythonでWebスクレイピングを行う際の定番ツール。

>>> import requests
>>> r = requests.get('http://httpbin.org/get')
>>> r
<Response [200]>
>>> r.text
'{\n  "args": {}, \n  "headers": {\n    "Accept": "*/*", \n    "Accept-Encoding": "gzip, deflate, br", \n    "Host": "httpbin.org", \n    "User-Agent": "python-requests/2.27.1", \n    "X-Amzn-Trace-Id": "Root=1-6296bdfc-46a5dc44551a4801724bfd6b"\n  }, \n  "origin": "172.29.0.1, 219.103.2.254", \n  "url": "http://httpbin.org/get"\n}\n'
>>> r.url
>>> r.ok
True
>>> r.json()
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.27.1', 'X-Amzn-Trace-Id': 'Root=1-6296bdfc-46a5dc44551a4801724bfd6b'}, 'origin': '172.29.0.1, 219.103.2.254', 'url': 'http://httpbin.org/get'}

Chapter 15 HTML/XMLを扱う

HTMLのclass属性は、Python予約語との衝突を防ぐためclass_='class名'のように末尾に_を指定する。

>>> from bs4 import BeautifulSoup
>>> from urllib import request
>>> soup = BeautifulSoup(request.urlopen('https://www.python.org'))
>>> soup.find_all('h1')
[<h1 class="site-headline">
<a href="/"><img alt="python™" class="python-logo" src="/static/img/python-logo.png"/></a>
</h1>, <h1>Functions Defined</h1>, <h1>Compound Data Types</h1>, <h1>Intuitive Interpretation</h1>, <h1>Quick &amp; Easy to Learn</h1>, <h1>All the Flow You’d Expect</h1>]
>>> soup.find_all('h1', class_='site-headline')
[<h1 class="site-headline">
<a href="/"><img alt="python™" class="python-logo" src="/static/img/python-logo.png"/></a>
</h1>]
>>> soup.find_all('h1', attrs={'class': 'site-headline'})
[<h1 class="site-headline">
<a href="/"><img alt="python™" class="python-logo" src="/static/img/python-logo.png"/></a>
</h1>]

Chapter 16 テスト

doctestを使った方法はシンプルでいいですね。

sample_doctest.py
"""
与えられた引数について、a / b を行う関数です

>>> div(5, 2)
2.5
"""

def div(a, b):
    """
    答えは小数で返ってきます
    
    >>> [div(n, 2) for n in range(5)]
    [0.0, 0.5, 1.0, 1.5, 2.0]
    """
    
    return a / b

以下、実行結果です。-m doctest -vをつけて実行すると、doctest.testmod()を書いていないコードのdoctestをコマンドラインで実行できる。

% python sample_doctest.py
% python -m doctest -v sample_doctest.py
Trying:
    div(5, 2)
Expecting:
    2.5
ok
Trying:
    [div(n, 2) for n in range(5)]
Expecting:
    [0.0, 0.5, 1.0, 1.5, 2.0]
ok
2 items passed all tests:
   1 tests in sample_doctest
   1 tests in sample_doctest.div
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

頭のよさとは「説明力」だ

説明力とは大まかに言って、次の3つの力によって構成されているとのこと。

  1. 時間感覚
  2. 要約力
  3. 例示力

とくに「要約力」の凄さを実感したのは、ハイデッガーの『存在と時間』で言いたかったことを、小学校4年生にわかるように齋藤孝先生が説明した以下の文。本当に説明力がある人は、相手が小学生だろうが、ビジネスパーソンだろうが、どんな人に対しても上手い説明ができるという例示にもなっていますね。

「人間というのは時間がとても大事な生き物でです。なぜなら、人間の生きる時間は限られているからです。 他の動物は生きて、生きて、結果、死ぬわけで、そんなに死ぬいことばかりを考えているわけではありませんが、人間は『自分がいつか死ぬ』ということをわかって生きているところが違います。 死を意識して生きているからこそ、いずれ死ぬのであれば、もう少し充実して生きようとか、もっと全力を尽くして生きようとか、そういうふうになるのが本来の人間の姿ではないかというふうに言ったのが、ハイデッガーなのです」

時間感覚については、「意味の含有率」が高い話し方というフレーズが印象的。15秒単位のなかにどれだけの意味が詰め込まれているかが大事とのこと。「15秒なのにこんなに詰まっている」という、砂金がたくさん入った砂のような話し方(これも例示)を目指したいですね。

再会

ルパンの娘』シリーズにハマって以来、著者の他の作品が気になって、『K2 池袋署刑事課 神崎・黒木』なども楽しんだのですが、第56回江戸川乱歩賞受賞となった本作も読み応えがあって十分楽しめめる作品でした。

タイトルの「再会」、意味の重さを感じます。登場人物のその後が幸せであって欲しいなと思います。

Pythonエンジニア育成推進協会監修 Python実践レシピ(3)

Pythonエンジニア育成推進協会監修 Python実践レシピ(2) - Mae向きなブログ」の続きです。

Chapter 11 ファイルとディレクトリへのアクセス

from pathlib import Path
TEST_PATH = "/Users/foo/tmp/hoge.pdf"

# ファイル名の取得
print(Path(TEST_PATH).name)
# 拡張子なしのファイ名の取得
print(Path(TEST_PATH).stem)
# 拡張子の取得
print(Path(TEST_PATH).suffix)
# 親ディレクトリの取得
print(Path(TEST_PATH).parent)
# CWDの取得
print(Path.cwd())
# ユーザホームディレクトリの取得
print(Path.home())

Chapter 12 データ圧縮、アーカイブと永続化

gzipコマンドがない環境でも、pythonコマンドの-mオプションを指定することで、コマンドラインで実行できる。

% python -m gzip -h
usage: gzip.py [-h] [--fast | --best | -d] [file ...]

A simple command line interface for the gzip module: act like gzip, but do not delete the input file.

positional arguments:
  file

optional arguments:
  -h, --help        show this help message and exit
  --fast            compress faster
  --best            compress better
  -d, --decompress  act like gunzip instead of gzip
日本語のファイル名を扱う

ZIPファイル中の圧縮されたファイル名に日本語が含まれているとき、環境依存の文字コードでファイル名が格納されている場合があり、注意が必要。

Chapter 13 特定のデータフォーマットを扱う

CSVファイルを扱う
  • 辞書データを用いたCSVファイルの読み込みと書き込みは便利そう
  • csvモジュールのSnifferクラスは、CSVファイルのデータ形式を推測するためのクラス
Excelを扱う
  • Excel VBAが苦手なので、仕事でExcelを扱うときは、RubyExcelファイルを操作してきましたが、openpyxlは便利そうですね。
  • Excel自体がインストールされていなくてもExcelファイルの読み書きができる。
Pillow thumbnails.py
  • /tmp/jpegは、Pathlibを用いているのに対し、save_thubnail_pathについては、文字列で扱っている点が少し疑問に感じました。あまり気にすることではないのでしょうか?