Python3 プログラミング勉強会の補足
先日、Python3 プログラミング勉強会 を開催しました。
以下に資料の中で引用したサンプルコードを置いておきました。
ちなみにこういったサンプルコードをアップする前に pep8 と flakes と doctest のテストを実行しておけば typo してツッコミを受けることもありません。例えば pytest 使えば、以下のように簡単にできます。
$ py.test --pep8 --flakes --doctest-module --clear . ============================= test session starts ============================== platform linux -- Python 3.4.0 -- py-1.4.20 -- pytest-2.5.2 plugins: flakes, pep8, cache collected 39 items algorithm_set1.py .... generator_sample1.py ... generator_sample2.py ...... generator_sample3.py ....... lru_cache_sample1.py .... singledispatch_sample1.py .... super_sample1.py .... test.txt . with_sample1.py ...... ========================== 39 passed in 0.15 seconds ===========================
ページ14: バージョニングのお話
勉強会ではスライドを飛ばしたけど、バージョニングのスキームがすごいことになってます。
[N:]N(.N)*[{a|b|c|rc}N][.postN][.devN]
RPM 以外で Epoch をバージョニングのスキームに組み込んでいるのを私は初めてみました。PEP440 の提案者が Nick Coghlan (@ncoghlan_dev) で、プロフィールをみると Red Hat で働いている開発者だったので元ネタは RPM なのかもしれません。あと、Python の3番目のバージョンをマイクロと呼ぶのも知りませんでした。
ページ16: setuptools の原罪と贖罪
このスライド1枚作るのに何時間もかけて情が移ってしまったために、このスライドを力説し過ぎて時間を浪費してしまいました。この資料の中で一番価値のあるスライドだと思っているいるので、何かに困ったときに見返してください。
ページ17: パッケージングと pbr
あー、pbr の話ももっとしたかったです。これだけで勉強会しても良いぐらいです。OpenStack プロジェクトで何が起きているか、みたいなのは今後の Python の未来に大きな影響を与えるような気がします。
簡単に紹介すると、setup.py にパッケージ情報を書かずに setup.cfg に Metadata2.0 のフォーマットでパッケージ情報を記述できます。
$ git clone https://github.com/openstack-dev/pbr
$ cd pbr/
$ vi setup.py import setuptools from pbr import util setuptools.setup( **util.cfg_to_args())
$ vi setup.cfg [metadata] name = pbr author = OpenStack author-email = openstack-dev@lists.openstack.org summary = Python Build Reasonableness ...
git の履歴から AUTHORS や ChangeLog も自動生成してくれます。git のコミットログから ChangeLog を作ってくれるのは結構便利かもしれませんね。コミットログの最初の行を ChangeLog のサマリとして扱ってるようにみえます。マージのコミットログは無視してたりして賢いです。
$ workon pbr3 # pbr や関連ツールをインストールしておいた仮想環境を使う (pbr3)$ python setup.py sdist (pbr3)$ head AUTHORS Alex Gaynor <alex.gaynor@gmail.com> Andrew Bogott <abogott@wikimedia.org> Angus Salkeld <asalkeld@redhat.com> Anthony Young <sleepsonthefloor@gmail.com> Attila Fazekas <afazekas@redhat.com> Ben Nemec <bnemec@redhat.com> Bhuvan Arumugam <bhuvan@apache.org> Brian Waldon <bcwaldon@gmail.com> Chang Bo Guo <guochbo@cn.ibm.com> ChangBo Guo(gcb) <eric.guo@easystack.cn> ... (pbr3)$ cat ChangeLog CHANGES ======= * Allow examining parsing exceptions * Update integration script for Apache 2.4 * Restore Monkeypatched Distribution Instance * Register testr as a distutil entry point * Check for git before querying it for a version * Allow _run_cmd to run commands in any directory * Make setUp fail if sdist fails * Permit pre-release versions with git metadata * Un-nest some sections of code 0.8.2 ----- * Remove --use-mailmap as it's not needed * Fix typos in docs 0.8.1 ----- * pbr/testr_command.py: Add logging * Documentation updates * Fixed a typo in the documentation * Make source configurable when using --coverage * README.rst: tweaks * Format autoindex.rst file properly * make pbr use hacking directly ... (pbr3)$ git log commit e1b98f578a0f94a791210dd48530e2fed43fbe61 Merge: fa17f42 6541911 Author: Jenkins <jenkins@review.openstack.org> Date: Mon Jun 30 17:34:07 2014 +0000 Merge "Check for git before querying it for a version" commit fa17f42d7d195dab77c042ac4881ac63bfb638f3 Author: Robert Collins <rbtcollins@hp.com> Date: Mon Mar 17 09:46:58 2014 +1300 Allow examining parsing exceptions. Having to put breakpoints in pbr to diagnose issues is bad for dealing with reports from users. Change-Id: Ifecf4c4e4bb5955e0e5feb4bf5b5b85150b08ebe commit d815366577a7dbb7a8dab66ab105e2803af4c007 Merge: ec1009c bdb0191 Author: Jenkins <jenkins@review.openstack.org> Date: Fri Jun 27 02:29:12 2014 +0000 Merge "Un-nest some sections of code" commit ec1009cf197ed555b29b6f226adb300914ea5bd0 Author: Sean Dague <sean@dague.net> Date: Thu Jun 26 08:22:47 2014 -0400 Update integration script for Apache 2.4 Apache 2.4 requires site configuration files to have a ".conf" extension, and Apache 2.2 does not want the extension. Add logic to figure out the right name for the file so we can run the tests against both versions of Apache. Fixes bug: #1334326 ...
テストランナーに tox と testr を使います。setuptools の拡張コマンドに testr オプションが追加されています。デフォルトでテストを並列実行 (CPU の数かな?) してくれるようです。
(pbr3)$ python setup.py testr running testr running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --list running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpe9wwqlo3 running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpbwa1_yy8 running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpqv7w0s4v running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpqdbg34vv running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpkd169eki running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmpch2tkra0 running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmp6h4ef3mr running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . --load-list /tmp/tmp6407izna Ran 57 tests in 2.529s (-0.726s) PASSED (id=9, skips=8) (pbr3)$ python setup.py testr --testr-args --concurrency=1 running testr running=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . Ran 57 tests in 9.140s (-0.065s) PASSED (id=7, skips=8)
ページ21: Pythonic なコード
エキスパート Python プログラミングから引用しました。
Pythonic とは、小さなコードパターンに最も効率的なイディオムを使ったコーディングや構文
最近、他人の Python コードを読んでいて「何かおかしい」と違和感を感じるときは、この Pythonic の概念を大事にしてコードを書いているかどうかの違いによるもののような気がしてきました。OSS のフレームワークやライブラリを使うときにも、その開発者の意図に共感できると親しみがもてたりするものです。
Pythonista というと、一貫性にこだわる怖い人たちなんでしょう?のイメージがあります。もちろんそういった場面にもよく遭遇しますが、
- The Zen of Python
Although practicality beats purity. ( とはいえ、純粋さよりも実用的であること )
- PEP8 の一節
A Foolish Consistency is the Hobgoblin of Little Minds
とか言っていて、一貫性にこだわり過ぎるのもよくないという戒めもあります。こだわりは強くても極論はよくないといった感じですかね。
ページ23: functools.singledispatch
汎用関数が気持ちよく書ける、デコレーターの応用例の紹介をしました。
勉強会でも singledispatch をコードリーディングしたのですが、ソースもシンプルなのでデコレーターの実用例としておもしろいと思います。
ページ33: Python 2.4 との互換性を気にする
これを気にしなくなって Python3 に感激したのも事実の1つです。
標準モジュールがなかったり、機能のバージョン毎の差異を吸収するように実装したものがいくつかありました (ここにサンプルコードを置きました) 。2.4 対応を考慮しながらコードを書くと、常にこういったことに悩まされながらコードを書いているという例です。あくまで自分の用途にあわせた実装なのでサンプルコードは参考程度にみてください。
ページ34: 集合型 set の応用例
これもスライドを飛ばしたけど、集合型をこんな用途にも使えるんだなぁと感心したスニペットです。アルゴリズムを勉強したくなる気を起こさせるコードでした。
def has_invalid_fields_loop(fields): """ >>> has_invalid_fields_loop(['foo', 'bar', 'foo', 'test']) True >>> has_invalid_fields_loop(['foo', 'bar']) False """ for field in fields: if field not in ['foo', 'bar']: return True return False def has_invalid_fields_set(fields): """ >>> has_invalid_fields_set(['foo', 'bar', 'foo', 'test']) True >>> has_invalid_fields_set(['foo', 'bar']) False """ return bool(set(fields) - set(['foo', 'bar']))
ページ35: super はスーパーな話
簡単な分かりやすいサンプルコードを提示したつもりだったのに、絶賛大ブーイングを受けたサンプルコードがこれでした。こんな複雑なことをする意図が分からない的な。
メソッド解決順序(MRO) がとても分かりやすいけれど、全てのクラスが object を継承するようになったため、どんな多重継承を行っても必ずダイヤモンド継承になる。多重継承が本当に必要かどうかの議論はもちろんあって良いですが、mixin 的に機能を扱いたいときとか、普通にその MRO や移譲先を意識して設計するでしょうし、サブクラスで拡張することを意識してコア機能作ったりするんじゃないかなぁとも思います。フレームワークとプラグインのような、それぞれの開発者が異なるケースでもたくさん応用例がありそうに思いますが、ちゃんと調べないと分からないぐらいにはややこしいです。
後半で時間がなかったからちゃんと背景を説明をしなかったせいでもあるけれど、もっと私も勉強しないといけないです。
ページ42: The Hacker's Guide to Python
Python Weekly で The Hacker's Guide to Python が紹介されていて、機会があったら読もうと思っていました。ちょうど勉強会するからと読み始めたらおもしろくて、この本を読んだために勉強会の内容もかなり変わってしまったぐらい影響を受けました。本当は AST やパフォーマンスの章も紹介したかったけれど、準備が全然間に合わなくて断念しました。