¿No se requiere __init__.py para los paquetes en Python 3.3+


195

Estoy usando Python 3.5.1. Leí el documento y la sección del paquete aquí: https://docs.python.org/3/tutorial/modules.html#packages

Ahora, tengo la siguiente estructura:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

Ahora, mientras que en /home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

Del mismo modo, ahora en casa, supercarpeta de Playground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

En realidad, puedo hacer todo tipo de cosas:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

¿Por qué funciona esto? Pensé que tenía que haber __init__.pyarchivos (los vacíos funcionarían) en ambos ay bpara module.pypoder ser importados cuando la ruta de Python apunta a la Playgroundcarpeta.

Esto parece haber cambiado desde Python 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

Con __init__.pyen ambos ~/Playground/ay ~/Playground/a/bfunciona bien.

Respuestas:


192

Python 3.3+ tiene paquetes de espacio de nombres implícitos que le permiten crear paquetes sin un __init__.pyarchivo.

Permitir paquetes de espacio de nombres implícitos significa que el requisito de proporcionar un __init__.pyarchivo puede eliminarse por completo y verse afectado ....

La antigua manera con __init__.pyarchivos todavía funciona como en Python 2.


10
Leeré el documento, pero es un poco largo. ¿Es posible resumir rápidamente? ¿Podría decirme: todavía es compatible con init .py, o los ignora por completo? Si los admite, ¿cuál es la diferencia en la funcionalidad y por qué esta dualidad?
wujek

3
Entonces el tutorial probablemente debería actualizarse. ¿Se ha abierto un error de documentación?
Michel Samia

44
Todavía estoy molesto porque esto desafía la Zen Of Python línea 2: Explicit is better than implicit.....
JayRizzo

55
@JayRizzo Pero: "Aunque la practicidad supera la pureza".
Mike Müller

19
@JayRizzo IMO es aún más explícito. A veces sucede hacer cosas de inicio __init__.py, a veces no. En Python 3, cuando necesito estas cosas, creo una nueva __init__.pycon código específico, de lo contrario no lo hago. Esto resulta útil para saber, visualmente, qué paquetes tienen un inicio personalizado. En cambio, en Python 2 siempre tengo que colocar un __init__.py(a menudo vacío), haciendo un gran número de ellos y, finalmente, más difícil de recordar dónde colocó su código de inicio. Esto también debería encajar "Debe haber una, y preferiblemente solo una, forma obvia de hacerlo".
Paolo

148

IMPORTANTE

La respuesta de @ Mike es correcta pero demasiado imprecisa. Es cierto que Python 3.3+ admite paquetes de espacio de nombres implícitos que le permite crear un paquete sin un __init__.pyarchivo.

Sin embargo, esto SOLO se aplica a los archivos VACÍOS__init__.py . Por lo tanto, los archivos VACÍOS__init__.py ya no son necesarios y pueden omitirse. Si desea ejecutar un script de inicialización particular cuando se importa el paquete o cualquiera de sus módulos o subpaquetes, aún necesita un __init__.pyarchivo. Esta es una excelente respuesta de Stack Overflow para __init__.pysaber por qué desea utilizar un archivo para realizar una inicialización adicional en caso de que se pregunte por qué esto es de alguna manera útil.

Ejemplo de estructura de directorio:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

EJEMPLOS

Los siguientes ejemplos demuestran cómo se ejecuta el script de inicialización cuando child_packagese importa uno o sus módulos.

Ejemplo 1 :

from parent_package import child_package  # prints "from parent"

Ejemplo 2 :

from parent_package.child_package import child1  # prints "from parent"

2
Supongamos que tengo run_script.pyen el mismo directorio, parent_packageasí que ¿puedo importar como from parent_package.child_package import child1sin __init__.py?
mrgloom

¿Es el propósito de esto para que pueda escribir child_package.some_function incluso si alguna_función está definida en childX.py? En otras palabras, ¿evita que el usuario sepa sobre los diferentes archivos en child_package? ?
johnbakers

Sí, no entiendo por qué lo harías child1.py, en child2.pylugar de simplemente poner su código en __init__.py directamente.
binki

¿No deberían ser las declaraciones de importación en __init__importaciones relativas, es decir from . import child1? La importación absoluta me da ModuleNotFoundError(en Python 3.6)
Halbeard

55
En mi experiencia, incluso con Python 3.3+, __init__.pytodavía se necesita un vacío a veces, como cuando quieres referir una subcarpeta como un paquete. Por ejemplo, si lo ejecuto python -m test.foono funcionará hasta que haya creado un vacío __init__.pydebajo de la carpeta de prueba. ¡Y estoy hablando de la versión 3.6.6 aquí!
Prahlad Yeri

7

Si tiene setup.pyen su proyecto y lo usa find_packages()dentro de él, es necesario tener un __init__.pyarchivo en cada directorio para que los paquetes se encuentren automáticamente.

Los paquetes solo se reconocen si incluyen un __init__.pyarchivo

UPD : si desea usar paquetes de espacio de nombres implícitos sin __init__.pytener que usarlos find_namespace_packages()en su lugar

Docs


2

Yo diría que uno debería omitir el __init__.pyúnico si quiere tener el paquete de espacio de nombres implícito . Si no sabe lo que significa, probablemente no lo quiera y, por lo tanto, debe continuar utilizando el __init__.pypar en Python 3.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.