Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is __all__ in __init__.py, needed when accessing class or method?

Tags:

python

Googling around, I read many answers explaining that __all__ is for 'from some.package.name import *' , restricting importable modules to only ones inside it.

I'm absolutely sure it's true, if I want to import all the modules using wildcard from packages. But my question is about when I want to import some lower level objects like class, functions than modules, from package directly, the __all__ seems useless because to directly access the class from packages, it's the only way to import class from modules under the package into the __init__ file.

Here's example While doing some Django jobs, I recognized that Django-contributors really enjoy using __all__in the __init__.py files.

For example, in the basic Django package, models, __init__ files go like this.

django.db.model.__init__.py

---skipped---

from django.db.models.base import DEFERRED, Model  #

---skipped---

__all__ = aggregates_all + constraints_all + fields_all + indexes_all
__all__ += [
    '---skipped---'
    'Prefetch', 'Q', 'QuerySet', 'prefetch_related_objects', 'DEFERRED', 'Model',
]

You can see that here, 'Model' is definitely included __all__ ,but problem here is it's already imported upper lines, so if you don't include 'Model' in __all__, you can import it with from statement from django.db.models import *.

So I concluded that, in this case __all__ is redundant or needless, and that the purpose of writing 'Model' despite its redundancy is that for readability.

Do you think it's the right conclusion?

like image 487
Now.Zero Avatar asked Dec 08 '25 08:12

Now.Zero


1 Answers

The tutorial about modules explains that __all__ is actually used to restrict what is imported when you use import *.

If __all__ is defined then when you import * from your package, only the names defined in __all__ are imported in the current namespace.

So it can be redundant, but only if you put in __all__ everything you import and define in your package.

Minimal working example:

testing/__init__.py:

from .moda import A
from .modb import B

__all__ = ['A']

testing/moda.py:

class A:
    pass

testing/modb.py:

class B:
    pass

Then when I import * from testing, I've got only A imported in current namespace, not B:

>>> from testing import *
>>> dir()
['A', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>> 'B' in dir()
False
>>> 'A' in dir()
True
like image 157
rolf82 Avatar answered Dec 10 '25 20:12

rolf82



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!