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 elimport 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.