LoginSignup
2
0

More than 5 years have passed since last update.

PEP 562 -- Module __getattr__ and __dir__を試してみた Part2

Last updated at Posted at 2018-07-11

前回の続き。

PEP 562 -- Module __getattr__ and __dir__を試してみた - Qiita

「__getattr__と__dir__関数を試してみた」と言いながら、__dir__を試していないことに気づいた。

前回の続きでmain3.pyを追加して実行すると以下のようになる。

getattr/main3.py
import getattr

print(dir(getattr))
実行結果
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__getattr__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'importlib']

ここには、file_loaderやdb_loaderが追加されていない。
そこで、__init__.pyに__dir__()を追加する。

__init__.py
import importlib


__all__ = ['file_loader', 'db_loader']


def __getattr__(name):
    if name in __all__:
        return importlib.import_module("." + name, __name__)
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


def __dir__():
    return __all__
実行結果
['db_loader', 'file_loader']

ただし、これだと__all__に代入した2つしか出力されなくなるので、

__init__.py
import importlib
import sys

__all__ = ['file_loader', 'db_loader']


def __getattr__(name):
    if name in __all__:
        return importlib.import_module("." + name, __name__)
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


# 位置が重要
__all__ += dir(sys.modules[__name__])


def __dir__():
    return __all__
実行結果
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__getattr__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'db_loader', 'file_loader', 'importlib', 'sys']

こうすることで、元のアトリビュートに追加することができる。
注:__dir__()の中でdir()を呼ぶと無限再起してしまいます

ちなみに、あまり考えずにgetattrディレクトリを作ってパッケージ名にしてしまったけど、getattr()組み込み関数があるのでよくない命名だった。

2
0
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
2
0