Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

PythonではPEP20 - The Zen of Python(日本語訳)にて次の通り心構えを掲げています。

読みやすいことは善である。特殊であることはルールを破る理由にならない。しかし、実用性を求めると自然さが失われることがある。

無理してPEP8違反ゼロを目指す必要はありませんが、出来る限りPEP8に準拠する統一した読みやすいコードを書いって欲しいです。どの程度の違反が許容範囲なのかは、下部のPyPiランキング上位ライブラリの違反状況で一覧にしてみました。よろしくお願いします。

プロジェクトのPEP8違反を発見する

flake8を利用すると、PEP8準拠状況を簡単に確認できます。

install
pip install flake8
flake8 {project_root} --filename=*.py --exclude=commands,migrations,[^_]*.py --max-line-length=79
実行結果
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でダウンロード数上位50プロジェクトに対して調査してみました。1行あたり平均0.1以下のPEP8違反であれば優秀なプロジェクトと言えるのではないでしょうか。経験上PEP8の存在を知らないPython初心者は1行あたり0.3を超えるコードを書くことが多いです。

スクリーンショット 2015-11-04 16.22.50.png

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)


実行結果
>>> 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チェックプラグインの導入

さいごに

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

スクリーンショット 2015-11-04 16.48.43.png

参考

PEP 0008 -- Style Guide for Python Code
PEP 20 -- The Zen of Python
プログラマが持つべき心構え (The Zen of Python)
PyPI Ranking

haminiku
やや,かみごたえがある。T字形の骨をはさんで片側にヒレ,片側にサーロインの肉のついた大きな塊
http://subc.github.io/
dena_coltd
    Delight and Impact the World
https://dena.com/jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした