模块能像对象一样有属性吗?
通过Python的属性,我可以让
obj.y
调用一个函数,而不仅仅是返回一个值。
有没有办法在模块中做到这一点?我有一个情况,我想要
module.y
调用一个函数,而不是仅仅返回存储在那里的值。
8 个回答
61
我这样做是为了正确继承一个模块的所有属性,并且能被isinstance()正确识别。
import types
class MyModule(types.ModuleType):
@property
def y(self):
return 5
>>> a=MyModule("test")
>>> a
<module 'test' (built-in)>
>>> a.y
5
然后你可以把这个放进sys.modules里:
sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class
62
只有新式类的实例才能拥有属性。你可以通过把它放在 sys.modules[thename] = theinstance
里,让Python认为这个实例是一个模块。举个例子,你的 m.py 模块文件可以是:
import sys
class _M(object):
def __init__(self):
self.c = 0
def afunction(self):
self.c += 1
return self.c
y = property(afunction)
sys.modules[__name__] = _M()
79
因为PEP 562在Python 3.7及以上版本中已经实现,现在我们可以这样做了。
文件:module.py
def __getattr__(name):
if name == 'y':
return 3
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
other = 4
示例:
>>> import module
>>> module.y
3
>>> module.other
4
>>> module.nosuch
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "module.py", line 4, in __getattr__
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
AttributeError: module 'module' has no attribute 'nosuch'
注意,如果你在__getattr__
函数中省略了raise AttributeError
,那么这个函数就会以return None
结束,这样module.nosuch
就会得到一个None
的值。
编辑
我的回答不能包含设置器和删除器。如果你需要这些功能,可以参考kxr的回答。
创建一个<class 'module'>
的子类,在那个类中定义属性,然后把模块类改成那个类。
文件:mymodule.py
import sys
class This(sys.__class__): # sys.__class__ is <class 'module'>
_y = 3
@property
def y(self): # do the property things in this class
return self._y
@y.setter
def y(self, value): # setter is also OK
self._y = value
other = 4
sys.modules[__name__].__class__ = This # change module class into This
示例:
>>> import mymodule
>>> mymodule.y
3
>>> mymodule.other
4
>>> mymodule.y = 5
>>> mymodule.y
5
>>> mymodule._y
5 # to prove that setter works
我还太菜,不知道为什么这样有效。所以应该感谢kxr。