'módulo de importación' vs. 'desde la función de importación de módulo'

125

Siempre he estado usando este método:

from sys import argv

y use argv con solo argv . Pero hay una convención de usar esto:

import sys

y usando el argumento argv por sys.argv

El segundo método hace que el código sea autodocumentado y (en realidad) lo cumplo. Pero la razón por la que prefiero el primer método es que es rápido porque estamos importando solo la función que se necesita en lugar de importar todo el módulo (que contiene más funciones inútiles que Python perderá tiempo importándolos). Tenga en cuenta que solo necesito argv y todas las demás funciones de sys son inútiles para mí.

Así que mis preguntas son. ¿El primer método realmente hace que el script sea rápido? ¿Qué método es el más preferido? ¿Por qué?

    
pregunta Santosh Kumar 18.02.2013 - 06:43
fuente

8 respuestas

159

La importación del módulo no desperdicia nada ; el módulo siempre se importa completamente (en la asignación sys.modules ), por lo tanto, si utiliza import sys o from sys import argv no hay probabilidades.

La única diferencia entre las dos declaraciones es qué nombre está enlazado; import sys une el nombre sys al módulo (entonces sys - > sys.modules['sys'] ), mientras que from sys import argv une un nombre diferente, argv , apuntando directamente al atributo contenido dentro del módulo (así que argv - > sys.modules['sys'].argv ). El resto del módulo sys todavía está allí, ya sea que uses algo más del módulo o no.

Tampoco hay diferencia de rendimiento entre los dos enfoques. Sí, sys.argv tiene que buscar dos cosas; tiene que buscar sys en su espacio de nombres global (encuentra el módulo), luego buscar el atributo argv . Y sí, al utilizar from sys import argv puede omitir la búsqueda de atributos, ya que ya tiene una referencia directa al atributo. Pero la declaración import todavía tiene que hacer ese trabajo, busca el mismo atributo al importar, y solo tendrá que usar argv una vez . Si tuviera que usar argv miles de veces en un bucle, tal vez podría hacer una diferencia, pero en este caso específico realmente no lo hace.

La elección entre uno u otro entonces, debe basarse en estilo de codificación en su lugar.

En un módulo grande , ciertamente usaría import sys ; la documentación del código es importante, y el uso de sys.argv en algún lugar en un módulo grande hace que sea mucho más claro a qué se refiere usted que solo argv alguna vez.

Si el único lugar donde usas argv está en un bloque '__main__' para llamar a una función main() , por supuesto usa from sys import argv si te sientes más feliz con eso:

if __name__ == '__main__':
    from sys import argv
    main(argv)

Yo todavía usaría import sys allí mismo. En igualdad de condiciones (y son, exactamente, en términos de rendimiento y el número de caracteres utilizados para escribirlo), eso es más fácil para mí.

Si está importando algo else por completo, tal vez el rendimiento entra en juego. Pero solo si usa un nombre específico en un módulo varias veces más , en un ciclo crítico, por ejemplo. Pero luego, crear un nombre local (dentro de una función) será más rápido aún:

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)
    
respondido por el Martijn Pieters 18.02.2013 - 19:17
fuente
38

Hay dos razones a favor de usar import module en lugar de from module import function .

Primero está el espacio de nombres. La importación de una función en el espacio de nombres global pone en riesgo las colisiones de nombres.

En segundo lugar, no es tan relevante para los módulos estándar, sino que es importante para sus propios módulos, especialmente durante el desarrollo. Es la opción para reload() un módulo. Considera esto:

from module import func
...
reload(module)
# func still points to the old code

Por otro lado

import module
...
reload(module)
# module.func points to the new code

En cuanto a la velocidad ...

  

estamos importando solo la función que se necesita en lugar de importar   El módulo completo (que contiene funciones más inútiles que Python   perderá tiempo importándolos)

Tanto si importa un módulo como si importa una función desde un módulo, Python analizará todo el módulo. De cualquier manera el módulo es importado. "Importar una función" no es más que vincular la función a un nombre. De hecho, import module es menos trabajo para el intérprete que from module import func .

    
respondido por el vartec 18.02.2013 - 10:09
fuente
17

En mi opinión, el uso de import normal mejora la legibilidad. Cuando reviso el código de Python, me gusta ver de dónde viene la función o clase dada donde se usa. Me evita desplazarme hasta la parte superior del módulo para obtener esa información.

En cuanto a los nombres largos de módulos, solo uso la palabra clave as y les doy alias cortos:

import collections as col
import foomodule as foo
import twisted.internet.protocol as twip

my_dict = col.defaultdict()
foo.FooBar()
twip_fac = twip.Factory()

