概要

前回(『Effective Python』その6 ビルトインモジュール)のつづきね。7章のノート。

最近友達と一緒にプログラミングしたりしているぼくにとってはホットな話題だ。でもざっと見た感じ、友達との協調作業というか、自作モジュールをどう対外用にどう定義するかってとこに重点がおかれていた。

 

楽しめたところノート

ドキュメンテーション文字列を書く

ドキュメンテーション文字列は __doc__ 属性で取得できる。

 

モジュールに書く

ファイルの一番上にこんなのを書く。

"""モジュールの目的を述べる1文

モジュールの全ユーザが
その働きについて
知っておくべきことの詳細を含む段落

Available functions:
- function1: 関数の説明
- function2: 関数の説明
"""

 

クラスにも書く

class Klass(object):
    """クラスの目的を述べる1文

    クラスの演算の
    重要な詳細を
    論じる段落

    Public attributes:
    - attribute1: アトリビュートの説明(float between 0 and 1)
    - attribute2: アトリビュートの説明(integer)
    """

 

関数にも書く

def function(arg1, arg2):
    """関数が何をするかを述べる1文

    振る舞いと
    引数について
    述べる段落

    Args:
        arg1: 引数の説明
        arg2: 引数の説明

    Returns:
        返り値の説明
    """
  • 返り値がないときは return None とか書く必要ない。
  • ジェネレータなら何を yield するのか述べる。
  • コルーチンなら何を yield し、 yield 式から何を受け取ることを期待し、いつイテレーションを止めるのか記述する。

 

モジュールがデカくなったらパッケージ化する

__init__.py を置くことで、そのディレクトリはパッケージとなる。 from ディレクトリ import モジュール ができるようになる。パッケージ利用の目的はふたつある。

  • モジュールを別々の名前空間に分割。
  • __all__ = ['属性名'] を使うことでエクスポートされる属性を制限し、安定した API を実現。

ただし通常は名前空間の分割だけで十分で、 __all__ は普通は使わない。

 

てか import * はヤメろ

あらゆる Python 本がそう言っているし、ぼくも大賛成。たまに C# をいじるのだけど、 import * 的なものが蔓延しているどころかデフォルトになっていて嫌気がさしてしまう。

 

ルート例外

自作モジュール(API)では自分用の例外階層を定義しよう。

# まずルート例外を定義して……
class Error(Exception):
    """Base-class for all exceptions raised by this module."""

# 他の例外はルート例外を定義する。
class InvalidDensityError(Error):
    """There was a problem with a provided density value."""

# そのモジュールの特有の例外はすべてコレで掴まえられる。
except my_module.Error as e:

わざわざ自作例外を用意すると、 API コードのバグを発見しやすくなる。自分で意図した例外と標準的な例外を分けて掴まえることができるからだ。掴まえた例外が自作例外でなければ、それは起こすつもりではなかった例外ということになり、 API コードのバグだということがわかるのだ。

 

pyvenv 仮想環境を使う だが断る

これまで virtualenvwrapper, pyenv, virtualenv, pyenv-virtualenv, pipenv を使ったことがある。最近は pipenv で落ち着きつつあったのだけど、また新しいのが来たか……しかも名前が似ているし……。とはいえ、目を通してみたところ pyenv とほとんど同じだ。それなら pipenv のほうがいいよ。

むしろここでは pipenv の使い方をおさらいしておく。

# pipenv は pip でサクッとインストールできる。
pip install pipenv
# Mac で、 Homebrew が入っているならこれでも OK。
brew install pipenv

# いま居るディレクトリで仮想環境を作る。
# 指定したバージョンがぱそこになければインストールからやってくれるらしい。
# これによって Pipfile, Pipfile.lock が作られる。
pipenv install --python 3.7

# 仮想環境内で python を実行する。
pipenv run python ***.py

# 仮想環境内にパッケージをインストール。
# Pipfile, Pipfile.lock が更新される。
pipenv install MODULE1 MODULE2
# 開発用パッケージをインストール。
pipenv install --dev MODULE1 MODULE2

# 仮想環境削除。
pipenv --rm

# Pipfile から仮想環境を作成。
pipenv install
# Pipfile.lock から仮想環境を作成。
pipenv sync
# 開発用パッケージも含めてインストールするなら。
pipenv install --dev
pipenv sync --dev

 

小休憩

いつか本物の Pythonista に会ったら訊いてみたいこと第一位、「ドキュメンテーション文字列をクラス名や関数名の上じゃなくて下に書くの見にくすぎないですか?」

Python で唯一センスを疑うポイントだ。

 

Effective Python 感想文一覧