top modules from beyond attempted __all__ python python-import

from - python modules list



¿Por qué__import__ de Python requiere de la lista? (3)

En Python, si desea importar un módulo mediante programación, puede hacer:

module = __import__(''module_name'')

Si quiere importar un submódulo, 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. Tu 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.


De hecho, el comportamiento de __import__() se debe enteramente a la implementación de la declaración de import , que llama a __import__() . Básicamente hay cinco formas diferentes de __import__() por 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 el primer y el segundo caso, la declaración de import debe asignar el objeto del módulo "más a la izquierda" al nombre "más a la izquierda": pkg . Después de import pkg.mod puede hacer pkg.mod.func() porque la instrucción de import introdujo el nombre local pkg , que es un objeto de módulo que tiene un atributo de mod . Entonces, la función __import__() tiene que devolver el objeto del módulo "más a la izquierda" para que pueda asignarse a pkg . Esas dos declaraciones de importación se traducen en:

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

En el tercer, cuarto y quinto caso, la declaración de import tiene que hacer más trabajo: tiene que asignar a (potencialmente) múltiples nombres, que tiene que obtener del 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 haría la implementación 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 importados , 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 de import querrá tener acceso, para que pueda ver si son módulos e intentar importarlos también. Entonces la llamada está más cerca de:

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

lo que hace que __import__() intente cargar pkg.mod y pkg.mod2 , así como también pkg (pero si mod o mod2 no existen, no es un error en la __import__() ; la import produce un error al import declaración.) Pero todavía no es lo correcto para el cuarto y quinto ejemplo, porque si la llamada fue así:

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

entonces tmp terminaría siendo pkg , como antes, y no el módulo pkg.mod que desea obtener el atributo submod . La implementación podría haber decidido hacerlo para que la declaración de import haga un trabajo extra, dividiendo el nombre del paquete . como la función __import__() ya lo hace y atravesando los nombres, pero esto habría significado duplicar parte del esfuerzo. Por lo tanto, en su lugar, la implementación hizo que __import__() devolviera el módulo más a la derecha en lugar del más a la izquierda si y solo si se pasa la lista from y no está vacía.

(El import pkg as p y la from pkg import mod as m sintaxis no cambia nada sobre esta historia, excepto a qué nombres locales se asignan - la función __import__() no ve nada diferente cuando, as se usa, todo permanece en la import implementación de declaración.)


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

La lista de salida debe ser una lista de nombres para emular from name import ... , o una lista vacía para emular el 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ío, pero su submódulo B cuando fromlist no está vacío.

Básicamente, así es como funciona la implementación de __import__ : si quieres el submódulo, pasas una lista de fromlist contiene algo que deseas importar del submódulo, y la implementación si __import__ es tal que se devuelve el submódulo.

Explicación adicional

Creo que la semántica existe para que se devuelva el módulo más relevante. En otras palabras, supongamos que tengo un paquete foo contiene una bar módulos con 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 cambio, importo con:

from foo import bar

Luego me refiero a baz como bar.baz ()

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

Si lo hago:

from foo.bar import baz

Entonces me refiero a baz como

baz()

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

Entonces, en el primer caso, tendría que usar el nombre completamente calificado, por __import__ tanto __import__ devuelve el primer nombre de módulo que usaría para referirse a los elementos importados, eso 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 la bar sigue siendo el módulo más específico para devolver.


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

Primero, intente construir debajo de la estructura del archivo:

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

Ahora A es un package , y B o C es un module . Entonces cuando intentamos un código como estos en ipython:

Segundo, ejecute el código de muestra en ipython:

In [2]: kk = __import__(''A'',fromlist=[''B'']) In [3]: dir(kk) Out[3]: [''B'', ''__builtins__'', ''__doc__'', ''__file__'', ''__name__'', ''__package__'', ''__path__'']

Parece que la lista de trabajos funciona como esperábamos. Pero las cosas se conectan cuando intentamos 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 = []

Entonces, tratamos de hacer lo mismo con eso.

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 la lista de prueba, ¿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 lugar de en un package , el parámetro paralist de la lista no ayuda en absoluto porque el module ha sido compilado. Una vez que se importa, no hay forma de ignorar a los demás.