Mengapa "impor *" buruk?


153

Disarankan untuk tidak menggunakan import *Python.

Adakah yang bisa berbagi alasan untuk itu, sehingga saya bisa menghindarinya nanti?



2
itu tergantung jika Anda menulis atau menulis kode yang perlu Anda gunakan kembali. terkadang membayar untuk mengabaikan standar kode. "import *" juga bisa baik-baik saja jika Anda memiliki konvensi penamaan yang menjelaskan dari mana barang itu berasal. mis. "dari impor Kucing *; TabbyCat; MaineCoonCat; CalicoCat;"
gatoatigrado

3
import *tidak bekerja untuk saya di tempat pertama dalam Python 2 atau 3.
joshreesjones

1
Apakah ini menjawab pertanyaan Anda? Apa sebenarnya yang "impor *" impor?
AMC

Jawaban:


223
  • Karena itu menempatkan banyak barang ke namespace Anda (mungkin membayangi beberapa objek lain dari impor sebelumnya dan Anda tidak akan mengetahuinya).

  • Karena Anda tidak tahu persis apa yang diimpor dan tidak dapat dengan mudah menemukan dari modul mana barang tertentu diimpor (keterbacaan).

  • Karena Anda tidak dapat menggunakan alat keren pyflakesuntuk mendeteksi kesalahan secara statis dalam kode Anda.


2
Ya, saya benar-benar benci pada pekerjaan saya ketika seseorang menggunakan * impor, karena dengan begitu saya tidak bisa hanya menjalankan pyflakes dan bahagia, tetapi harus memperbaiki impor itu. Sangat menyenangkan, dengan piringan itu membantu saya untuk :-)
gruszczy

7
Sebagai contoh nyata, banyak pengguna NumPy telah digigit oleh numpy.anymembayangi anyketika mereka melakukannya from numpy import *atau alat "membantu" melakukannya untuk mereka.
user2357112 mendukung Monica

1
Haruskah saya menghindari menggunakan saklar --pylab untuk IPython karena alasan yang sama?
timgeb

6
Untuk menyorot risiko Aku tak pernah berpikir sebelum membaca ini ( "mungkin bayangan objek lain dari impor sebelumnya"): import *membuat urutan dari importpernyataan yang signifikan ... bahkan untuk modul perpustakaan standar yang biasanya tidak peduli tentang pesanan impor . Sesuatu yang tidak bersalah seperti abjad importpernyataan Anda dapat merusak skrip Anda ketika mantan korban perang impor menjadi satu-satunya yang selamat. (Bahkan jika skrip Anda bekerja sekarang dan tidak pernah berubah, itu bisa tiba-tiba gagal beberapa saat kemudian jika modul yang diimpor memperkenalkan nama baru yang menggantikan nama yang Anda andalkan.)
Kevin J. Chase

49

Menurut Zen Python :

Eksplisit lebih baik daripada implisit.

... tidak bisa berdebat dengan itu, tentunya?


29
Sebenarnya, Anda bisa berdebat dengan itu. Ini juga sama sekali tidak konsisten, mengingat bahwa Anda tidak mendeklarasikan variabel secara eksplisit dalam Python, mereka hanya muncul begitu Anda menetapkannya.
Konrad Rudolph

7
@ gruszczy: menyatakan variabel tidak berguna untuk apa ? Menetapkan? Tidak, itu dua konsep yang terpisah dan menyatakan sesuatu menyampaikan informasi yang sangat berbeda dan penting. Ngomong-ngomong, saksi mata selalu agak terkait dengan redundansi, mereka adalah dua wajah dari koin yang sama.
Konrad Rudolph

3
@ benar, tapi itu bukan maksud saya. Maksud saya adalah bahwa kegagalan untuk secara eksplisit mendeklarasikan variabel mengarah ke kesalahan. Anda mengatakan bahwa "tugas tanpa [deklarasi] tidak mungkin". Tapi itu salah, seluruh poin saya adalah bahwa Python sayangnya membuat hal itu mungkin terjadi.
Konrad Rudolph

3
@kriss lain sepotong informasi yang diberikan kepada compiler dengan deklarasi adalah kenyataan bahwa Anda memang berniat untuk mendeklarasikan variabel baru. Itu informasi penting untuk sistem tipe. Anda mengatakan bahwa IDE modern menyelesaikan masalah kesalahan ketik tapi itu hanya salah, dan sebenarnya ini adalah masalah besar dalam bahasa yang dikompilasi secara tidak statis, itulah sebabnya Perl menambahkan use strict(JavaScript var). Sebagai tambahan, tentu saja Python tidak bertulisan (itu sebenarnya sangat diketik). Bagaimanapun, bahkan jika Anda benar, ini masih akan bertentangan dengan Zen Python, dikutip dalam jawaban ini.
Konrad Rudolph

