0

背景问题

python 程序导入一些模块,每个模块创建各种类。它还导入了一个带有子模块的包,这些子模块需要能够看到 Python 程序顶层可用的所有类。包子模块如何查看其导入器可用的所有类?

这是我当前的解决方案,它有效,但它需要顶级程序从子模块创建一个实例并通过globals()实例方法传入字典(见下文)。至少在导入包的子模块后只需执行一次。

什么是不需要顶级程序通过其的更好方法globals()?如果可能的话,我希望这对顶级程序透明地自动发生。

带注释的输出

$ python top_t.py 
Hi, I'm an instance of ModM!
# Expected, but not desired.
ModM in SubModS:0's globals = No
Adding globals from higher level to level of SubModS.
# Yeah!
ModM in SubModS:0's globals = Yes
# Persistent
ModM in SubModS:1's globals = Yes
# Sufficient to create a new instance from submodule.
Hi, I'm an instance of ModM!

代码

top_t.py

from mod_m import ModM
from package_p import SubModS

m0 = ModM()
s0 = SubModS(0)

s0.see_class('ModM')
s0.broaden_view(globals())
s0.see_class('ModM')
s1 = SubModS(1)
s1.see_class('ModM')
m1 = s0.create_inst('ModM')

mod_m.py

class ModM(object):
    def __init__(self):
        print "Hi, I'm an instance of ModM!"

package_p/__init__.py

__all__ = ['SubModS']
from .submod_s import SubModS

package_p/submod_s.py

class SubModS(object):
    def __init__(self, i):
        self.i = i
    def see_class(self, cls):
        print "{} in {}:{}'s globals = {}".format(cls, self.__class__.__name__, self.i, 'Yes' if cls in globals() else 'No')
    def broaden_view(self, higher_globals):
        print 'Adding globals from higher level to level of {}.'.format(self.__class__.__name__)
        local_globals = globals()
        for nm, ob in higher_globals.iteritems():
            if nm not in local_globals:
                local_globals[nm] = ob
    def create_inst(self, cls):
        return globals()[cls]()
4

1 回答 1

0

在考虑了 BrenBarn 的评论并探索(谷歌搜索)Python 插件框架后,我决定根据以下链接制作一个适合我需要的非常简单的框架:

上述示例的修改版本如下所示(见下文)。

关键是使用元类来收集基于中心便利基类的所有类的列表。

程序输出

$ python top_t.py
Hi, I'm instance #0 of SubModS!
Can ModM be seen by SubModS:0?  Yes!
Can UnBasedClass be seen by SubModS:0?  No!
Hi, I'm instance #0 of ModM!
Hi, I'm instance #1 of ModM!
Can SubModS be seen by ModM:1?  Yes!
Hi, I'm instance #1 of SubModS!

代码

top_t.py

from mod_m import ModM
from package_p import SubModS

s0 = SubModS()
s0.see_class('ModM')
s0.see_class('UnBasedClass')
s0.create_inst('ModM')

m0 = ModM()
m0.see_class('SubModS')
m0.create_inst('SubModS')

mod_m.py

from package_p import PluginBase
class ModM(PluginBase):
    def __init__(self):
        super(ModM, self).__init__()

package_p/__init__.py

__all__ = ['SubModS', 'PluginBase']
from .meta_base import PluginBase
from .submod_s import SubModS

package_p/submod_s.py

from .meta_base import PluginBase
class SubModS(PluginBase):
    def __init__(self):
        super(SubModS, self).__init__()

package_p/meta_base.py

class PluginMount(type):
    def __init__(cls, name, bases, attrs):
        if not hasattr(cls, 'plugins'):
            cls.plugins = []
        else:
            cls.plugins.append(cls)

class PluginBase(object):
    __metaclass__ = PluginMount
    i = 0
    def __init__(self):
        self.i = self.__class__.i
        print "Hi, I'm instance #{} of {}!".format(self.i, self.__class__.__name__)
        self.__class__.i += 1
    def see_class(self, name):
        print "Can {} be seen by {}:{}?  {}!".format(name, self.__class__.__name__, self.i, 'Yes' if name in (cls.__name__ for cls in self.__class__.plugins) else 'No')
    def create_inst(self, name):
        for cls in self.__class__.plugins:
            if name == cls.__name__:
                return cls()
        return None

希望这对其他人有帮助!

当然欢迎其他方法和评论。

谢谢!

于 2013-11-01T23:07:27.670 回答