26
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

自作 Package の submodule の import と flake8

Last updated at Posted at 2019-08-11

21世紀も20年経とうとしている今、Python スクリプトを走らせてスペルミスなどの単純ミスて止まるのは文明的じゃない; flake8 などの静的解析を使おう。それは多くの記事があるのでいいとして、自作の package に flake8 を使うと

F401 'mypackage.module1' imported but unused

みたいなことをいう。その import には意味があるんだけど... という話。

設定

package とは複数のモジュールがひとつのディレクトリに入ったもの:

mypackage/
  + __init__.py
  + module1.py
  + module2.py
import mypackage

して使う。

module1.py では関数 function1() が、module2 には class Class2 が定義してあるとしよう。

問題

import mypackage

mypackage.module1.function1()
c = mypackage.Class2()

のように使うために __init__.py

import mypackage.module1
from mypackage.module2 import Class2

と書きたい。すると、

$ flake8 mypackage/*.py
mypackage/__init__.py:1:1: F401 'mypackage.module1' imported but unused
mypackage/__init__.py:2:1: F401 'mypackage.module2.Class2' imported but unused

と言われる。確かに __init__.py では使ってないけど意味はあるんだ。これらの import 文が無いと

import mypackage.module1
from mypackage.module2 import Class2

と毎回書かなければならないので、それはナイ。PEP8的な正解は?

解決法1(手っ取り早い方法)

# noqa とコメントすると flake8 などの linter が無視する。

from . import module1  # noqa
from .module2 import Class2  #noqa

解決法2

やらなくても動くけど、package の公式の機能は __all__ にリストアップべき。

Any backwards compatibility guarantees apply only to public interfaces. Accordingly, it is important that users be able to clearly distinguish between public and internal interfaces.

To better support introspection, modules should explicitly declare the names in their public API using the __all__ attribute.

すなわち、

from . import module1
from .module2 import Class2

__all__ = ['module1', 'Class2']

まず、. を使えば「このパッケージ」を意味するので、mypackage と繰り返し書かなくて良い。パッケージ名を変えても修正しなくていいという利点もある。そして __all__ というリストに import したものを書く。すると、unused でなくなったので flake8 さんは満足。

__all__ とは

flake8 を満足させるためだけのダミーの変数というわけではなく、一応意味はある。

__init__.py に import を書かず、

__all__ = ['module1']

と書くと、奨励されないアイツ from mypackage import * した時に

from mypackage import *

module1.funtion()

module1 が読み込まれる。もし、__all__from . import module1 も無ければ、import * でも module1 は読み込まれない。

from . import module1 があれば __all__ = ['module1'] は不要なので __all__ は重複とは言える。逆に、__all__ だけでは import mypackage の時には自動 import してくれない。とはいえ、PEP8 に書かれていることなので、他の人も使う package として公開するときはちゃんと __all__ を書くのが良さそう。

参考

すべてはここに書いてあった。

26
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?