Can modules have properties the same way that objects can? Ask Question

Can modules have properties the same way that objects can? Ask Question

With python properties, I can make it such that

obj.y 

calls a function rather than just returning a value.

Is there a way to do this with modules? I have a case where I want

module.y 

to call a function, rather than just returning the value stored there.

ベストアンサー1

As PEP 562 has been implemented in Python >= 3.7, now we can do this

file: module.py

def __getattr__(name):
    if name == 'y':
        return 3
    raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

other = 4

demo:

>>> 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'

Note that if you omit the raise AttributeError in the __getattr__ function, it means the function ends with return None, then the module.nosuch will get a value of None.

EDIT

My answer cannot have setters and deleters. If you need, adopt kxr's answer.

Create a subclass of <class 'module'>, define properties in that class, then change module class into that class.

file: 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

demo:

>>> import mymodule
>>> mymodule.y
3
>>> mymodule.other
4
>>> mymodule.y = 5
>>> mymodule.y
5
>>> mymodule._y
5    # to prove that setter works

I am too novice to know why it works. So the credit should go to kxr.

おすすめ記事