3
@ Kriss Anda salah: menggunakan kembali nama variabel yang sama bukan masalah - menggunakan kembali variabel yang sama (yaitu nama yang sama dalam cakupan yang sama). Deklarasi eksplisit akan mencegah kesalahan ini (dan lainnya, berdasarkan kesalahan ketik sederhana, yang, seperti telah saya katakan, sebenarnya merupakan masalah yang sangat umum dan memakan waktu, meskipun Anda benar bahwa masalahnya lebih besar pada Perl-like) bahasa). Dan kontradiksi yang saya singgung adalah persyaratan Zen untuk kesaksian, yang secara fisik dibuang keluar jendela di sini.
Konrad Rudolph

40

Anda tidak lolos **locals()ke fungsi, bukan?

Karena Python tidak memiliki pernyataan "termasuk", dan yang selfparameter eksplisit, dan scoping aturan yang cukup sederhana, biasanya sangat mudah untuk menunjuk jari pada variabel dan memberitahu mana yang objek berasal dari - tanpa membaca modul lain dan tanpa jenis IDE (yang terbatas di jalan introspeksi, oleh karena bahasanya sangat dinamis).

The import *istirahat semua itu.

Juga, ia memiliki kemungkinan nyata untuk menyembunyikan bug.

import os, sys, foo, sqlalchemy, mystuff
from bar import *

Sekarang, jika modul bar memiliki atribut " os", " mystuff", dll ..., mereka akan menimpa yang diimpor secara eksplisit, dan mungkin menunjuk ke hal-hal yang sangat berbeda. Mendefinisikan __all__bar seringkali bijaksana - ini menyatakan apa yang akan diimpor secara implisit - tetapi masih sulit untuk melacak dari mana objek berasal, tanpa membaca dan menguraikan modul bar dan mengikuti nya impor. Jaringan import *adalah hal pertama yang saya perbaiki ketika saya memiliki sebuah proyek.

Jangan salah paham: jika import *hilang, saya akan menangis untuk memilikinya. Tetapi harus digunakan dengan hati-hati. Kasus penggunaan yang baik adalah untuk menyediakan antarmuka fasad di atas modul lain. Demikian juga, penggunaan pernyataan impor bersyarat, atau impor di dalam ruang nama fungsi / kelas, memerlukan sedikit disiplin.

Saya pikir dalam proyek-proyek menengah ke besar, atau yang kecil dengan beberapa kontributor, kebersihan minimum diperlukan dalam hal analisis statis - menjalankan setidaknya pyflakes atau bahkan lebih baik pylint yang dikonfigurasi dengan benar - untuk menangkap beberapa jenis bug sebelum itu terjadi.

Tentu saja karena ini adalah python - jangan ragu untuk melanggar aturan, dan untuk mengeksplorasi - tetapi waspada terhadap proyek yang dapat tumbuh sepuluh kali lipat, jika kode sumber hilang disiplin maka itu akan menjadi masalah.


6
Python 2.x memang memiliki pernyataan "include". Itu disebut execfile(). Untungnya, ini jarang digunakan dan hilang dalam 3.x.
Sven Marnach

Bagaimana **vars()cara memasukkan global jika fungsi yang dipanggil ada di file lain? : P
Solomon Ucko

16

Tidak apa-apa untuk dilakukan from ... import *dalam sesi interaktif.


Bagaimana kalau di dalam docteststring? Apakah import *ditafsirkan dalam "kotak pasir" dalam kasus ini? Terima kasih.
PatrickT

16

Itu karena Anda mencemari namespace. Anda akan mengimpor semua fungsi dan kelas di namespace Anda sendiri, yang mungkin berbenturan dengan fungsi yang Anda tentukan sendiri.

Lebih jauh, saya pikir menggunakan nama yang berkualifikasi lebih jelas untuk tugas pemeliharaan; Anda melihat pada baris kode itu sendiri dari mana fungsi berasal, sehingga Anda dapat memeriksa dokumen dengan lebih mudah.

Dalam modul foo:

def myFunc():
    print 1

Dalam kode Anda:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2


9

Katakanlah Anda memiliki kode berikut dalam modul bernama foo:

import ElementTree as etree

dan kemudian dalam modul Anda sendiri, Anda memiliki:

from lxml import etree
from foo import *

Anda sekarang memiliki modul sulit-untuk-debug yang sepertinya memiliki lxml's etree di dalamnya, tetapi sebenarnya memiliki ElementTree sebagai gantinya.


7

Ini semua adalah jawaban yang bagus. Saya akan menambahkan bahwa ketika mengajar orang baru kode dengan Python, berurusan denganimport * sangat sulit. Bahkan jika Anda atau mereka tidak menulis kode, itu masih merupakan batu sandungan.

Saya mengajar anak-anak (sekitar 8 tahun) untuk memprogram dengan Python untuk memanipulasi Minecraft. Saya ingin memberi mereka lingkungan pengkodean yang bermanfaat untuk bekerja dengan ( Editor Atom ) dan mengajarkan pengembangan yang digerakkan oleh REPL (via bpython ). Dalam Atom saya menemukan bahwa petunjuk / penyelesaian berfungsi sama efektifnya dengan bpython. Untungnya, tidak seperti beberapa alat analisis statistik lainnya, Atom tidak tertipuimport * .

