nikkie-ftnextの日記

イベントレポートや読書メモを発信

イベントレポート | #pyhack にて 退py のコードをオブジェクト指向でリファクタリングするというプロポーザル駆動開発を進めました

はじめに

頑張れば、何かがあるって、信じてる。nikkieです。
11/30の pyhack で手を動かした内容を備忘のためにまとめます。

勉強会の概要

(第105回)Python mini Hack-a-thon - connpass

基本的に毎月開催です。スプリントのゆるい版みたいな感じで各自自分でやりたいことを持ってきて、勝手に開発を進めています。参加費は無料です。 初めての方も常連さんもぜひご参加ください。

11/30は他のPython勉強会と重なったこともあり、人数は10〜15人くらいで推移し、ゆったりめでした。

やったこと

標題についての解説です。

背景

Pythonを始めたときに『退屈なことはPythonでやらせよう』1(退py2)にお世話になりました。
この本をはじめ、入門書で最初に見たコードを繰り返し真似る中で、同様のコード3が書けるようになりました。

      if width > SQUARE_FIT_SIZE and height > SQUARE_FIT_SIZE:
          # Calculate the new width and height to resize to.
          if width > height:
❶            height = int((SQUARE_FIT_SIZE / width) * height)
              width = SQUARE_FIT_SIZE
          else:
❷            width = int((SQUARE_FIT_SIZE / height) * width)
              height = SQUARE_FIT_SIZE

          # Resize the image.
          print('Resizing %s...' % (filename))
     ❸     im = im.resize((width, height))

こちらのようなコードを書いて自分のやりたいことができるのは非常に嬉しいのですが、仕事でも書く中で変更しにくさを感じるようになりました。
そこで、動作し、かつ、変更しやすいコードをPythonで書けるようになりたいと最近はオブジェクト指向のインプットをしています。

取り組み

退py 17章の画像処理のコード(前掲)をオブジェクト指向で書き直してみます。

オブジェクト指向で書き直すにあたって、増田さんの本や、増田さんの本で言及されている『ThoughtWorksアンソロジー』の「オブジェクト指向エクササイズ」を参考にしました。
インプットした内容の実践です。

なお、単体テストを書いて進めるテスト駆動開発をしています。

成果

画像ファイル1つを渡す場合(MVP)は動作させられました。

# 縮小したい画像のパスを渡すと
$ py-im-process ~/Downloads/pyconjp.jpg
# カレントディレクトリに縮小した画像ができる
$ open pyconjp.jpg

もう少し手を動かしてCfPに落とし込んでいきます。

手を動かす中で気づいたこと

  • Python.gitignoreをコピペでなくwgetすればいいと気づく:wget https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore -O .gitignore4
  • 単体テストで返り値の型を確認するassertIsInstanceメソッドが存在していたことに気づく
    - 長いこと`isinstance`の返り値がTrueか確認していました。恥ずかしい😖
    
  • ファーストクラスコレクションに__iter__メソッドを実装
    • ファーストクラスコレクション自体がfor inに置けるようになる(ファーストクラスコレクションの持つリスト型のプロパティだけでなく)
In [5]: @dataclass
   ...: class Foo:
   ...:     list_: List[int]
   ...:     def __iter__(self):
   ...:         return iter(self.list_)
   ...:

In [6]: l = Foo([1, 2, 3])

In [9]: for i in l.list_:
   ...:     print(i)
   ...:
1
2
3

In [10]: for i in l:
    ...:     print(i)
    ...:
1
2
3

In [5]: iter(l)
Out[5]: <list_iterator at 0x108e035c0>

今後やりたいこと

  • 変更しやすさを体験したい
    • 指定した画像ファイルをグレースケールにもできるようにしたい
    • argparseのadd_subparser
    • main関数がまだ知りすぎている(カプセル化しきれていない)ので修正する
  • 存在する画像ファイルが指定されたことの検証
    • argparseのadd_argumenttypeを使えばできそう
  • 画像ファイル単体でなく、ディレクトリも指定できるようにしたい
  • テストを書いていることを活かしてリファクタリング
    • クラスの分け方、もっとよくできないか試したい

終わりに

久々参加の #pyhack、人が少なめだったので、がっつりやりたい開発ができて満足しています。
必要そうな小さなクラスを作った後、それらを使って1つの処理を組み立てるところで時間がかかるので、設計のときに呼び出し関係を考えた方がよさそうです。

次回12/14は 技書博2 と重なったので、タイムラインから見つめています。 参加者の皆さま、1日ありがとうございました。

PS: 2020年のnikkieへ

新規開発でmypy導入するっ!


  1. 原著(英語版)の2nd Editionが出たようです。100ページ増! ref: What's New in the 2nd Edition of "Automate the Boring Stuff with Python" - The Invent with Python Blog

  2. 一部の熱狂的なファン(私です)による呼称です

  3. 英語版の本文とソースコードは公開されています。続くコードは Automate the Boring Stuff with Python より

  4. ref: gitignore を落としてくれるシェルスクリプト - 私が歌川です