2009-12-22 15 views
148

Mi paquete tiene la siguiente estructura:¿Cómo escribir buenos archivos correctos __init__.py/paquete

mobilescouter/ 
    __init__.py #1 
    mapper/ 
     __init__.py #2 
     lxml/ 
      __init__.py #3 
      vehiclemapper.py 
      vehiclefeaturemapper.py 
      vehiclefeaturesetmapper.py 
     ... 
     basemapper.py 
    vehicle/ 
     __init__.py #4 
     vehicle.py 
     vehiclefeature.py 
     vehiclefeaturemapper.py 
    ... 

No estoy seguro de cómo los archivos __init__.py estén escritas correctamente.
La __init__.py #1 parece:

__all__ = ['mapper', 'vehicle'] 
import mapper 
import vehicle 

Pero, ¿cómo, por ejemplo, __init__.py #2 parece? El mío es:

__all__ = ['basemapper', 'lxml'] 
from basemaper import * 
import lxml 

Cuando debe utilizarse __all__?

+0

Tenga en cuenta que el uso de la importación * en el código generalmente es una mala práctica y, si es posible, debe evitarse. Hay muy pocos casos de uso buenos para esto, pero son realmente raros. – Mayou36

Respuesta

116

__all__ es muy bueno - que ayuda declaraciones guía de importación sin necesidad de importar automáticamente los módulos http://docs.python.org/tutorial/modules.html#importing-from-a-package

utilizando __all__ y import * es redundante, solamente se necesita __all__

Creo que una de las razones más poderosas para utilizar en un import *__init__.py para importar paquetes es para poder refactorizar una secuencia de comandos que ha crecido en varias secuencias de comandos sin romper una aplicación existente. Pero si estás diseñando un paquete desde el principio. Creo que es mejor dejar __init__.py archivos vacíos.

por ejemplo:

foo.py - contains classes related to foo such as fooFactory, tallFoo, shortFoo 

entonces la aplicación crece y ahora es toda una carpeta

foo/ 
    __init__.py 
    foofactories.py 
    tallFoos.py 
    shortfoos.py 
    mediumfoos.py 
    santaslittlehelperfoo.py 
    superawsomefoo.py 
    anotherfoo.py 

entonces el guión de inicio puede decir

__all__ = ['foofactories', 'tallFoos', 'shortfoos', 'medumfoos', 
      'santaslittlehelperfoo', 'superawsomefoo', 'anotherfoo'] 
# deprecated to keep older scripts who import this from breaking 
from foo.foofactories import fooFactory 
from foo.tallfoos import tallFoo 
from foo.shortfoos import shortFoo 

de manera que un guión escrito a lo siguiente no se rompe durante el cambio:

from foo import fooFactory, tallFoo, shortFoo 
+2

Estaba muy confundido acerca de '__all__' y la importación de línea por línea. Su ejemplo es muy esclarecedor. – Junchen

98

Mis propios archivos __init__.py están vacíos la mayoría de las veces. En particular, nunca tengo un from blah import * como parte de __init__.py - si "importar el paquete" significa obtener todo tipo de clases, funciones, etc. definidas directamente como parte del paquete, entonces copiaré léxicamente el contenido de blah.py en el paquete __init__.py en su lugar y eliminar blah.py (la multiplicación de archivos fuente no sirve de nada aquí).

Si insiste en admitir las expresiones idiomáticas import * (eek), entonces usar __all__ (con una lista tan minúscula de nombres como puede tener) puede ayudar a controlar los daños. En general, los espacios de nombres y las importaciones explícitos son buenas cosas, y yo fuerte sugieren reconsiderar cualquier enfoque basado en sistemática pasar por uno o ambos conceptos -)

+9

Personalmente, prefiero mantener las cosas separadas, y luego importar *. La razón es que, a pesar de doblar y otras cosas, todavía odio buscar archivos que contengan demasiadas clases, incluso si están relacionadas. –

+4

@stefano piensa en un gran marco.si usa 'import *' debes aceptar incondicionalmente todo el framework en su totalidad, incluso las características que nunca usarás. mantener '__init __. py' empty te da más oportunidades que solo semánticas de todo o nada. pensar en retorcido. –

+0

si lo mantiene vacío, incluso después de importar mobilescouter, uno todavía no puede usar mobilescouter.mapper o mobilescouter.vehicle o mobilescouter.whatever. no es importar mobilescouter.A, mobilescouter.B ..... ¿demasiado detallado? – sunqiang

Cuestiones relacionadas