Namun, mari kita ambil contoh ini ... Dalam pembungkus ini mereka from local_module import *memiliki banyak modul termasuk daftar blok ini . Mari kita abaikan risiko tabrakan namespace. Dengan melakukan itu from mcpi.block import *mereka membuat seluruh daftar jenis blok yang tidak jelas ini sesuatu yang harus Anda perhatikan untuk mengetahui apa yang tersedia. Jika mereka malah digunakan from mcpi import block, maka Anda bisa mengetik walls = block.dan kemudian daftar autocomplete akan muncul. Tangkapan layar Atom.io


6

Memahami poin yang valid yang diletakkan orang di sini. Namun, saya punya satu argumen yang, kadang-kadang, "impor bintang" tidak selalu menjadi praktik yang buruk:

  • Ketika saya ingin menyusun kode saya sedemikian rupa sehingga semua konstanta pergi ke modul yang disebut const.py :
    • Jika saya melakukannya import const, maka untuk setiap konstanta, saya harus menyebutnya sebagai const.SOMETHING, yang mungkin bukan cara yang paling nyaman.
    • Jika aku melakukan from const import SOMETHING_A, SOMETHING_B ... , maka jelas itu terlalu bertele-tele dan mengalahkan tujuan penataan.
    • Jadi saya merasa dalam hal ini, melakukan from const import *mungkin pilihan yang lebih baik.

4

Ini adalah praktik yang sangat buruk karena dua alasan:

  1. Keterbacaan Kode
  2. Risiko mengungguli variabel / fungsi dll

Untuk poin 1 : Mari kita lihat contoh ini:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

Di sini, saat melihat kode tidak ada yang akan mendapatkan ide tentang dari modul mana b, cdand sebenarnya milik.

Di sisi lain, jika Anda suka:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

Ini jauh lebih bersih untuk Anda, dan orang baru yang bergabung dengan tim Anda akan memiliki ide yang lebih baik.

Untuk poin 2 : Misalkan keduanya module1dan module2memiliki variabel sebagai b. Ketika saya melakukannya:

from module1 import *
from module2 import *

print b  # will print the value from module2

Di sini nilai dari module1hilang. Akan sulit untuk men-debug mengapa kode tidak berfungsi meskipun bdinyatakan dalammodule1 dan saya telah menulis kode yang mengharapkan kode saya untuk digunakanmodule1.b

Jika Anda memiliki variabel yang sama di modul yang berbeda, dan Anda tidak ingin mengimpor seluruh modul, Anda bahkan dapat melakukan:

from module1 import b as mod1b
from module2 import b as mod2b

2

Sebagai tes, saya membuat module test.py dengan 2 fungsi A dan B, yang masing-masing mencetak "A 1" dan "B 1". Setelah mengimpor test.py dengan:

import test

. . . Saya dapat menjalankan 2 fungsi sebagai test.A () dan test.B (), dan "test" muncul sebagai modul di namespace, jadi jika saya mengedit test.py saya dapat memuatnya kembali dengan:

import importlib
importlib.reload(test)

Tetapi jika saya melakukan hal berikut:

from test import *

tidak ada referensi untuk "test" di namespace, jadi tidak ada cara untuk memuatnya kembali setelah diedit (sejauh yang saya tahu), yang merupakan masalah dalam sesi interaktif. Sedangkan salah satu dari yang berikut:

import test
import test as tt

akan menambahkan "test" atau "tt" (masing-masing) sebagai nama modul di namespace, yang akan memungkinkan memuat ulang.

Jika aku melakukan:

from test import *

nama "A" dan "B" muncul di namespace sebagai fungsi . Jika saya mengedit test.py, dan mengulangi perintah di atas, versi fungsi yang dimodifikasi tidak dimuat ulang.

Dan perintah berikut ini memunculkan pesan kesalahan.

importlib.reload(test)    # Error - name 'test' is not defined

Jika seseorang tahu cara memuat ulang modul yang memuat "from module import *", silakan kirim. Kalau tidak, ini akan menjadi alasan lain untuk menghindari formulir:

from module import *

2

Seperti yang disarankan dalam dokumen, Anda sebaiknya (hampir) tidak pernah menggunakan import *kode produksi.

Meskipun mengimpor *dari modul buruk, mengimpor * dari suatu paket bahkan lebih buruk. Secara default, from package import *mengimpor nama apa pun yang ditentukan oleh paket __init__.py, termasuk semua submodul dari paket yang dimuat sebelumnyaimport pernyataan .

Namun, jika __init__.pykode paket mendefinisikan daftar bernama __all__, itu diambil sebagai daftar nama submodule yang harus diimpor ketika from package import *ditemui.

Pertimbangkan contoh ini (dengan asumsi tidak ada __all__definisi dalam sound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

Pernyataan terakhir akan mengimpor echodan surroundmodul ke namespace saat ini (mungkin mengesampingkan definisi sebelumnya) karena mereka didefinisikan dalam sound.effectspaket ketika importpernyataan dieksekusi.

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.