Python的import
语句可以使用导入钩子返回types.ModuleType
的子类吗?我想覆盖__getattribute__
以在特定模块之外的代码引用不在__all__
中的名称时显示运行时警告。
我知道如何在导入后替换sys.modules['foo']
。我想要的是在导入时模式匹配模式的模块,这样导入代码就有机会触发警告。
from somemodule import sys
;相反,它是一个文档工具。这种检测应该通过包含正确的__all__
来更轻松地记录模块的API。它应该可以帮助您避免意外地将sys
引用为somemodule.sys
,而不仅仅是import sys
。
答案 0 :(得分:5)
由于我在你编辑之前错过了你的问题,我想我会再接受一次打击(留下原来的答案给后人)。
这是一个也不需要导入钩子的替代方案。它可以在逐个模块的基础上轻松使用:包含此代码的模块将具有特殊的__getattribute__()
行为,而其他模块将像往常一样运行。
class StrictModule(types.ModuleType):
def __getattribute__(self, key):
if key is "__dict__": # fake __dict__ with only visible attributes
return dict((k, v) for k, v in globals().iteritems()
if k.startswith("__") or k in __all__)
if (key.startswith("__") or key in __all__) and key in globals():
return globals()[key]
else:
raise AttributeError("'module' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
globals()[key] = value
sys.modules[__name__] = StrictModule(__name__)
请注意,只需调用常规module
类型的__getattribute__()
(或者object
类型的),就可以轻松解决此“限制”问题。我的印象是你试图为你的模块提供某种“私人成员”限制。对此几乎没有任何意义。
答案 1 :(得分:3)
您甚至不需要导入钩子。只需在Python的模块注册表sys.modules
中以所需名称引用该对象,Python会话中的任何未来import
语句(即使在其他模块中)都将导入对该实体的引用。
import types, sys
class MyModuleType(types.ModuleType):
pass
sys.modules["foo"] = MyModuleType("foo")
import foo
print type(foo) # MyModuleType
Python甚至不关心sys.modules
中的对象是否实际上是模块或其他类型的对象。你可以在那里放一个int
而不会给出一个f ***。
sys.modules["answer"] = 42
import answer
答案 2 :(得分:3)
你可以调整this ActiveState recipe,也许是这样的:
# safemodule.py
import sys
import types
import warnings
class EncapsulationWarning(RuntimeWarning): pass
class ModuleWrapper(types.ModuleType):
def __init__(self, context):
self.context = context
super(ModuleWrapper, self).__init__(
context.__name__,
context.__doc__)
def __getattribute__(self, key):
context = object.__getattribute__(self, 'context')
if hasattr(context, '__all__') and key not in context.__all__:
warnings.warn('%s not in %s.__all__' % (key, context.__name__),
EncapsulationWarning,
2)
return context.__getattribute__(key)
if 'old_import' not in globals():
old_import = __import__
def safe_import(*args, **kwargs):
m = old_import(*args, **kwargs)
return ModuleWrapper(m)
__builtins__['__import__'] = safe_import
然后,像这样使用它:
C:\temp>python
ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import safemodule
>>> import sys
>>> type(sys)
<class 'safemodule.ModuleWrapper'>
>>>
当然,您可以将其修改为仅包装某些模块等。