Como excepción, siempre uso la notación from module import something cuando trato con el módulo __future__ . No puedes hacerlo de otra manera cuando quieres que todas las cadenas estén unicode de forma predeterminada en Python 2, por ejemplo,

from __future__ import unicode_literals
from __future__ import print_function
    
respondido por el golem 04.03.2015 - 18:25
fuente
16

Utilizo from import s cuando mejora la legibilidad. Por ejemplo, prefiero (los puntos y coma son solo para ahorrar espacio aquí):

from collections import defaultdict
from foomodule import FooBar, FooBaz
from twisted.internet.protocol import Factory
defaultdict(); FooBar(); FooBaz(); Factory()

en lugar de:

import collections
import foomodule
import twisted.internet.protocol
collections.defaultdict(); foomodule.FooBar(); foomodule.FooBaz()
twisted.internet.protocol.Factory()

El último es más difícil de leer (y escribir) para mí porque contiene mucha información redundante. Además, es útil saber de antemano qué partes de un módulo estoy usando.

Prefiero import s regular si uso muchos nombres cortos de un módulo:

import sys
sys.argv; sys.stderr; sys.exit()

O si un nombre es tan genérico que no tiene sentido fuera de su espacio de nombres:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing
    
respondido por el user76704 18.02.2013 - 19:42
fuente
4

Aunque tanto import sys como from sys import agrv importan todo el módulo sys , este último usa el enlace de nombres, por lo que solo el módulo argv es accesible al resto del código.

Para algunas personas, este sería el estilo preferido, ya que solo hace accesible la función que usted estableció explícitamente.

Sin embargo, sí introduce posibles conflictos de nombre. ¿Qué pasaría si tuvieras otro módulo llamado argv ? Tenga en cuenta que también puede importar explícitamente la función y cambiar el nombre con from sys import argv as sys_argv , una convención que cumple con la importación explícita y es menos probable que provoque colisiones en el espacio de nombres.

    
respondido por el Duncan 20.02.2013 - 05:49
fuente
1

Hace poco me hice esta pregunta. He cronometrado los diferentes métodos.

biblioteca de solicitudes

def r():
    import requests
    return 'hello'
timeit r() # output: 1000000 loops, best of 3: 1.55 µs per loop

def rg():
    from requests import get
    return 'hello'
timeit rg() # output: 100000 loops, best of 3: 2.53 µs per loop

biblioteca beautifulsoup

def bs():
    import bs4
    return 'hello' 
timeit bs() # output: 1000000 loops, best of 3: 1.53 µs per loop

def be():
    from bs4 import BeautifulSoup
    return 'hello'
timeit be() # output: 100000 loops, best of 3: 2.59 µs per loop

biblioteca json

def js():
    import json
    return 'hello'
timeit js() # output: 1000000 loops, best of 3: 1.53 µs per loop

def jl():
    from json import loads
    return 'hello'
timeit jl() # output: 100000 loops, best of 3: 2.56 µs per loop

biblioteca de sistemas

def s():
    import sys
    return 'hello'
timeit s() # output: 1000000 loops, best of 3: 1.55 µs per loop

def ar():
    from sys import argv
    return 'hello'
timeit ar() # output: 100000 loops, best of 3: 2.87 µs per loop

Me parece que hay una ligera diferencia en el rendimiento.

    
respondido por el tmthyjames 07.01.2015 - 22:23
fuente
-1

En cuanto a los fragmentos de código publicados, importar módulos completos y hacer referencia a module.function es prácticamente el estándar, al menos para los módulos estándar. La única excepción parece ser datetime

from datetime import datetime, timedelta

para que puedas decir datetime.now() en lugar de datetime.datetime.now() .

Si le preocupa el rendimiento, siempre puede decir (por ejemplo)

argv = sys.argv

y luego haga su código crítico de rendimiento ya que la búsqueda del módulo ya está hecha. Sin embargo, aunque esto funcionará con funciones / métodos, la mayoría de los IDE se confundirán y no mostrarán (por ejemplo) un enlace / firma de origen para la función cuando se asigne a una variable.

    
respondido por el Austin 03.06.2016 - 18:01
fuente
-2

Solo quiero añadir que si haces algo como

from math import sin

(o cualquier otra biblioteca incorporada como sys o posix ), entonces sin se incluirá en la documentación de su módulo (es decir, cuando haga >>> help(mymodule) o $ pydoc3 mymodule . Para evitar esto , importar utilizando:

import math
from math import sin as _sin

PS: una biblioteca incorporada se compila a partir del código C y se incluye con Python. argparse , os y io no son paquetes integrados

    
respondido por el Epic Wink 03.09.2017 - 07:33
fuente

Lea otras preguntas en las etiquetas