代码之家  ›  专栏  ›  技术社区  ›  Stefano Borini

伪装一个类的真实模块

  •  3
  • Stefano Borini  · 技术社区  · 16 年前

    假设您有一个python包的如下布局

    ./a
    ./a/__init__.py
    ./a/_b.py
    

    里面 __init__.py 你有

    from _b import *
    

    在你的房间里

    class B(object): pass
    

    如果从交互提示导入

    >>> import a
    >>> a.B
    <class 'a._b.B'>
    >>> 
    

    我怎样才能完全隐藏“B”的存在?

    我要解决的问题是:我想要一个Facade包导入“隐藏”的模块和类。门面上可用的类(在我的例子中 a )保持稳定,为未来提供保障。但是,我希望能够自由地将类重新定位到“引擎盖下”,从而实现隐藏模块。这一切都很好,但是如果一些客户机代码对外观提供的对象进行了pickle处理,那么这个pickled数据将引用隐藏的模块嵌套,而不是外观嵌套。换句话说,如果我重新定位 B 模块中的类 _c.py ,客户端代码将无法取消拾取,因为pickled类引用 a._b.B ,已移动。如果他们提到 a.B 我可以根据需要在引擎盖下重新定位B类,而不会破坏泡菜数据。

    2 回复  |  直到 16 年前
        1
  •  5
  •   bobince    16 年前

    尝试:

    B.__module__= 'a'
    

    顺便说一下,你可能想要一个绝对进口:

    from a._b import *
    

    由于没有新的显式点语法的相对导入正在消失( see PEP 328 )

    埃塔重新评论:

    我必须为每个类显式地设置模块

    是的,我不认为有什么方法可以解决这个问题,但至少在 __init__ 以下内容:

    for value in globals().values():
        if inspect.isclass(value) and value.__module__.startswith('a.'):
            value.__module__= 'a'
    

    (对于新风格的课程,只有你能摆脱 isinstance(value, type) 而不是 inspect . 如果模块不必以 __main__ 你可以使用 __name__ 而不是硬编码 'a' )

        2
  •  2
  •   miku    16 年前

    你可以设置 __module__ 变量为 Class B

    class B(object): pass
    B.__module__ = 'a'
    

    对于类、函数和方法,此属性包含在其中定义对象的模块的名称。

    或者在你的 __init__.py :

    from a._b import B # change this line, when required, e.g. from a._c import B
    B.__module__ = 'a'