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.