¿Para qué sirve __init__.py?

Respuestas:

1456

Solía ​​ser una parte requerida de un paquete ( antiguo "paquete regular" anterior a 3.3 , no más nuevo 3.3+ "paquete de espacio de nombres" ).

Aquí está la documentación.

Python define dos tipos de paquetes, paquetes regulares y paquetes de espacio de nombres. Los paquetes regulares son paquetes tradicionales tal como existían en Python 3.2 y versiones anteriores. Un paquete normal generalmente se implementa como un directorio que contiene un __init__.pyarchivo. Cuando se importa un paquete normal, este __init__.pyarchivo se ejecuta implícitamente y los objetos que define están vinculados a nombres en el espacio de nombres del paquete. El __init__.pyarchivo puede contener el mismo código de Python que cualquier otro módulo puede contener, y Python agregará algunos atributos adicionales al módulo cuando se importe.

Pero solo haga clic en el enlace, contiene un ejemplo, más información y una explicación de los paquetes de espacios de nombres, el tipo de paquetes sin ellos __init__.py.

Loki
fuente
187
¿Qué significa esto: "esto se hace para evitar que directorios con un nombre común, como cadena, oculten involuntariamente módulos válidos que se producen más adelante en la ruta de búsqueda de módulos"?
Carl G
97
@CarlG Python busca en una lista de directorios para resolver nombres en, por ejemplo, declaraciones de importación. Debido a que estos pueden ser cualquier directorio, y el usuario final puede agregar otros arbitrarios, los desarrolladores tienen que preocuparse por los directorios que comparten un nombre con un módulo válido de Python, como 'string' en el ejemplo de documentación. Para aliviar esto, ignora los directorios que no contienen un archivo llamado _ _ init _ _.py (sin espacios), incluso si está en blanco.
Two-Bit Alchemist
186
@CarlG Prueba esto. Haga un directorio llamado 'datetime' y en él haga dos archivos en blanco, el archivo init.py (con guiones bajos) y datetime.py. Ahora abra un intérprete, importe sys y emita sys.path.insert(0, '/path/to/datetime'), reemplazando esa ruta con la ruta al directorio que acaba de crear. Ahora intenta algo como from datetime import datetime;datetime.now(). Debería obtener un AttributeError (porque ahora está importando su archivo en blanco). Si repitiera estos pasos sin crear el archivo de inicio en blanco, esto no sucedería. Eso es lo que se pretende prevenir.
Two-Bit Alchemist
44
@ DarekNędza Tienes algo configurado incorrectamente si no puedes abrir un intérprete de Python y emitir from datetime import datetimesin error. ¡Eso es bueno desde la versión 2.3!
Alquimista de dos bits
55
@SWang: Eso es incorrecto: builtinsenumera funciones y clases integradas, no módulos integrados (cf. docs.python.org/3/tutorial/modules.html#the-dir-function ). Si desea enumerar los módulos integrados , haga import sys; print(sys.builtin_module_names)(cf. docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Maggyero
844

Los archivos nombrados __init__.pyse usan para marcar directorios en el disco como directorios de paquetes Python. Si tienes los archivos

mydir/spam/__init__.py
mydir/spam/module.py

y mydirestá en su camino, puede importar el código module.pycomo

import spam.module

o

from spam import module

Si elimina el __init__.pyarchivo, Python ya no buscará submódulos dentro de ese directorio, por lo que los intentos de importar el módulo fallarán.

El __init__.pyarchivo generalmente está vacío, pero se puede usar para exportar partes seleccionadas del paquete con un nombre más conveniente, mantener funciones convenientes, etc. Dado el ejemplo anterior, se puede acceder al contenido del módulo init como

import spam

basado en esto

caritos
fuente
96
Actualización: el archivo __init__.pyse requería en Python 2.X y todavía se requiere en Python 2.7.12 (lo probé) pero ya no se requiere (supuestamente) en Python 3.3 en adelante, y no se requiere en Python 3.4.3 (I probado) Consulte stackoverflow.com/questions/37139786 para más detalles.
Rob_before_edits
44
No lo uses Es un paquete de "espacio de nombres", no un paquete normal. El paquete de espacio de nombres se utiliza para casos de uso muy raros. Es posible que no necesite saber cuándo usarlo. Solo úsalo __init__.py.
metano
2
sin embargo, si tiene setup.pyy usa find_packages(), es necesario tenerlo __init__.pyen cada directorio. Ver stackoverflow.com/a/56277323/7127824
techkuz
484

Además de etiquetar un directorio como un paquete de Python y definirlo __all__, le __init__.pypermite definir cualquier variable a nivel de paquete. Hacerlo suele ser conveniente si un paquete define algo que se importará con frecuencia, de forma similar a la API. Este patrón promueve la adhesión a la filosofía pitónica "plano es mejor que anidado".

Un ejemplo

Aquí hay un ejemplo de uno de mis proyectos, en el que frecuentemente importo un sessionmakerllamado Sessionpara interactuar con mi base de datos. Escribí un paquete de "base de datos" con algunos módulos:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

Mi __init__.pycontiene el siguiente código:

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Como lo defino Sessionaquí, puedo comenzar una nueva sesión usando la sintaxis a continuación. Este código sería el mismo ejecutado desde dentro o fuera del directorio del paquete "base de datos".

from database import Session
session = Session()

Por supuesto, esto es una pequeña conveniencia: la alternativa sería definir Sessionen un nuevo archivo como "create_session.py" en mi paquete de base de datos, y comenzar nuevas sesiones usando:

from database.create_session import Session
session = Session()

Otras lecturas

Hay un hilo de reddit bastante interesante que cubre los usos apropiados de __init__.pyaquí:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

La opinión mayoritaria parece ser que los __init__.pyarchivos deben ser muy delgados para evitar violar la filosofía "explícito es mejor que implícito".

Nathan Gould
fuente
3
engine, sessionmaker, create_engine, Y ostodos pueden también ser importados de databaseahora ... parece que usted ha hecho un lío de ese espacio de nombres.
ArtOfWarfare
99
@ArtOfWarfare, puede usar __all__ = [...]para limitar lo que se importa con import *. Pero aparte de eso, sí, te queda un espacio de nombres de alto nivel desordenado.
Nathan Gould
¿Puedo saber qué es la 'URL DE BASE DE DATOS'? Traté de replicar esto encerrando create_engine con 'mysql + mysqldb: // root: python @ localhost: 3306 / test' pero no funciona. Gracias.
SunnyBoiz
2
¿Cómo accedería a la clase 'Sesión' definida en init desde el interior del paquete, por ejemplo, quieries.py?
vldbnc
253

Hay 2 razones principales para __init__.py

  1. Por conveniencia: los otros usuarios no necesitarán conocer la ubicación exacta de sus funciones en la jerarquía de su paquete.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    # in file1.py
    def add():
        pass

    entonces otros pueden llamar a add () por

    from your_package import add

    sin saber file1, como

    from your_package.file1 import add
  2. Si quieres que algo se inicialice; por ejemplo, el registro (que debe colocarse en el nivel superior):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
flycee
fuente
77
oh, antes de leer su respuesta, pensé que llamar a una función explícitamente desde su ubicación es una buena práctica.
Aerin
2
@Aerin sería mejor no considerar que las declaraciones cortas (o, en este caso, las conclusiones subjetivas) sean siempre ciertas. Importar desde __init__.pypuede ser útil a veces, pero no siempre.
Tobias Sette
2
¿Se ejecuta este código en el momento de la importación o en tiempo de ejecución?
user1559897
111

El __init__.pyarchivo hace que Python trate los directorios que lo contienen como módulos.

Además, este es el primer archivo que se carga en un módulo, por lo que puede usarlo para ejecutar el código que desea ejecutar cada vez que se carga un módulo, o especificar los submódulos que se exportarán.

Can Berk Güder
fuente
89

Desde Python 3.3, __init__.py ya no es necesario definir directorios como paquetes Python importables.

Consulte PEP 420: Paquetes de espacio de nombres implícitos :

Soporte nativo para directorios de paquetes que no requieren __init__.pyarchivos de marcadores y que pueden abarcar automáticamente múltiples segmentos de ruta (inspirados en varios enfoques de terceros para paquetes de espacios de nombres, como se describe en PEP 420 )

Aquí está la prueba:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

referencias:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__. ¿Py no se requiere para paquetes en Python 3?

zeekvfu
fuente
3
Es el paquete "espacio de nombres". No lo use para el paquete regular.
metano
@methan, ¿podrías explicar tu comentario?
Robert Lugg
3
@RobertLugg Ver dev.to/methane/don-t-omit-init-py-3hga
metano
57

En Python la definición de paquete es muy simple. Al igual que Java, la estructura jerárquica y la estructura de directorios son las mismas. Pero tienes que tenerlo __init__.pyen un paquete. Explicaré el __init__.pyarchivo con el siguiente ejemplo:

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.pypuede estar vacío, siempre que exista. Indica que el directorio debe considerarse como un paquete. Por supuesto,__init__.py también puede establecer el contenido apropiado.

Si agregamos una función en module_n1:

def function_X():
    print "function_X in module_n1"
    return

Despues de correr:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

Luego seguimos el paquete de jerarquía y llamamos a module_n1 la función. Podemos usar __init__.pyen subPackage_b así:

__all__ = ['module_n2', 'module_n3']

Despues de correr:

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

Por lo tanto, usando * importing, el paquete del módulo está sujeto a __init__.pycontenido.

Marcus Thornton
fuente
¿Cómo se verá mi setup.py para hacer la misma importación a través de la biblioteca empaquetada? from package_x.subPackage_b.module_n1 import function_X
technazi
así que la clave aquí es "usar * importar, el paquete del módulo está sujeto al contenido init .py"
Minnie
54

Aunque Python funciona sin un __init__.pyarchivo, aún debe incluir uno.

Especifica que un paquete debe tratarse como un módulo, por lo tanto, inclúyalo (incluso si está vacío).

También hay un caso en el que realmente puedes usar un __init__.pyarchivo:

Imagine que tiene la siguiente estructura de archivos:

main_methods 
    |- methods.py

Y methods.pycontenía esto:

def foo():
    return 'foo'

Para usarlo foo()necesitaría uno de los siguientes:

from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()

Tal vez allí necesite (o desee) mantenerse methods.pydentro main_methods(tiempos de ejecución / dependencias, por ejemplo), pero solo desea importar main_methods.


Si cambiaste el nombre de methods.pya __init__.py, podrías usarlo foo()simplemente importando main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'

Esto funciona porque __init__.pyse trata como parte del paquete.


Algunos paquetes de Python realmente hacen esto. Un ejemplo es con JSON , donde ejecutar import jsones importar __init__.pydesde el jsonpaquete ( vea la estructura del archivo del paquete aquí ):

Código fuente: Lib/json/__init__.py

Simón
fuente
39

__init__.py tratará el directorio en el que se encuentra como un módulo cargable.

Para las personas que prefieren leer el código, pongo el comentario de Two-Bit Alchemist aquí.

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 
B.Mr.W.
fuente
30

Facilita la importación de otros archivos de Python. Cuando colocaste este archivo en un directorio (digamos cosas) que contiene otros archivos py, entonces puedes hacer algo como importar cosas.otras.

root\
    stuff\
         other.py

    morestuff\
         another.py

Sin esto __init__.pydentro del directorio, no podría importar other.py, porque Python no sabe dónde está el código fuente de las cosas y no puede reconocerlo como un paquete.

Epitafio
fuente
2
Tengo la misma estructura en mi proyecto (python 3.4) pero no puedo hacer que otro.py vea otro.py. ¿Como debo hacer la importación? desde root.stuff importar otro? Funciona en modo de depuración VSCode pero no en línea de comando. ¿Algunas ideas?
rodrigorf
10

Un __init__.pyarchivo facilita las importaciones. Cuando un __init__.pyestá presente dentro de un paquete, la función a()se puede importar desde un archivo de esta b.pymanera:

from b import a

Sin él, sin embargo, no puede importar directamente. Tienes que modificar la ruta del sistema:

import sys
sys.path.insert(0, 'path/to/b.py')

from b import a
Alec Alameddine
fuente
¿Qué quiere decir que "la función a () se puede importar desde el archivo b.py [fragmento] Sin ella, sin embargo, no se puede importar directamente "? Puedo importar la función a () del archivo b.py sin __init__.py.
aderchox