Python Forum
Do packages really require "__init__.py" ?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Do packages really require "__init__.py" ?
#1
Hello,

In the official documentation for Python 3 it is written that :

Quote:The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.

However, when a create a package without the presence of the file "__init__.py", it "works". I means that Python knows that it is a package even if the file "__init__.py" does not exist.

Demonstration:

Let's consider the following file tree:

├── package
│   ├── __init__.py
│   ├── module1.py
│   ├── module2.py
│   └── module3.py
└── test1.py


And let's consider the following code (the content of the file test1.py):

import os
import sys
from pprint import pformat

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

import package
print('What is a package ? %s' %pformat(package))
print('Do packages have a property called "__path__" ? %s' %('yes' if hasattr(package, '__path__') else 'no'))
print('package.__path__ = %s' %package.__path__)
print('')

from package import module1
print('What is a module ? %s' %pformat(module1))
print('Do modules have a property called "__path__" ? %s' %('yes' if hasattr(module1, '__path__') else 'no'))
print('')
Now run the script test1.py:

With the file "package/__init__.py":

Output:
$ ls package/__init__.py && python3 test1.py package/__init__.py What is a package ? <module 'package' from '/home/denis/projects/imap/package_vs_module/package/__init__.py'> Do packages have a property called "__path__" ? yes package.__path__ = ['/home/denis/projects/imap/package_vs_module/package'] What is a module ? <module 'package.module1' from '/home/denis/projects/imap/package_vs_module/package/module1.py'> Do modules have a property called "__path__" ? no
And without the file "package/__init__.py":

Output:
$ rm -f package/__init__.py && rm -rf package/__pycache__ && python3 test1.py What is a package ? <module 'package' (namespace)> Do packages have a property called "__path__" ? yes package.__path__ = _NamespacePath(['/home/denis/projects/imap/package_vs_module/package', '/home/denis/projects/imap/package_vs_module/package']) What is a module ? <module 'package.module1' from '/home/denis/projects/imap/package_vs_module/package/module1.py'> Do modules have a property called "__path__" ? no
Conclusion:

Python recognises "package" as being a package event without the presence of the file "__init__.py".

Do I misunderstand something ?

Thanks,

Denis
Reply
#2
I means that Python knows that it is a package even if the file "__init__.py" does not exist.
Sooner or later you will run into an issue where an import cannot be located, and your software will fail.
You can wait for that to happen, or buy some insurance by creating the __init__.py files.
Personally, I always create them.
Reply
#3
(Feb-14-2019, 04:19 PM)denis_beurive Wrote: Python recognises "package" as being a package event without the presence of the file "__init__.py".

Do I misunderstand something ?
No,from Python 3.3+ supports Implicit Namespace Packages that allows to create a package without an __init__.py file.
This however only applies to empty __init__.py files.
So empty __init__.py files are no longer necessary and can be omitted.

To give a example,i always have one __init__.py that has content to lift sub modules,
this to avoid long import statement and make it easier for users of package.
my_pack\
|-- __init__.py
  color\
  |-- base_color.py
    gradient\    
    |-- gradient.py
__init__.py
from .color import base_color
from .color.gradient import gradient
base_color.py
def red():
    return 'rgb(255, 0, 0)'
gradient.py
def hsl_value():
    return 'rgba(255, 100, 50, 1.0)'
As i have lifted with __init__.py there is no need to say color.gradient.hsl_value() when import.
Usage:
λ ptpython
>>> from my_pack import base_color, gradient

>>> base_color.red()
'rgb(255, 0, 0)'


>>> gradient.hsl_value()
'rgba(255, 100, 50, 1.0)'
And stop using very old %s string formatting.
>>> for word in 'f-strings are awesome'.split():
...     print(f'{word.upper():~^20}')
~~~~~F-STRINGS~~~~~~
~~~~~~~~ARE~~~~~~~~~
~~~~~~AWESOME~~~~~~~

>>> # f-strings support any Python expressions inside the curly braces
>>> name = 'f-string'
>>> print(f"My cool string is called {name.upper()}.")
My cool string is called F-STRING.
 
>>> a, b = 5, 7
>>> f'{a}/{b} = {a/b:.2}'
'5/7 = 0.71'
Reply
#4
(Feb-15-2019, 03:59 AM)snippsat Wrote: snippsat

Thank you for your response. It's clear.

Denis
Reply
#5
Python 3.7.2, Eclipse IDE 2018‑12, Kubuntu 18.10 x64

If I use in Database/Tables/__init__.py line of code:
__all__ = ["Career", "Videos"]
, then in other packages this code:
from Database.Tables import Career
causes an error:
Error:
module Database.Tables has no attribute 'Career'
But if I comment line
#__all__ = ["Career", "Videos"]
this error dissapear.

Why?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Why doesn't list require global keyword? johnywhy 9 646 Jan-15-2024, 11:47 PM
Last Post: sgrey
  Pattern Require Last Line Print() why? Harshil 4 2,373 Aug-08-2020, 04:54 PM
Last Post: Harshil
  Require Some Suggestions gouravlal 2 1,856 Jul-27-2020, 06:14 AM
Last Post: gouravlal
  Do you require imports used in other files? Panda 1 2,472 Jul-14-2018, 02:30 PM
Last Post: gontajones
  Why does function print require bracket for text? richardm55 2 2,915 May-23-2018, 07:30 PM
Last Post: buran
  I Require some help for project idea...FaceRecognizer Door actived JavierGTZ 0 2,466 Aug-18-2017, 04:45 PM
Last Post: JavierGTZ
  Why is there an __init__ statement within the __init__ definition iFunKtion 7 5,962 Feb-06-2017, 07:31 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020