Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

実装モジュールを切り替えるモジュール

昨日のコードをモジュール化する

try except ImportErrorとか多い書く人にはいいかも知れないな

modinstaller.py

from abc import ABCMeta, abstractmethod
import sys

def install(imports, *args, **kwargs):
    global _mod_name, _imports
    local = sys._getframe(1).f_locals
    _mod_name = local['__name__']
    _imports = imports
    _search(*args, **kwargs)

class Installer(object):
    
    __metaclass__ = ABCMeta

    @classmethod
    def install(cls, *args, **kwargs):
        i = cls(*args, **kwargs)
        _install(i)


def _install(obj):
    names = _mod_name.split('.')
    if sys.modules.get(_mod_name, None):
        del sys.modules[_mod_name]
    try:
        mod = __import__('.'.join(names[:-1]))
        mod.__dict__[names[-1]] = obj
    except ImportError:
        pass
    sys.modules[_mod_name] = obj
    


def _search(*args, **kwargs):
    for name in _imports:
        try:
            names = name.split('.')
            imp_name = '.'.join(names[:-1])
            nm = __import__(imp_name)
            mod_name = imp_name.split('.')[-1]
            mod = getattr(nm, mod_name, None)
            if mod:
                obj = getattr(mod ,names[-1], None)
                if obj and issubclass(obj, Installer):
                    return obj.install(*args, **kwargs)
        except ImportError:
            pass

使い方
仕込みたいモジュールに

  1. importするクラスの配列

を書く
実装クラスは

  1. Installerクラスのサブクラスであること

例:

example/engine1.py

import modinstaller

class Engine(modinstaller.Installer):
    
    def method(self):
        print("engine1 call")

example/engine2.py

import modinstaller

class Engine(modinstaller.Installer):
    
    def method(self):
        print("engine2 call")

example/engine.py

import modinstaller

imports = ['example.engine1.Engine', 'example.engine2.Engine']
modinstaller.install(imports)

example.engineをimportするとEngineクラスが使えるようにする。
実装クラスは配列の先頭からimportしていきimportできた時点で止まる。

test.py

from example import engine

engine.method()

engine1.Engineがimportできればそれを使用し、なければengine2.Engineを使用する。

Unix系とWindowsで実装モジュール切り替えるとか、kqueue,epoll切り替えとか
いろいろ使う場面はあるよね。