2010-04-27 6 views
67

En Python, si desea importar mediante programación un módulo, que puede hacer:¿Por qué __import__ de Python requiere de la lista?

module = __import__('module_name') 

Si desea importar un submódulo, se podría pensar que sería una simple cuestión de:

module = __import__('module_name.submodule') 

Por supuesto, esto no funciona; usted acaba de obtener module_name nuevamente. Tienes que hacer:

module = __import__('module_name.submodule', fromlist=['blah']) 

¿Por qué? El valor real de fromlist no parece importar en absoluto, siempre que no esté vacío. ¿De qué sirve pedir un argumento y luego ignorar sus valores?

La mayoría de las cosas en Python parecen estar hechas por una buena razón, pero por mi vida, no puedo encontrar ninguna explicación razonable para que este comportamiento exista.

Respuesta

116

De hecho, el comportamiento de __import__() se debe enteramente a la implementación de la declaración import, que llama al __import__(). Hay básicamente cinco maneras ligeramente diferentes __import__() se puede llamar import (con dos categorías principales):

import pkg 
import pkg.mod 
from pkg import mod, mod2 
from pkg.mod import func, func2 
from pkg.mod import submod 

En la primera y el segundo caso, el import declaración debe asignar el objeto módulo "más a la izquierda" a el nombre "más a la izquierda": pkg. Después de import pkg.mod puede hacer pkg.mod.func() porque la declaración import introdujo el nombre local pkg, que es un objeto de módulo que tiene un atributo mod. Por lo tanto, la función __import__() tiene que devolver el objeto del módulo "más a la izquierda" para que pueda asignarse a pkg. Por tanto, estas dos declaraciones de importación se traducen en:

pkg = __import__('pkg') 
pkg = __import__('pkg.mod') 

En el tercero, cuarto y quinto caso, la declaración import tiene que hacer más trabajo: tiene que asignar a (potencialmente) múltiples nombres, los cuales tiene que llegar desde el objeto del módulo La función __import__() solo puede devolver un objeto, y no hay una razón real para hacer que recupere cada uno de esos nombres del objeto del módulo (y la implementación sería mucho más complicada). Así que el enfoque simple sería algo así como (para el tercer caso):

tmp = __import__('pkg') 
mod = tmp.mod 
mod2 = tmp.mod2 

sin embargo, eso no funcionará si pkg es un paquete y mod o mod2 son módulos en ese paquete que no están ya importada, ya que están en el tercer y quinto caso. La función __import__() necesita saber que mod y mod2 son nombres a los que la declaración import querrá tener acceso, para que pueda ver si son módulos e intentar importarlos también.Así que la llamada está más cerca de:

tmp = __import__('pkg', fromlist=['mod', 'mod2']) 
mod = tmp.mod 
mod2 = tmp.mod2 

que provoca __import__() para tratar de carga pkg.mod y pkg.mod2, así como pkg (pero si no existen mod o mod2, no es un error en la llamada __import__(); producir una de error se deja a la declaración import) pero que todavía no es lo correcto para el cuarto y quinto ejemplo, porque si la llamada fuera así:.

tmp = __import__('pkg.mod', fromlist=['submod']) 
submod = tmp.submod 

continuación tmp terminaría siendo pkg, como antes, y no el módulo pkg.mod del que desea obtener el atributo submod. La implementación podría haber decidido hacerlo para que la declaración import haga un trabajo extra, dividiendo el nombre del paquete en . como lo hace la función __import__() y recorriendo los nombres, pero esto habría significado duplicar parte del esfuerzo. Así que, en cambio, la aplicación hace __import__() retorno del derecho más - módulo en lugar de la más a la izquierda uno si y sólo si fromlist se pasa y no está vacío.

(El import pkg as p y from pkg import mod as m sintaxis no cambia nada de esta historia, excepto la que los nombres locales se asignan a - la función __import__() ve nada diferente cuando se utiliza as, todo permanece en la aplicación import comunicado.)

2

La respuesta se puede encontrar en la documentación para __import__:

El fromlist debe ser una lista de nombres de emular from name import ..., o una lista vacía para emular import name.

