Nekoya Press

2017-07-21 Fri 05:10

逆引きPython - コーディングスタイル(社内向け)

INDEX

  • コーディングスタイル
  • ファイル操作
  • 日付・時刻
  • その他
  • 基本方針

    Pythonの公式ガイドであるPEP8を基本とする(mumumu版日本語訳)。

    ただし、全てのファイルの先頭に以下のエンコーディング宣言を入れるものとする。

    # -*- coding: utf-8 -*-
    

    これは、ソースコード内に日本語を書くことをイレギュラーとして捉えることを抑止するためである。

    「日本語でコメントを入れたいけど、その前にエンコーディング宣言を入れなければ」のような事態が発生することは、現状を鑑みると好ましくないと判断した。

    それ以外の細かい部分は原則としてGoogle Python Style Guideに従うが、絶対厳守というわけではない。

    明文化しているわけではないが、なんとなくこんな感じでやってる。

    1. メンバーの理解を損ねない範囲でクラスを直接importしてもよい
    2. サードパーティライブラリの公式ドキュメントにあれば関数を直接importしてもよい

    1はそろそろ改めることも考えていいかもしれない…

    Google Python Style Guideはrev 2.29の和訳があるが、2014/01/03現在の最新版はrev 2.59になっているので差分は追いかけたい。

    表記に関する規約

    flake8による文法チェック

    プロダクトのコードは全てflake8による文法チェックを通過することとする。

    vimを使っている場合は、vim-flake8でファイルの保存時に随時チェックをかけることを推奨する。

    インストールは適当にやればいいが、例えばプレーンなvim環境だと~/.vim/plugin/でこういう風にやる。

    pip install flake8
    wget --no-check-certificate https://raw.github.com/nvie/vim-flake8/master/ftplugin/python_flake8.vim
    

    .vimrcに以下を書いておくと保存時に自動チェックが出来る。

    autocmd BufWrite *.py :call Flake8()
    

    任意で実行したければ以下のようにキーを割り当てれば良い。

    map  :!inspect_python %
    " もしくは以下
    autocmd FileType python map   :call Flake8()
    

    チェックしたくないルールは.vimrcに以下のように記述すればOK

    let g:flake8_ignore="E501,E128,E124,E221"
    

    こういうのを書いておくと、トグルでE501の判定ON/OFFとか出来るのでご自由に。

    let g:flake8_ignore = ''
    function! Flake8IgnoreToggle()
        let rule = 'E501'
        if g:flake8_ignore == rule
            echo 'flake8 check E501'
            let g:flake8_ignore = ''
        else
            echo 'flake8 ignore E501'
            let g:flake8_ignore = rule
        endifendfunction
    nnoremap 5 :call Flake8IgnoreToggle()
    

    一行の文字数

    PEP8の制約がゆるくなって「チームで合意が取れるなら一行100文字でもいいんじゃねーの」という記述になったようだ。

    今までチーム的には「厳しいけど他に基準がないので80文字に収める、ただしテストコードは破ってもよい」としていたが、この変更を受けて「全てのコードを一行100文字未満に収める」ことを規約とする。

    プロジェクトのルートディレクトリに以下のようなsetup.cfgを置けば、あとはよしなにやってくれる。

    [flake8]
    max-line-length = 99
    

    テストコードの書き方

    テストランナー

    noseを使う。今のトレンドはPytestっぽいけど、乗り換えるだけのメリットが感じられないので今までの路線を継続する。

    ok_, eq_の禁止

    今まではこの2つを積極的に利用してきたが、これから書くコードについてはこの2つを使ってはならない。

    Python2.7になってunittest.assertEqualでリストや辞書を比較して違った時の出力がPytestみたいに親切になったので、

    from nose.tools import assert_equal
    

    としてこれを使う。

    ok_についてはこれまでも特に取り上げなかったが、eq_とセットで扱うべきだと考えられるので(どちらもnose/tools/trivial.pyで定義されている)個別のassert系のメソッドを利用することとする。

    assert_equalのmaxDiff設定

    長い項目で差異があった場合、assert_equalが情報を省略する。この挙動はmaxDiffで調整できる。

    import nose.tools
    nose.tools.assert_equal.__self__.maxDiff = None
    

    のように書くと、一切の省略をしないようになる。この値をどうするかはプロジェクトごとに判断すればよい。

    現時点での推奨は、プロジェクトごとにtestutils.pyを持ち、その中でプロジェクト標準の設定値を与えることとする。

    assertionの順序

    assert_equalなどの「実値」と「期待値」を比較する場合は、期待値を後に書く。

    公式ドキュメントでは、

    assertEqual(first, second, msg=None)
    

    first, secondとなっていて、順序については記載がない。

    JUnitでは期待値が先になっていて、Javaのバックグラウンドがある人はこちらを自然なものとして捉えている。phpunitも同様である。

    PerlではTest::Moreがgot, expectedの順で書くことを標準としている。

    RubyのRSpecは文法そのものが違うが、実値に対して「XXであるべき」のような記述をするので期待値が後のパターンと考えられる。

    unittestのドキュメントにはfirst, secondとしか書いていないが、ドキュメントのサンプルコードが全て期待値を後に書いているので、それに従うことにする。

    nekoya.github.io