Le. CY
Le. CY

Reputation: 23

How to correctly extend variable __all__ in a __init__.py?

I'm confused when I tried write myself __init__.py after saw the code in numpy\__init__.py library.

Here is numpy\__init__.py code snippet

__all__.extend(['__version__', 'pkgload', 'PackageLoader',
           'show_config'])
__all__.extend(core.__all__)
__all__.extend(_mat.__all__)
__all__.extend(lib.__all__)
__all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma'])

And My directory structure is:

app/

......test.py

......lib1\

............ __init__.py

............ Lib1File.py

............ sublib1\

............ ............ __init__.py

............ ............ SubLib1File.py

The code in test.py is

from lib1 import *

if __name__ == "__main__":
    result1 = Lib1File.add(10, 15)    # a simple function in Lib1File.py
    print(result1)
    result2 = Sublib1File.mul(10,15)  # a simple function in Sublib1File.py
    print(result2)

The code in lib1\__init__.py is

from . import sublib1
__all__ = ["Lib1File"]
__all__.extend(sublib1.__all__)
print(__all__)                 # it can print ['Lib1File', 'Sublib1File'] on console

The code in lib1\sublib1\__init__.py is

__all__ = ["Sublib1File"]

But when I ran test.py, I got a error

*File "test.py", line 1, in module from lib1 import . AttributeError: module 'lib1' has no attribute 'Sublib1File'

My questions are

  1. Why I get this error even if __all__ = ['Lib1File', 'Sublib1File'] in lib1\__init__.py?

  2. How should I fix it if I still just use one import from lib1 import *?

  3. If we cannot solve question 2, what's the purpose of __all__.extend(...) in numpy\__init__?

Upvotes: 0

Views: 807

Answers (3)

user8651755
user8651755

Reputation:

If you take another look at numpy's top-level __init__ module you'll see that for each from . import xyz that's used to extend __all__ there's a corresponding from .xyz import *.

Adding a name to a module's __all__ is meaningless if the corresponding object isn't either defined in the module itself or imported from somewhere else. The __all__ statement doesn't import anything on it's own.

Add from .sublib1 import * below from . import sublib1 in lib1/__init__.py.

Also see: Can someone explain __all__ in Python?

Upvotes: 2

Le. CY
Le. CY

Reputation: 23

you are right @Wyatt, @MegaIng.

I post my answer here for the three questions, just in case others need it.

Q1. Why I get this error even if __all__ = ['Lib1File', 'Sublib1File'] in lib1__init__.py?

A1. Because you just add module name to __all__. But it actually does not have SublibFile module in lib1 directory. So python cannot find the definition of SublibFile module just by the module name.

Q2. How should I fix it if I still just use one import from lib1 import *?

A2. Add one line from .sublib1 import * in lib1/__init__.py. This will put modules that are defined in __all__ in lib1\sublib1\__init__.py to lib\ package so that python can find correspondence module definition by the module name.

Q3. What's the purpose of __all__.extend(...) in numpy\__init__?

A3. In order to extend __all__ flexibility.

Upvotes: 0

MegaIng
MegaIng

Reputation: 7886

Extending @wyatts answer, add the following line in lib1/__init__.py:

from .sublib1 import *

To make the example work.

Upvotes: 1

Related Questions