'Modul importieren' vs. 'Modul importieren'

143

Ich habe immer diese Methode verwendet:

from sys import argv

und argvmit nur argv verwenden . Es gibt jedoch eine Konvention, die dies verwendet:

import sys

und mit dem argv von sys.argv

Die zweite Methode macht den Code selbst dokumentiert und ich halte mich (wirklich) daran. Aber der Grund, warum ich die erste Methode bevorzuge, ist, dass sie schnell ist, weil wir nur die benötigte Funktion importieren, anstatt das gesamte Modul zu importieren (das mehr nutzlose Funktionen enthält, die Python beim Importieren verschwendet). Beachten Sie, dass ich nur argv brauche und alle anderen Funktionen von sys für mich nutzlos sind.

Also meine Fragen sind. Macht die erste Methode das Skript wirklich schnell? Welche Methode wird am meisten bevorzugt? Warum?

Santosh Kumar
quelle

Antworten:

175

Das Importieren des Moduls verschwendet nichts . Das Modul wird immer vollständig importiert (in das sys.modulesMapping), also ob Sie verwenden import sysoder from sys import argvkeine Gewinnchancen machen.

Der einzige Unterschied zwischen den beiden Anweisungen besteht darin, welcher Name gebunden ist. import sysBindet den Namen sysan das Modul (so sys-> sys.modules['sys']), während from sys import argvein anderer Name argvgebunden wird und direkt auf das im Modul enthaltene Attribut zeigt (so argv-> sys.modules['sys'].argv). Der Rest des sysModuls ist noch vorhanden, egal ob Sie etwas anderes aus dem Modul verwenden oder nicht.

Es gibt auch keinen Leistungsunterschied zwischen den beiden Ansätzen. Ja, sys.argvmuss zwei Dinge nachschlagen; Es muss sysin Ihrem globalen Namespace nachschlagen (findet das Modul) und dann das Attribut nachschlagen argv. Und ja, mit können from sys import argvSie die Attributsuche überspringen, da Sie bereits einen direkten Verweis auf das Attribut haben. Die importAnweisung muss dies jedoch noch tun. Sie sucht beim Importieren nach dem gleichen Attribut und muss nur einmal verwendet argv werden . Wenn Sie argvTausende Male in einer Schleife verwenden müssten, könnte dies möglicherweise einen Unterschied bewirken, in diesem speziellen Fall jedoch nicht.

Die Wahl zwischen dem einen oder anderen sollte stattdessen auf dem Codierungsstil basieren .

In einem großen Modul würde ich sicherlich verwenden import sys; Die Codedokumentation spielt eine wichtige Rolle, und die Verwendung einer sys.argvbeliebigen Stelle in einem großen Modul macht deutlich, worauf Sie sich beziehen, als dies argvjemals der Fall gewesen wäre.

Wenn der einzige Ort, den Sie verwenden, argvin einem '__main__'Block ist, um eine main()Funktion aufzurufen , verwenden Sie auf jeden Fall, from sys import argvwenn Sie sich darüber glücklicher fühlen:

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

Ich würde es immer noch selbst benutzen import sys. Alle Dinge sind gleich (und sie sind genau in Bezug auf die Leistung und die Anzahl der Zeichen, die zum Schreiben verwendet werden), das ist für mich nur ein Augenschmaus.

