I implemented a custom __getattr__ on a module that retrieves a value and caches it with setattr. Here is the simplified version:
# mymodule.py
import sys
__this = sys.modules[__name__]
def __getattr__(name: str):
print(f"Generating {name}")
value = "some value"
setattr(__this, name, value)
return value
This works fine:
>>> import mymodule
>>> mymodule.foo
Generating foo
'some value'
>>> mymodule.bar
Generating bar
'some value'
>>> mymodule.bar
'some value'
Note how __getattr__ is called only on attributes that don’t already exist on the module. How can I identify these attributes? Python obviously knows about them, but I can’t get that information.
hasattr doesn’t work, because under the hood it calls getattr which calls my function:
>>> hasattr(mymodule, "foo")
True
>>> hasattr(mymodule, "something")
Generating something
True
"foo" in dir(mymodule) works, but it requires to enumerate all attributes with dir() to test for a single one. One can delete attributes with del mymodule.foo, so keeping track of them in __getattr__ using a global set doesn’t work (and having a custom __delattr__ is not supported yet).
How can I test if "something" is an attribute of mymodule without calling mymodule.__getattr__?
Modules are objects in Python, and just like most objects, they have a
__dict__.Keep in mind that
__dict__also contains certain things that you don't explicitly define, like__name__and__doc__(which exist on all modules). Though attempting to access these would not invoke your__getattr__anyway, so it's consistent with the behavior you're looking for.