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__
.
>>> mymodule.__dict__
{...}
>>> "foo" in mymodule.__dict__
True
>>> "something" in mymodule.__dict__
False
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.