Wenn Sie etwas ganz anderes importieren , kommt vielleicht die Leistung ins Spiel. Aber nur, wenn Sie einen bestimmten Namen in einem Modul mehrfach verwenden , zum Beispiel in einer kritischen Schleife. Aber dann wird das Erstellen eines lokalen Namens (innerhalb einer Funktion) noch schneller sein:

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)
Martijn Pieters
quelle
1
Es gibt auch Situationen, in denen Sie ein Paket mit Unterpaketen oder Modulen haben, die ein Attribut eines dieser Unterpakete / Module im Paket der obersten Ebene verfügbar machen. Mit from...importkönnen Sie dies tun, package.attributeanstatt dies zu tun. Dies package.subpackage_or_module.attributekann hilfreich sein, wenn Sie logische oder konzeptionelle Gruppierungen innerhalb des Pakets haben, die Dinge aber für Benutzer Ihres Pakets ein wenig komfortabler gestalten möchten. ( numpytut so etwas, glaube ich.)
JAB
In Django gibt es Unmengen von Stellen, an denen Dinge from django.core.management.base import BaseCommandbesser sind, und alles andere (besonders import django) würde zu unlesbarem Code führen. Also, während ich diese Antwort mag, denke ich, dass es einige Bibliotheken (und insbesondere einige Frameworks) gibt, in denen die Konvention den bloßen Import verletzen soll. Verwenden Sie wie immer Ihr Urteil darüber, was in einer bestimmten Situation am besten ist. Aber irre auf der Seite des Expliziten (mit anderen Worten, ich stimme größtenteils zu).
Neuronet
1
@JAB: Sie können weiterhin verwenden , import ... asdas Paket zu einem anderen Namen zu finden: import package.subpackage_or_module as shortname. from parent import subtut im Wesentlichen das gleiche.
Martijn Pieters
43

Es gibt zwei Gründe für die Verwendung von import moduleanstatt from module import function.

Erstens ist der Namespace. Das Importieren einer Funktion in den globalen Namespace kann zu Namenskollisionen führen.

Zweitens ist dies nicht relevant für Standardmodule, aber wichtig für Ihre eigenen Module, insbesondere während der Entwicklung. Es ist die Option zu reload()einem Modul. Bedenken Sie:

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

Auf der anderen Seite

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

Was die Geschwindigkeit betrifft ...

Wir importieren nur die Funktion, die benötigt wird, anstatt das gesamte Modul zu importieren (das mehr nutzlose Funktionen enthält, die Python beim Importieren verschwendet).

Unabhängig davon, ob Sie ein Modul importieren oder eine Funktion aus einem Modul importieren, analysiert Python das gesamte Modul. In beiden Fällen wird das Modul importiert. "Eine Funktion importieren" ist nichts anderes als die Funktion an einen Namen zu binden. In der Tat import moduleist weniger Arbeit für Dolmetscher als from module import func.

vartec
quelle
6
reload () war in Python 2 eingebaut; Für Python 3 ist dies nicht mehr der Fall.
André
Ich dachte, es gäbe auch Auswirkungen auf zirkuläre Importabhängigkeiten?
ADP
18

Ich benutze from imports, wenn es die Lesbarkeit verbessert. Zum Beispiel bevorzuge ich (Semikolons sind hier nur platzsparend):

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

Anstatt von:

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

Letzteres ist für mich schwieriger zu lesen (und zu schreiben), da es so viele redundante Informationen enthält. Außerdem ist es hilfreich, im Voraus zu wissen, welche Teile eines Moduls ich verwende.

Ich bevorzuge reguläre imports, wenn ich viele Kurznamen aus einem Modul verwende:

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

Oder wenn ein Name so allgemein ist, dass er außerhalb seines Namensraums keinen Sinn ergibt:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

quelle
Das ist meine Lieblingsantwort. "Explizit ist besser als implizit" widerspricht manchmal der Lesbarkeit, Einfachheit und DRY. Vor allem, wenn Sie ein Framework wie Django verwenden.
Neuronet
18

Meiner Meinung nach importverbessert die regelmäßige Verwendung die Lesbarkeit. Wenn ich Python-Code überprüfe, sehe ich gerne, woher die angegebene Funktion oder Klasse kommt und wo sie verwendet wird. Es erspart mir das Scrollen zum oberen Rand des Moduls, um diese Informationen zu erhalten.

Für die langen Modulnamen verwende ich einfach das asSchlüsselwort und gebe ihnen kurze Aliase:

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

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

Ausnahmsweise benutze ich immer die from module import somethingNotation, wenn ich mich mit dem __future__Modul befasse. Sie können es einfach nicht anders machen, wenn Sie möchten, dass alle Zeichenfolgen in Python 2 standardmäßig Unicode sind, z

from __future__ import unicode_literals
from __future__ import print_function
Golem
quelle
Amen! "import as" ist eine gewinnende Kombination :-)
paj28
4

