1

I'm trying to run some logic when objects are imported from a module by using __getattr__ as described here: __getattr__ on a module

...but the logic runs twice. Why is that happening and how can I stop it?

enter image description here

main.py

from test import x, y

test.py

def __getattr__(name: str):
    print(f"Imported {name}")
pyjamas
  • 4,608
  • 5
  • 38
  • 70
  • Please post your code and output as text, not a screenshot. – Barmar Mar 30 '21 at 01:15
  • 1
    Have you tried checking the traceback during the calls? – o11c Mar 30 '21 at 01:32
  • 1
    @o11c there's no traceback, since the code executes successfully. Running python in verbose mode doesn't reveal any information when I reproduce this locally. Checking the cProfile shows 5 calls to `test.__getattr__`: `5 0.000 0.000 0.000 0.000 test.py:1(__getattr__)` – C.Nivs Mar 30 '21 at 01:37
  • 2
    @C.Nivs The dupe shows how to check the traceback. – wim Mar 30 '21 at 02:23

1 Answers1

1

Your __getattr__ returns None for all attributes, including __path__, and if a module has a __path__ attribute, it's treated as a package.

For a package, from test import x, y needs to handle possible submodules named test.x and test.y. The code that does this handling uses hasattr first, to test whether test already has x and y attributes:

elif not hasattr(module, x):
    ...

and that hasattr is responsible for the first __getattr__('x') and __getattr__('y') calls.

The second __getattr__('x') and __getattr__('y') calls are just the ones you'd expect to happen, to retrieve test.x and test.y for the import.


Your __getattr__ shouldn't return a value for special attributes like __path__.

Also, unrelated, naming a module test is a bad idea, because the standard library already claimed that name for Python's own test suite.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • "Your __getattr__ returns None for all attributes, including __path__" is there any way for me to prevent this? I still want to make my logic only run once, but I'm not sure how to make `hasattr` return `False` for `__path__` here – pyjamas Mar 30 '21 at 15:53
  • Nevermind, just had to add `raise AttributeError` in the case that `name=='__path__'` – pyjamas Mar 30 '21 at 16:03