伪装一个类的真实模块

Ste*_*ini 3 python

假设你有一个python包的以下布局

./a
./a/__init__.py
./a/_b.py
Run Code Online (Sandbox Code Playgroud)

__init__.py你的内心

from _b import *
Run Code Online (Sandbox Code Playgroud)

你在_b.py里面

class B(object): pass
Run Code Online (Sandbox Code Playgroud)

如果从交互式提示导入

>>> import a
>>> a.B
<class 'a._b.B'>
>>> 
Run Code Online (Sandbox Code Playgroud)

我怎样才能完全隐藏_b的存在?

我试图解决的问题如下:我想要一个导入"隐藏"模块和类的Facade包.从外观(在我的情况下a)可用的类保持稳定并保证将来.但是,我希望自由地在"引擎盖下"重新定位类,因此隐藏模块.这一切都很好,但是如果一些客户端代码挑选了一个由Facade提供的对象,那么这个pickle数据将引用隐藏模块嵌套,而不是外观嵌套.换句话说,如果我B在模块中重新定位类_c.py,客户端代码将无法解开,因为pickled类指的是a._b.B已移动的.如果他们提到a.B,我可以在引擎盖下尽可能多地重新安置B级,而不会破坏腌制数据.

bob*_*nce 5

尝试:

B.__module__= 'a'
Run Code Online (Sandbox Code Playgroud)

顺便提一下,您可能想要绝对导入:

from a._b import *
Run Code Online (Sandbox Code Playgroud)

因为没有新的显式点语法的相对导入正在消失(参见PEP 328).

ETA评论:

我必须为每个类明确设置模块

是的,我认为没有办法解决这个问题,但你可以至少自动完成它,最后__init__:

for value in globals().values():
    if inspect.isclass(value) and value.__module__.startswith('a.'):
        value.__module__= 'a'
Run Code Online (Sandbox Code Playgroud)

(对于新式类,只有你可以逃避isinstance(value, type)而不是inspect.如果模块不必运行,__main__你可以使用__name__而不是硬编码'a'.)