Al importar un módulo de un paquete, tenga en cuenta que __import__('A.B', ...) devuelve el paquete A cuando fromlist está vacía, pero su submódulo B cuando fromlist no está vacía.

Así que, básicamente, eso es sólo la forma en la implementación de __import__ obras: si desea que el submódulo, se pasa un fromlist que contiene algo que desea importar desde el submódulo, y la puesta en práctica si __import__ es tal que se devuelve el submódulo .

una explicación más detallada

creo que existen la semántica de manera que se devuelve el módulo más relevante. En otras palabras, supongamos que tengo un paquete foo que contiene el módulo bar con la función baz. Si yo:

import foo.bar 

Entonces me refiero a baz como

foo.bar.baz() 

Esto es como __import__("foo.bar", fromlist=[]).

Si en lugar importo con:

from foo import bar 

Entonces se refieren a baz como bar.baz()

que sería similar a __imoort__("foo.bar", fromlist=["something"]).

Si hago:

from foo.bar import baz 

Entonces se refieren a baz como

baz() 

que es como __import__("foo.bar", fromlist=["baz"]).

Así que en el primer caso, tendría que usar el nombre completo, por lo tanto __import__ devuelve el primer nombre de módulo que utilizaría para referirse a los elementos importados, que es foo. En el último caso, bar es el módulo más específico que contiene los elementos importados, por lo que tiene sentido que __import__ devuelva el módulo foo.bar.

El segundo caso es un poco extraño, pero supongo que fue escrito de esa manera para admitir la importación de un módulo usando la sintaxis from <package> import <module>, y en ese caso bar sigue siendo el módulo más específico para devolver.

+0

Decir "así es como funciona la implementación" no responde mi pregunta. ¿Por qué funciona de esa manera? Diciendo que "emular la importación desde el nombre ..." está más cerca, ¿pero bajo qué circunstancias lo necesitarías? La lista de salida no hace una pizca de diferencia de cómo __import__ realmente funciona, por lo que no veo dónde hay un caso donde tendría que pasarlo para emular cualquier cosa, excepto cuál debería ser el comportamiento obvio de la función. – ieure

+1

Tienes razón, me hace la pregunta. Actualicé mi respuesta para dar una respuesta más relevante. – mipadi

4

Todavía me siento raro cuando leo la respuesta, así que probé los ejemplos de código a continuación.

En primer lugar, tratar de construir la estructura de archivos a continuación:

tmpdir 
    |A 
    |__init__.py 
    | B.py 
    | C.py 

Ahora A es un package, y B o C es un module. Así que cuando tratamos algo de código como estos en ipython:

En segundo lugar, ejecute el código de ejemplo en ipython:

In [2]: kk = __import__('A',fromlist=['B']) 

    In [3]: dir(kk) 
    Out[3]: 
    ['B', 
    '__builtins__', 
    '__doc__', 
    '__file__', 
    '__name__', 
    '__package__', 
    '__path__'] 

Parece que el fromlist funciona como esperábamos. Pero las cosas se conectan cuando tratamos de hacer las mismas cosas en un module. Supongamos que tenemos un módulo llamado C.py y código en él:

handlers = {} 

    def hello(): 
     print "hello" 

    test_list = [] 

Así que ahora tratamos de hacer lo mismo en él.

In [1]: ls 
    C.py 

    In [2]: kk = __import__('C') 

    In [3]: dir(kk) 
    Out[3]: 
    ['__builtins__', 
    '__doc__', 
    '__file__', 
    '__name__', 
    '__package__', 
    'handlers', 
    'hello', 
    'test_list'] 

Entonces, cuando solo queremos importar el test_list, ¿funciona?

In [1]: kk = __import__('C',fromlist=['test_list']) 

    In [2]: dir(kk) 
    Out[2]: 
    ['__builtins__', 
    '__doc__', 
    '__file__', 
    '__name__', 
    '__package__', 
    'handlers', 
    'hello', 
    'test_list'] 

Como muestra el resultado, cuando tratamos de utilizar fromlist en un module en lugar de un package, el parámetro fromlist no ayuda en absoluto, porque module ha sido recopilada. Una vez que se importa, no hay forma de ignorar a los demás.

Cuestiones relacionadas