Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to check if a Python module with a custom __getattr__ has a given attribute?

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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__?

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading