'modul impor' vs. 'dari fungsi impor modul'


143

Saya selalu menggunakan metode ini:

from sys import argv

dan gunakan argvhanya dengan argv . Tetapi ada kesepakatan untuk menggunakan ini:

import sys

dan menggunakan argv oleh sys.argv

Metode kedua membuat kode didokumentasikan sendiri dan saya (benar-benar) mematuhinya. Tapi alasan saya lebih suka metode pertama adalah cepat karena kita hanya mengimpor fungsi yang diperlukan daripada mengimpor seluruh modul (yang berisi lebih banyak fungsi tidak berguna yang python akan membuang waktu mengimpornya). Perhatikan bahwa saya hanya perlu argv dan semua fungsi lain dari sys tidak berguna bagi saya.

Jadi pertanyaan saya adalah. Apakah metode pertama benar-benar membuat script cepat? Metode mana yang paling disukai? Mengapa?



Jawaban:


175

Mengimpor modul tidak membuang apa pun ; modul selalu sepenuhnya diimpor (ke sys.modulespemetaan), jadi apakah Anda menggunakan import sysatau from sys import argvtidak membuat kesulitan.

Satu-satunya perbedaan antara kedua pernyataan itu adalah apa nama yang terikat; import sysmengikat nama syske modul (jadi sys-> sys.modules['sys']), sementara from sys import argvmengikat nama yang berbeda argv,, menunjuk langsung ke atribut yang terdapat di dalam modul (jadi argv-> sys.modules['sys'].argv). Sisa sysmodul masih ada, apakah Anda menggunakan hal lain dari modul atau tidak.

Juga tidak ada perbedaan kinerja antara kedua pendekatan. Ya, sys.argvharus mencari dua hal; itu harus mencari sysdi namespace global Anda (menemukan modul), kemudian mencari atributnya argv. Dan ya, dengan menggunakan from sys import argvAnda dapat melewati pencarian atribut, karena Anda sudah memiliki referensi langsung ke atribut. Tetapi importpernyataan itu masih harus melakukan itu, itu mencari atribut yang sama ketika mengimpor, dan Anda hanya perlu menggunakannya argv sekali . Jika Anda harus menggunakan argvribuan kali dalam satu lingkaran itu mungkin bisa membuat perbedaan, tetapi dalam kasus khusus ini sebenarnya tidak.

Pilihan antara satu atau yang lain itu, harus didasarkan pada gaya pengkodean saja.

Dalam modul besar , saya pasti akan menggunakan import sys; dokumentasi kode penting, dan menggunakan sys.argvsuatu tempat dalam modul besar membuatnya lebih jelas apa yang Anda maksud daripada yang argvpernah ada.

Jika satu-satunya tempat yang Anda gunakan argvadalah dalam '__main__'blok untuk memanggil main()fungsi, tentu saja gunakan from sys import argvjika Anda merasa lebih bahagia tentang hal itu:

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

Saya masih menggunakannya di import syssana sendiri. Semua hal menjadi sama (dan mereka, tepatnya, dalam hal kinerja dan jumlah karakter yang digunakan untuk menulisnya), itu hanya lebih mudah bagi saya.

Jika Anda mengimpor sesuatu yang lain sama sekali, maka mungkin kinerja ikut bermain. Tetapi hanya jika Anda menggunakan nama tertentu dalam sebuah modul berkali-kali , dalam loop kritis misalnya. Tetapi kemudian membuat nama lokal (dalam suatu fungsi) akan menjadi lebih cepat:

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)

1
Ada juga situasi di mana Anda memiliki paket dengan subpackages atau modul yang memperlihatkan atribut salah satu subpackages / modul dalam paket tingkat atas. Menggunakan from...importmemungkinkan Anda untuk melakukan package.attributelebih daripada package.subpackage_or_module.attribute, yang dapat berguna jika Anda memiliki pengelompokan logis atau konseptual dalam paket tetapi ingin membuat hal-hal sedikit lebih nyaman bagi pengguna paket Anda. (Saya numpykira melakukan hal seperti ini.)
JAB

Dalam Django Anda memiliki banyak tempat di mana hal-hal seperti from django.core.management.base import BaseCommandlebih baik, dan hal lain (terutama import django) akan menyebabkan kode tidak terbaca. Jadi, sementara saya suka jawaban ini, saya pikir ada beberapa perpustakaan (dan terutama beberapa kerangka kerja) di mana konvensi itu melanggar impor kosong. Seperti biasa, gunakan penilaian Anda tentang apa yang terbaik dalam situasi tertentu. Tetapi sesat di sisi eksplisit (dengan kata lain saya setuju untuk sebagian besar).
neuronet

1
@JAB: Anda masih dapat menggunakan import ... asuntuk menemukan paket untuk nama yang berbeda: import package.subpackage_or_module as shortname. from parent import subpada dasarnya melakukan hal yang sama.
Martijn Pieters

43

Ada dua alasan yang mendukung penggunaan import moduledaripada from module import function.

Pertama adalah namespace. Mengimpor fungsi ke namespace global berisiko bertabrakan nama.

Kedua tidak begitu relevan dengan modul standar, tetapi signifikan untuk Anda memiliki modul, terutama selama pengembangan. Ini pilihan untuk reload()modul. Pertimbangkan ini:

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

Di samping itu

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

Adapun kecepatan ...

kami hanya mengimpor fungsi yang diperlukan daripada mengimpor seluruh modul (yang berisi lebih banyak fungsi tidak berguna yang python akan membuang waktu mengimpornya)

Apakah Anda mengimpor modul atau mengimpor fungsi dari modul, Python akan mem-parsing seluruh modul. Either way modul diimpor. "Mengimpor fungsi" tidak lebih dari mengikat fungsi ke sebuah nama. Bahkan import modulelebih sedikit pekerjaan untuk penerjemah daripada from module import func.


6
reload () adalah builtin di Python 2; itu tidak lagi berlaku untuk Python 3.
André

Saya pikir ada juga implikasi yang berkaitan dengan ketergantungan impor sirkuler?
ADP

18

Saya menggunakan from imports setiap kali itu meningkatkan keterbacaan. Sebagai contoh, saya lebih suka (titik koma hanya untuk menghemat ruang di sini):

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

dari pada:

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

Yang terakhir lebih sulit untuk dibaca (dan ditulis) untuk saya karena mengandung begitu banyak informasi yang berlebihan. Juga, berguna untuk mengetahui sebelumnya bagian mana dari modul yang saya gunakan.

Saya lebih suka imports biasa jika saya menggunakan banyak nama pendek dari modul:

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

Atau jika sebuah nama sangat umum sehingga tidak masuk akal di luar ruang namanya:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

Ini jawaban favorit saya. 'Eksplisit lebih baik daripada implisit' terkadang bertentangan dengan keterbacaan, kesederhanaan, dan KERING. Apalagi saat menggunakan framework seperti Django.
neuronet

18

Menurut pendapat saya menggunakan reguler importmeningkatkan keterbacaan. Saat mengulas kode Python, saya suka melihat dari mana fungsi atau kelas yang diberikan berasal dari tempat kode itu digunakan. Ini menyelamatkan saya dari gulir ke bagian atas modul untuk mendapatkan info itu.

Sedangkan untuk nama modul yang panjang saya hanya menggunakan askata kunci dan memberi mereka alias pendek:

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

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

Sebagai pengecualian saya selalu menggunakan from module import somethingnotasi ketika saya berurusan dengan __future__modul. Anda tidak bisa melakukannya dengan cara lain ketika Anda ingin semua string menjadi unicode secara default di Python 2, misalnya

from __future__ import unicode_literals
from __future__ import print_function

Amin! "import as" adalah kombinasi yang unggul :-)
paj28

4

Meskipun import sysdan from sys import agrvkeduanya mengimpor seluruh sysmodul, yang terakhir menggunakan pengikatan nama sehingga hanya argvmodul yang dapat diakses untuk sisa kode.

Bagi sebagian orang ini akan menjadi gaya yang disukai karena hanya membuat diakses fungsi yang Anda nyatakan secara eksplisit.

Namun itu memperkenalkan potensi konflik nama. Bagaimana jika Anda memiliki modul lain yang dinamai argv? Catatan Anda juga dapat secara eksplisit mengimpor fungsi dan mengganti nama dengan from sys import argv as sys_argv, konvensi yang memenuhi impor eksplisit dan kecil kemungkinannya untuk memberikan tabrakan ruang nama.


2
Jadi bagaimana yang if sys_argv:lebih baik dari itu if sys.argv:? Saya tahu apa arti pernyataan kedua, saya tidak tahu apa arti bentuk pertama tanpa mundur ke impor aneh.
msw

1

Baru-baru ini saya mengajukan pertanyaan ini kepada diri saya sendiri. Saya menghitung waktu berbagai metode.

meminta perpustakaan

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

perpustakaan 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

perpustakaan 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

perpustakaan sys

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

Menurut saya ada sedikit perbedaan dalam kinerja.


Anda menambahkan dalam pencarian atribut. Untuk membandingkan import moduledengan from module import namebenar, tambahkan pencarian nama ke import modulecase. Misalnya menambahkan baris sys.argvke artes, dll. Masih akan ada perbedaan, karena pekerjaan yang dilakukan sedikit berbeda, karena bytecode yang berbeda dihasilkan dan codepath yang berbeda dieksekusi.
Martijn Pieters

2
Perhatikan bahwa saya langsung menjawab perbedaan itu dalam jawaban saya; akan ada perbedaan antara menggunakan import syskemudian menggunakan sys.argvribuan waktu dalam satu lingkaran vs from sys import argvkemudian menggunakan hanya argv. Tapi kamu tidak. Untuk hal-hal yang Anda lakukan sekali saja di tingkat global modul Anda, Anda harus benar-benar mengoptimalkan keterbacaan, bukan perbedaan waktu yang mikroskopis.
Martijn Pieters

1
Ahhhh! Dan saya pikir saya sedang melakukan sesuatu! :) Saya hanya membaca jawaban Anda. Sepertinya saya melompati pistol itu. Terasa enak direndahkan.
tmthyjames

-1

Melihat fragmen kode yang diterbitkan, mengimpor seluruh modul dan merujuk module.functioncukup banyak standar, setidaknya untuk modul standar. Satu-satunya pengecualian tampaknyadatetime

from datetime import datetime, timedelta

sehingga Anda bisa mengatakan datetime.now()bukan datetime.datetime.now().

Jika Anda khawatir tentang kinerja, Anda selalu bisa mengatakan (misalnya)

argv = sys.argv

dan kemudian lakukan kode kritis kinerja Anda karena pencarian modul sudah dilakukan. Namun meskipun ini akan bekerja dengan fungsi / metode, sebagian besar IDE akan menjadi bingung dan tidak akan (misalnya) menampilkan tautan sumber / tanda tangan untuk fungsi ketika itu ditugaskan ke variabel.


-2

Saya hanya ingin menambahkan itu jika Anda melakukan sesuatu seperti

from math import sin

(atau perpustakaan bawaan lainnya seperti sysatau posix), maka sinakan dimasukkan dalam dokumentasi untuk modul Anda (yaitu ketika Anda melakukannya >>> help(mymodule)atau $ pydoc3 mymodule. Untuk menghindari ini, impor menggunakan:

import math
from math import sin as _sin

PS: perpustakaan bawaan adalah yang dikompilasi dari kode C dan disertakan dengan Python. argparse, osdan iobukan paket bawaan

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.