Obwohl import sysund from sys import agrvbeide das gesamte sysModul importieren , verwendet letzteres die Namensbindung, sodass nur das argvModul für den Rest des Codes zugänglich ist.

Für einige Leute wäre dies der bevorzugte Stil, da er nur die von Ihnen ausdrücklich angegebene Funktion zugänglich macht.

Es führt jedoch zu potenziellen Namenskonflikten. Was wäre, wenn Sie ein anderes Modul namens hätten argv? Beachten Sie, dass Sie die Funktion auch explizit importieren und umbenennen können from sys import argv as sys_argv, eine Konvention, die dem expliziten Import entspricht und die mit geringerer Wahrscheinlichkeit zu Namensraumkollisionen führt.

Duncan
quelle
2
Wie ist es if sys_argv:besser als if sys.argv:? Ich weiß, was die zweite Aussage bedeutet, ich habe keine Ahnung, was die erste Form bedeutet, ohne zum bizarren Import zurückzukehren.
msw
1

Diese Frage habe ich mir vor kurzem gestellt. Ich habe die verschiedenen Methoden zeitlich festgelegt.

fordert Bibliothek an

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

schöne Suppenbibliothek

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

json Bibliothek

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

Sys-Bibliothek

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

Es scheint mir, dass es einen kleinen Unterschied in der Leistung gibt.

tmthyjames
quelle
Sie fügen eine Attributsuche hinzu. Fügen Sie dem Fall diese Namenssuche hinzu, um einen Vergleich import modulemit from module import namekorrekt durchzuführen . ZB die Zeile zum Test hinzufügen usw. Es wird immer noch einen Unterschied geben, da die durchgeführte Arbeit leicht unterschiedlich ist, da ein unterschiedlicher Bytecode generiert und unterschiedliche Codepfade ausgeführt werden. import modulesys.argvar
Martijn Pieters
2
Beachten Sie, dass ich diesen Unterschied in meiner Antwort direkt anspreche. Es gibt einen Unterschied zwischen der Verwendung import sysvon sys.argvTausenden von Zeit in einer Schleife from sys import argvund der Verwendung von nur argv. Aber du nicht. Für Dinge, die Sie nur einmal auf globaler Ebene Ihres Moduls tun , sollten Sie wirklich die Lesbarkeit optimieren, nicht mikroskopische Unterschiede in den Timings.
Martijn Pieters
1
Ahhhh! Und ich dachte, ich hätte was vor! :) Ich habe nur deine Antwort überflogen. Sieht so aus, als hätte ich die Waffe darauf gesprungen. Fühlt sich gut an, demütig zu sein.
tmthyjames
-1

Veröffentlichte Codefragmente zu betrachten, ganze Module zu importieren und auf sie zu verweisen, module.functionist zumindest für Standardmodule so ziemlich der Standard. Die einzige Ausnahme scheint zu seindatetime

from datetime import datetime, timedelta

so kann man datetime.now()eher sagen als datetime.datetime.now().

Wenn Sie sich Sorgen um die Leistung machen, können Sie immer sagen (zum Beispiel)

argv = sys.argv

Führen Sie dann Ihren leistungskritischen Code aus, da die Modulsuche bereits erfolgt ist. Obwohl dies mit Funktionen / Methoden funktioniert, werden die meisten IDEs verwirrt und zeigen (zum Beispiel) keine Quellverknüpfung / -signatur für die Funktion an, wenn sie einer Variablen zugewiesen wird.

Austin
quelle
-2

Ich möchte das nur hinzufügen, wenn Sie so etwas tun

from math import sin

(oder eine andere eingebaute Bibliothek wie sysoder posix), sinwird dann in die Dokumentation für Ihr Modul aufgenommen (dh wenn Sie dies tun >>> help(mymodule)oder $ pydoc3 mymodule. Um dies zu vermeiden, importieren Sie mit:

import math
from math import sin as _sin

PS: Eine eingebaute Bibliothek ist eine, die aus C-Code kompiliert und in Python enthalten ist. argparse, osUnd iosind nicht eingebaut in Paketen

Epischer Wink
quelle