¿Usar 'importar módulo' o 'desde módulo importar'?

Resuelto Filip Dupanović asked hace 15 años • 23 respuestas

Intenté encontrar una guía completa sobre si es mejor usar import moduleo from module import. Acabo de empezar con Python y estoy intentando empezar teniendo en cuenta las mejores prácticas.

Básicamente, esperaba que alguien pudiera compartir sus experiencias, qué preferencias tienen otros desarrolladores y cuál es la mejor manera de evitar problemas en el futuro.

Filip Dupanović avatar Apr 02 '09 23:04 Filip Dupanović
Aceptado

La diferencia entre import moduley from module import fooes principalmente subjetiva. Elija el que más le guste y sea constante en su uso. Aquí hay algunos puntos que le ayudarán a decidir.

import module

  • Ventajas:
    • Menos mantenimiento de tus importestados de cuenta. No es necesario agregar ninguna importación adicional para comenzar a usar otro elemento del módulo.
  • Contras:
    • Escribir module.foosu código puede ser tedioso y redundante (el tedio se puede minimizar usando import module as moluego escribir mo.foo)

from module import foo

  • Ventajas:
    • Menos escritura para usarfoo
    • Más control sobre a qué elementos de un módulo se puede acceder
  • Contras:
    • Para utilizar un nuevo artículo del módulo tienes que actualizar tu importestado de cuenta
    • Pierdes contexto sobre foo. Por ejemplo, está menos claro qué ceil()significa en comparación conmath.ceil()

Cualquiera de los métodos es aceptable, pero no lo utilice from module import *.

Para cualquier conjunto de código grande razonable, si lo desea, import *probablemente lo cementará en el módulo y no podrá eliminarlo. Esto se debe a que es difícil determinar qué elementos utilizados en el código provienen del 'módulo', lo que facilita llegar al punto en el que crees que importya no los usas, pero es extremadamente difícil estar seguro.

Mark Roddy avatar Apr 02 '2009 16:04 Mark Roddy

Hay otro detalle aquí, no mencionado, relacionado con la escritura en un módulo. Es cierto que esto puede no ser muy común, pero lo he necesitado de vez en cuando.

Debido a la forma en que funcionan las referencias y la vinculación de nombres en Python, si desea actualizar algún símbolo en un módulo, digamos foo.bar, desde fuera de ese módulo, y hacer que otro código de importación "vea" ese cambio, debe importar foo a de cierta manera. Por ejemplo:

módulo fo:

bar = "apples"

módulo a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

módulo b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

Sin embargo, si importa nombres de símbolos en lugar de nombres de módulos, esto no funcionará.

Por ejemplo, si hago esto en el módulo a:

from foo import bar
bar = "oranges"

Ningún código externo ase verá barcomo "naranjas" porque mi configuración barsimplemente afectó el nombre "barra" dentro del módulo a, no "alcanzó" el fooobjeto del módulo ni actualizó su archivo bar.

Michael Ray Lovett avatar Oct 04 '2013 16:10 Michael Ray Lovett

Aunque mucha gente ya ha explicado sobre importvs import from, quiero intentar explicar un poco más sobre lo que sucede bajo el capó y dónde están todos los lugares en los que cambia.


import foo:

Importa fooy crea una referencia a ese módulo en el espacio de nombres actual. Luego, debe definir la ruta completa del módulo para acceder a un atributo o método particular desde dentro del módulo.

Por ejemplo foo.bar, pero nobar

from foo import bar:

Importa fooy crea referencias a todos los miembros enumerados ( bar). No establece la variable foo.

Por ejemplo bar, pero no bazofoo.baz

from foo import *:

Importa fooy crea referencias a todos los objetos públicos definidos por ese módulo en el espacio de nombres actual (todo lo que figura en __all__si __all__existe; de ​​lo contrario, todo lo que no comienza con _). No establece la variable foo.

Por ejemplo bar, y bazpero no _quxo foo._qux.


Ahora veamos cuando lo hacemos import X.Y:

>>> import sys
>>> import os.path

Consulte sys.modulescon nombre osy os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Comprobar globals()y locals()dictar espacios de nombres con osy os.path:

>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

En el ejemplo anterior encontramos que solo osse inserta en el espacio de nombres local y global. Entonces, deberíamos poder usar:

>>> os
<module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

Pero no path.

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Una vez que elimines el osespacio de nombres from locals(), no podrás acceder ostan bien como os.pathaunque existan en sys.modules:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Ahora hablemos de import from:

from:

>>> import sys
>>> from os import path

Consulte sys.modulescon osy os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Descubrimos que sys.modulesencontramos lo mismo que antes usandoimport name

Bien, veamos cómo se ve en los dictados locals()del globals()espacio de nombres:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

Puede acceder utilizando el nombre, pathno mediante os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Eliminemos 'ruta' de locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Un último ejemplo usando un alias:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

Y ningún camino definido:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>
James Sapam avatar Feb 04 '2014 08:02 James Sapam

Ambas formas son compatibles por una razón: hay ocasiones en las que una es más apropiada que la otra.

  • import module: agradable cuando utilizas muchos bits del módulo. El inconveniente es que deberá calificar cada referencia con el nombre del módulo.

  • from module import ...: es bueno que los elementos importados se puedan utilizar directamente sin el prefijo de nombre del módulo. El inconveniente es que debes enumerar cada cosa que usas y que no está claro en el código de dónde viene algo.

Cuál usar depende de qué hace que el código sea claro y legible, y tiene más que ver con las preferencias personales. Me inclino por import modulelo general porque en el código está muy claro de dónde proviene un objeto o función. Lo uso from module import ...cuando uso mucho algún objeto/función en el código.

dwc avatar Apr 02 '2009 16:04 dwc