模块能像对象一样有属性吗?

134 投票
8 回答
41134 浏览
提问于 2025-04-15 11:41

通过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。

撰写回答