PEP8コーディング規約を守らないPythonistaは全員等しく糞

Pythonistaが唯一守らなければいけないルールは[PEP8コーディング規約](https://www.python.org/dev/peps/pep-0008/)だと思う。初心者であれば特に変な癖が付く前にエディタにPEP8をチェックするプラグインを導入すべきだ。PEP8違反が多いコードとバグや問題が多発するコードは明らかに相関がある。本エントリではPEP8規約に沿ったコードか確認ツールの導入方法、有名ライブラリのPEP8規約準拠割合、各エディタ毎のPEP8ツールを紹介していく。

Pythonでは[PEP20 - The Zen of Python](https://www.python.org/dev/peps/pep-0020/)([日本語訳](http://qiita.com/IshitaTakeshi/items/e4145921c8dbf7ba57ef))にて次の通り心構えを掲げています。

```py
読みやすいことは善である。特殊であることはルールを破る理由にならない。しかし、実用性を求めると自然さが失われることがある。
```
無理してPEP8違反ゼロを目指す必要はありませんが、出来る限りPEP8に準拠する統一した読みやすいコードを書いって欲しいです。どの程度の違反が許容範囲なのかは、下部のPyPiランキング上位ライブラリの違反状況で一覧にしてみました。よろしくお願いします。

# プロジェクトのPEP8違反を発見する
flake8を利用すると、PEP8準拠状況を簡単に確認できます。


```shell-session:install
pip install flake8
flake8 {project_root} --filename=*.py --exclude=commands,migrations,[^_]*.py --max-line-length=79
```

```shell-session:実行結果
xxxxxx.py:20:1: E101 indentation contains mixed spaces and tabs
xxxxxx.py:20:1: W191 indentation contains tabs
xxxxxx.py:20:9: E223 tab before operator
xxxxxx.py:20:14: E261 at least two spaces before inline comment
xxxxxx.py:21:1: W191 indentation contains tabs
xxxxxx.py:21:8: E223 tab before operator
xxxxxx.py:21:13: E261 at least two spaces before inline comment
xxxxxx.py:22:1: W191 indentation contains tabs
xxxxxx.py:22:10: E223 tab before operator
xxxxxx.py:22:14: E261 at least two spaces before inline comment
xxxxxx.py:23:1: W191 indentation contains tabs
xxxxxx.py:23:9: E223 tab before operator



# 1行毎にPEP8違反しているコードに遭遇すると戦慄が走る
```


# PyPiランキング上位の有名ライブラリのPEP8違反状況
PEP8違反はどのくらいが適切なのか、[PyPi Ranking](http://pypi-ranking.info/alltime)でダウンロード数上位50プロジェクトに対して調査してみました。1行あたり平均0.1以下のPEP8違反であれば優秀なプロジェクトと言えるのではないでしょうか。経験上PEP8の存在を知らないPython初心者は1行あたり0.3を超えるコードを書くことが多いです。

![スクリーンショット 2015-11-04 16.22.50.png](https://qiita-image-store.s3.amazonaws.com/0/65312/010b2de8-3630-24c3-7987-128a8767ec92.png "スクリーンショット 2015-11-04 16.22.50.png")


```py:PEP8違反状況確認コード
# -*- coding:utf-8 -*-
from __future__ import absolute_import, unicode_literals
import os
import commands

pypi_ranking = [
    'simplejson',
    'setuptools',
    'requests',
    'distribute',
    'virtualenv',
    'six',
    'pip',
    'certifi',
    'boto',
    'wincertstore',
    'pbr',
    'python-dateutil',
    'nose',
    'Jinja2',
    'lxml',
    'docutils',
    'MarkupSafe',
    'pyasn1',
    'pytz',
    'PyYAML',
    'pycrypto',
    'pika',
    'rsa',
    'coverage',
    'colorama',
    'Django',
    'psycopg2',
    'botocore',
    'cffi',
    'awscli',
    'paramiko',
    'jmespath',
    'pycparser',
    'SQLAlchemy',
    'ecdsa',
    'redis',
    'selenium',
    'bcdoc',
    'supervisor',
    'Werkzeug',
    'mock',
    'zc.buildout',
    'httplib2',
    'Paste',
    'Flask',
    'pep8',
    'pymongo',
    'carbon',
    'ssl',
    'meld3',

]


def get_py_file_line_count(_dir):
    _cmd_base = 'find {} -name \*.py|xargs wc -l'
    cmd = _cmd_base.format(_dir)
    result = commands.getoutput(cmd)
    return int(result.split('\n')[-1].replace(' total', ''))


def get_flake8_warning(_dir):
    cmd_base = 'flake8 {} --filename=*.py --exclude=commands,migrations,[^_]*.py ' \
               '--max-line-length=79|wc -l'
    cmd = cmd_base.format(_dir)
    return int(commands.getoutput(cmd))

# pip install
for app_name in pypi_ranking:
    os.system('pip install {}'.format(app_name))

# PEP8違反状況の調査
for app_name in pypi_ranking:
    _path_base = '~/.virtualenvs/test1/lib/python2.7/site-packages/{}/'
    path = _path_base.format(app_name)

    # flake8でのPEP8違反
    try:
        flake8_warning = get_flake8_warning(path)

        # pyファイルの合計行数をカウント
        lines = get_py_file_line_count(path)
        per_line = float(flake8_warning) / float(lines)

        print 'APP:{} TotalLine:{} PEP8-warning:{} ' \
              'PEP8-warning-each-line:{}'.\
            format(app_name, lines, flake8_warning, per_line)
    except Exception:
        print "ERROR directory does not exist:{}".format(app_name)


```

```shell-session:実行結果
>>> python check.py
APP:simplejson TotalLine:4041 PEP8-warning:176 PEP8-warning-each-line:0.0435535758476
APP:setuptools TotalLine:9004 PEP8-warning:496 PEP8-warning-each-line:0.0550866281653
APP:requests TotalLine:17168 PEP8-warning:3218 PEP8-warning-each-line:0.187441752097
ERROR directory does not exist:distribute
APP:Jinja2 TotalLine:10806 PEP8-warning:93 PEP8-warning-each-line:0.00860632981677
APP:lxml TotalLine:6533 PEP8-warning:354 PEP8-warning-each-line:0.0541864380836
APP:docutils TotalLine:39915 PEP8-warning:6685 PEP8-warning-each-line:0.167480896906
APP:MarkupSafe TotalLine:816 PEP8-warning:8 PEP8-warning-each-line:0.00980392156863
....

```


# エディタ毎にPEP8チェックプラグインの導入

- PyCharm : 標準で搭載しています。
- vim : [vimでpythonのコーディングスタイルを自動でチェック&自動修正する](http://ton-up.net/technote/2013/11/26/vim-python-style-check-and-fix/)
- Emacs : [Emacs で Python のソースコードを編集するあいだ常に PEP8 のチェックをおこなう](http://qiita.com/ynakayama/items/e5ec9b53ae6eeec4fa6e)
- Ecrips : [Eclipse (luna)とPydevでPythonの開発環境を作る #PEP8に準拠](http://58.hatenablog.com/entry/2014/12/30/190946)


# さいごに
ブーメラン怖いので自分が公開しているモジュールのPEP8違反状況を調べてみた。適切にPEP8チェックプラグインを導入して意識してコードを書いていけば、そうそうPEP8違反をすることは無いと思います。

![スクリーンショット 2015-11-04 16.48.43.png](https://qiita-image-store.s3.amazonaws.com/0/65312/338dc77e-4362-cfb4-41b1-08ed3f7c2f40.png)




# 参考
[PEP 0008 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/)
[PEP 20 -- The Zen of Python](https://www.python.org/dev/peps/pep-0020/)
[プログラマが持つべき心構え (The Zen of Python)](http://qiita.com/IshitaTakeshi/items/e4145921c8dbf7ba57ef)
[PyPI Ranking](http://pypi-ranking.info/alltime)