在元类中发现模块的问题__new __

时间:2017-03-29 15:42:29

标签: python metaprogramming metaclass

基本上,我想加载特定模块的所有函数(如果存在)并将它们与类方法合并。如果我在__module__内部构建了__new__类,我可以直接构建模块并导入它。我正在寻找一个get_module_fns来解决我的问题。我希望做的事情如下:

get_module_fns('pathto.mod1.toimport') 

如果存在,则会将所有函数作为dict返回。

这是代码和测试的link

# mtcl.py
import inspect
import imp


def get_module_fns(module_name, module_path):
    try:
        mod_loaded = imp.load_source(module_name, module_path)
        module_fns = [(name, func) for name, func in
                      inspect.getmembers(mod_loaded, inspect.isfunction)]
    except FileNotFoundError as e:
        return {}
    except ImportError as e:
        return {}
    return dict(module_fns)


class GetModuleFunctions(type):

    def __new__(cls, name, bases, namespaces, **kwargs):

        module_functions = get_module_fns('toimport', './toimport.py')
        namespaces.update(module_functions)

        new_class = super(GetModuleFunctions, cls).__new__(
            cls, name, bases, namespaces)

        new_class._mdl_fns = module_functions

        return new_class


class ClassBase(metaclass=GetModuleFunctions):

    def __init__(self, *args, **kwargs):
        super(ClassBase, self).__init__(*args, **kwargs)

    @property
    def module_functions(self):
        return self.__class__._mdl_fns
# mod0.py
from .mtcl import ClassBase


class M0(ClassBase):

    def function_m0(self):
        return 0  
# mod1/__init__.py
from ..mtcl import ClassBase


class M1(ClassBase):

    def function_m1(self):
        return 1
# mod1/toimport.py

def function_1(obj,  *args, **kwargs):
    return 1
# mod1/mod2/__init__.py
from ...mtcl import ClassBase


class M2(ClassBase):

    def function_m2(self):
        return 2
# mod1/mod2/toimport.py

def function_2(obj,  *args, **kwargs):
    return 2

1 个答案:

答案 0 :(得分:1)

尝试以下方法:

import inspect
import importlib


def get_module_fns(cls, module_name):
    try:
        mod_loaded = importlib.import_module(
            '%s.%s' % (cls.__module__, module_name)
        )
        module_fns = [(name, func) for name, func in
                      inspect.getmembers(mod_loaded, inspect.isfunction)]
    except ModuleNotFoundError as e:
        return {}
    except ImportError as e:
        return {}
    return dict(module_fns)


class GetModuleFunctions(type):

    def __new__(cls, *args, **kwargs):
        new_class = super(GetModuleFunctions, cls).__new__(
            cls, *args, **kwargs)
        module_functions = get_module_fns(new_class, 'toimport')
        for name, fn in module_functions.items():
            setattr(new_class, name, fn)
        new_class._mdl_fns = module_functions
        return new_class

由于您正在查找类模块中的模块,因此应该这样做:

mod_loaded = importlib.import_module(
    '%s.%s' % (cls.__module__, module_name)
)

可悲的是,您无法在namespace之后使用__new__.super

for name, fn in module_functions.items():                
    setattr(new_class, name, fn)