Pregunta

¿Para qué sirve __init__.py en un directorio fuente de Python?

¿Fue útil?

Solución

Solía ??ser una parte requerida de un paquete ( viejo, pre -3.3 " paquete normal " , no newer 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 archivo __init__.py . Cuando se importa un paquete normal, este archivo __init__.py se ejecuta implícitamente, y los objetos que define están vinculados a los nombres en el espacio de nombres del paquete. El archivo __init__.py 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 __init__.py .

Otros consejos

Los archivos llamados __init__.py se 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 mydir está en su camino, puede importar el código en module.py como

import spam.module

o

from spam import module

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

El archivo __init__.py 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

Además de etiquetar un directorio como un paquete de Python y definir __all__ , __init__.py le permite 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 adherencia al pitón '' plano es mejor que anidado '' filosofía.

Un ejemplo

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

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

Mi __init__.py contiene 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 defino Session aquí, puedo comenzar una nueva sesión usando la sintaxis a continuación. Este código sería el mismo ejecutado desde dentro o desde fuera de la "base de datos". directorio del paquete.

from database import Session
session = Session()

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

from database.create_session import Session
session = Session()

Lecturas adicionales

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

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

La opinión de la mayoría parece ser que los archivos __init__.py deben ser muy delgados para evitar violar el " explícito es mejor que implícito " filosofía.

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 conocer el archivo1, 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)
    

El archivo __init__.py 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.

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

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

  

Soporte nativo para directorios de paquetes que no requieren archivos de marcador __init__.py y 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/
¿No se requiere __init__.py para los paquetes en Python 3?

En Python la definición de paquete es muy simple. Al igual que Java, la estructura jerárquica y la estructura del directorio son las mismas. Pero debe tener __init__.py en un paquete. Explicaré el archivo __init__.py 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__.py puede 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

Después de ejecutar:

>>>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__.py en subPackage_b así:

__all__ = ['module_n2', 'module_n3']

Después de ejecutar:

>>>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, al usar * importar, el paquete del módulo está sujeto al contenido de __init__.py .

Aunque Python funciona sin un archivo __init__.py , 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 puede usar un archivo __init__.py :

Imagine que tiene la siguiente estructura de archivos:

main_methods 
    |- methods.py

Y method.py contenían esto:

def foo():
    return 'foo'

Para usar 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) mantener method.py dentro de main_methods (tiempos de ejecución / dependencias, por ejemplo) pero solo desea importar main_methods .


Si cambió el nombre de method.py a __init__.py , podría usar foo () simplemente importando main_methods :

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

Esto funciona porque __init__.py se trata como parte del paquete.


Algunos paquetes de Python realmente hacen esto. Un ejemplo es con JSON , donde ejecuta import json en realidad está importando __init__.py del paquete json ( vea la estructura del archivo del paquete aquí ):

  

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

__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 comentario de Alquimista de dos bits 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
>>> 

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

root\
    stuff\
         other.py

    morestuff\
         another.py

Sin este __init__.py dentro de las cosas 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 .

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

from b import a

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

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

from b import a
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top