แนะนำให้ไม่ใช้import *
ใน Python
ใครช่วยกรุณาแบ่งปันเหตุผลเพื่อที่ฉันสามารถหลีกเลี่ยงได้ในครั้งต่อไป?
import *
ไม่ทำงานสำหรับฉันตั้งแต่แรกใน Python 2 หรือ 3
แนะนำให้ไม่ใช้import *
ใน Python
ใครช่วยกรุณาแบ่งปันเหตุผลเพื่อที่ฉันสามารถหลีกเลี่ยงได้ในครั้งต่อไป?
import *
ไม่ทำงานสำหรับฉันตั้งแต่แรกใน Python 2 หรือ 3
คำตอบ:
เพราะมันทำให้สิ่งต่าง ๆ มากมายใน namespace ของคุณ (อาจเงาวัตถุอื่น ๆ จากการนำเข้าก่อนหน้านี้และคุณจะไม่ทราบเกี่ยวกับมัน)
เนื่องจากคุณไม่ทราบว่าสิ่งใดที่นำเข้ามาและไม่สามารถหาได้ง่ายว่าโมดูลใดที่นำเข้าบางสิ่ง (อ่านได้)
เพราะคุณไม่สามารถใช้เครื่องมือเจ๋ง ๆ เช่นpyflakes
ตรวจจับข้อผิดพลาดในรหัสของคุณได้
numpy.any
เงาany
เมื่อพวกเขาทำfrom numpy import *
หรือเครื่องมือ "มีประโยชน์" ทำเพื่อพวกเขา
import *
ทำให้ลำดับของimport
ข้อความสั่งสำคัญ ... แม้สำหรับโมดูลไลบรารีมาตรฐานที่ไม่สนใจสั่งนำเข้า . บางสิ่งที่ไร้เดียงสาเหมือนการเรียงimport
ข้อความของคุณอาจทำให้สคริปต์ของคุณเสียหายเมื่ออดีตผู้บาดเจ็บจากสงครามการนำเข้ากลายเป็นผู้รอดชีวิตเพียงคนเดียว (แม้ว่าสคริปต์ของคุณจะทำงานได้ในขณะนี้และไม่เคยเปลี่ยนแปลง แต่มันก็อาจล้มเหลวได้ในภายหลังหากโมดูลที่นำเข้ามีชื่อใหม่ซึ่งมาแทนที่ชื่อที่คุณใช้)
use strict
(JavaScript var
) แน่นอนว่า Python นั้นไม่ได้เป็นแบบพิมพ์ดีด อย่างไรก็ตามแม้ถ้าคุณมีสิทธินี้จะยังคงขัดแย้งกับเซนของงูใหญ่, อ้างในคำตอบนี้
คุณไม่ผ่าน**locals()
ฟังก์ชั่นใช่มั้ย
เนื่องจากงูใหญ่ขาด "รวม" คำสั่งและself
พารามิเตอร์ที่ชัดเจนและกฎระเบียบที่กำหนดขอบเขตค่อนข้างง่ายก็มักจะง่ายมากที่จะชี้ที่ตัวแปรและบอกที่วัตถุที่มาจาก - โดยไม่ต้องอ่านโมดูลอื่น ๆ และไม่มีการใด ๆ ของ IDE (ซึ่งมีข้อ จำกัด ในทางของการวิปัสสนาต่อไปโดยความจริงแล้วภาษาเป็นแบบไดนามิกมาก)
การimport *
แบ่งทั้งหมดนั้น
นอกจากนี้ยังมีความเป็นไปได้ที่จะซ่อนข้อบกพร่องอย่างเป็นรูปธรรม
import os, sys, foo, sqlalchemy, mystuff
from bar import *
ตอนนี้หากโมดูลบาร์มีแอตทริบิวต์" os
", " mystuff
", ฯลฯ ... ใด ๆ พวกเขาจะแทนที่คนที่นำเข้าอย่างชัดเจนและอาจชี้ไปที่สิ่งที่แตกต่างกันมาก กำหนด__all__
ในแถบมักจะฉลาด - รัฐนี้สิ่งปริยายจะถูกนำเข้า - แต่ก็ยังยากที่จะติดตามวัตถุที่มาจากโดยไม่ต้องอ่านและแยกโมดูลบาร์และต่อไปนี้ของการนำเข้า เครือข่ายของimport *
เป็นสิ่งแรกที่ฉันแก้ไขเมื่อฉันเป็นเจ้าของโครงการ
อย่าเข้าใจฉันผิด: ถ้าimport *
คนที่หายไปฉันจะร้องไห้เพื่อที่จะได้มัน แต่จะต้องมีการใช้อย่างระมัดระวัง กรณีการใช้งานที่ดีคือการจัดหาส่วนต่อประสานส่วนหน้าผ่านโมดูลอื่น ในทำนองเดียวกันการใช้คำสั่งนำเข้าแบบมีเงื่อนไขหรืออิมพอร์ตภายในเนมสเปซฟังก์ชัน / คลาสต้องใช้วินัยเล็กน้อย
ฉันคิดว่าในโครงการขนาดกลางถึงใหญ่หรือโครงการขนาดเล็กที่มีผู้สนับสนุนหลายคนจำเป็นต้องมีสุขอนามัยขั้นต่ำในแง่ของการวิเคราะห์ทางสถิติ - ทำงานอย่างน้อย pyflakes หรือดีกว่า pylint ที่ตั้งค่าไว้อย่างถูกต้อง - เพื่อดักจับแมลงหลายชนิดก่อน พวกเขาเกิดขึ้น
แน่นอนเพราะนี่คือ python อย่าลังเลที่จะทำลายกฎและสำรวจ - แต่ระวังโครงการที่อาจเติบโตเป็นสิบเท่าหากซอร์สโค้ดไม่มีระเบียบวินัยมันจะเป็นปัญหา
execfile()
มันเรียกว่า โชคดีที่มันไม่ค่อยได้ใช้และหายไปใน 3.x
**vars()
ที่จะรวม Globals ถ้าฟังก์ชั่นที่เรียกว่าอยู่ในแฟ้มอื่นได้หรือไม่ : P
ไม่เป็นไรที่จะทำfrom ... import *
ในเซสชันโต้ตอบ
doctest
สตริง? การimport *
ตีความถูกตีความใน "กล่องทราย" ในกรณีนี้หรือไม่? ขอบคุณ
นั่นเป็นเพราะคุณกำลังสร้างมลภาวะให้กับเนมสเปซ คุณจะนำเข้าฟังก์ชั่นและคลาสทั้งหมดในเนมสเปซของคุณเองซึ่งอาจขัดแย้งกับฟังก์ชันที่คุณกำหนดเอง
นอกจากนี้ฉันคิดว่าการใช้ชื่อที่ผ่านการรับรองมีความชัดเจนมากขึ้นสำหรับงานบำรุงรักษา คุณเห็นบรรทัดโค้ดที่มีฟังก์ชันมาจากคุณจึงสามารถตรวจสอบเอกสารได้ง่ายขึ้น
ในโมดูลฟู:
def myFunc():
print 1
ในรหัสของคุณ:
from foo import *
def doThis():
myFunc() # Which myFunc is called?
def myFunc():
print 2
http://docs.python.org/tutorial/modules.html
โปรดทราบว่าโดยทั่วไปการปฏิบัติของนำเข้า
*
จากโมดูลหรือแพคเกจขมวดคิ้วเพราะมันมักจะทำให้เกิดรหัสที่อ่านได้ไม่ดี
สมมติว่าคุณมีรหัสต่อไปนี้ในโมดูลที่ชื่อว่า foo:
import ElementTree as etree
และจากนั้นในโมดูลของคุณเองคุณมี:
from lxml import etree
from foo import *
ตอนนี้คุณมีโมดูลที่ยากต่อการดีบักซึ่งดูเหมือนว่ามันมี etree ของ lxml แต่มี ElementTree แทน
ทั้งหมดนี้เป็นคำตอบที่ดี ฉันจะเพิ่มว่าเมื่อสอนคนใหม่ให้เขียนโค้ดใน Python การจัดการกับimport *
มันยากมาก แม้ว่าคุณหรือพวกเขาไม่ได้เขียนรหัสก็ยังคงเป็นบล็อกสะดุด
ฉันสอนเด็ก ๆ (อายุประมาณ 8 ปี) ให้เข้าร่วมโปรแกรมใน Python เพื่อจัดการ Minecraft ฉันต้องการให้สภาพแวดล้อมการเข้ารหัสที่เป็นประโยชน์แก่พวกเขาในการทำงานกับ ( Atom Editor ) และสอนการพัฒนาที่ขับเคลื่อนด้วย REPL (ผ่านbpython ) ใน Atom ฉันพบว่าคำใบ้ / ความสำเร็จนั้นทำงานได้อย่างมีประสิทธิภาพเหมือนกับ bpython โชคดีที่ไม่เหมือนที่อื่นเครื่องมือในการวิเคราะห์บางสถิติ Atom import *
จะไม่หลงกลโดย
แต่จะช่วยให้ตัวอย่างนี้ ... ในนี้เสื้อคลุมพวกเขาfrom local_module import *
โมดูลพวงรวมทั้งรายชื่อของบล็อกนี้ ลองเพิกเฉยต่อความเสี่ยงของการชนกันของ namespace การทำเช่นfrom mcpi.block import *
นี้ทำให้รายการทั้งหมดของประเภทบล็อกที่ไม่ชัดเจนซึ่งคุณต้องดูเพื่อดูว่ามีอะไรบ้าง หากพวกเขาใช้แทนคุณfrom mcpi import block
สามารถพิมพ์walls = block.
แล้วรายการเติมข้อความอัตโนมัติจะปรากฏขึ้น
ทำความเข้าใจกับคะแนนที่ถูกต้องที่ผู้คนใส่ไว้ที่นี่ อย่างไรก็ตามฉันมีอาร์กิวเมนต์หนึ่งที่บางครั้ง "การนำเข้าดาว" อาจไม่ใช่วิธีที่ไม่ดีเสมอไป:
const.py
:
import const
นั้นสำหรับทุกค่าคงที่ฉันต้องอ้างอิงมันconst.SOMETHING
ซึ่งอาจไม่ใช่วิธีที่สะดวกที่สุดfrom const import SOMETHING_A, SOMETHING_B ...
แล้วเห็นได้ชัดว่ามันเป็นวิธีการ verbose เกินไปและเอาชนะวัตถุประสงค์ของการสร้างfrom const import *
อาจเป็นทางเลือกที่ดีกว่ามันเป็นวิธีปฏิบัติที่ไม่ดีมากด้วยเหตุผลสองประการ:
สำหรับจุดที่ 1 : มาดูตัวอย่างของสิ่งนี้:
from module1 import *
from module2 import *
from module3 import *
a = b + c - d
นี่เห็นรหัสไม่มีใครจะได้รับความคิดเกี่ยวกับการที่โมดูลb
, c
และd
จริงเป็น
ในทางกลับกันถ้าคุณทำเช่นนั้น:
# 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
มันสะอาดกว่าสำหรับคุณและคนใหม่ที่เข้าร่วมทีมของคุณจะมีความคิดที่ดีกว่า
สำหรับจุดที่ 2 : ให้พูดทั้งสองmodule1
และมีตัวแปรmodule2
b
เมื่อฉันทำ:
from module1 import *
from module2 import *
print b # will print the value from module2
ค่าที่นี่module1
สูญเสียไป มันจะยากที่จะแก้ปัญหาว่าทำไมรหัสไม่ทำงานแม้ว่าb
จะมีการประกาศในmodule1
และฉันได้เขียนรหัสคาดว่ารหัสของฉันที่จะใช้module1.b
หากคุณมีตัวแปรเดียวกันในโมดูลที่ต่างกันและคุณไม่ต้องการนำเข้าทั้งโมดูลคุณอาจทำได้:
from module1 import b as mod1b
from module2 import b as mod2b
เป็นการทดสอบฉันสร้างโมดูล test.py ด้วย 2 ฟังก์ชัน A และ B ซึ่งพิมพ์ "A 1" และ "B 1" ตามลำดับ หลังจากนำเข้า test.py ด้วย:
import test
. . . ฉันสามารถเรียกใช้ฟังก์ชัน 2 อย่างเป็น test.A () และ test.B () และ "test" แสดงเป็นโมดูลในเนมสเปซดังนั้นหากฉันแก้ไข test.py ฉันสามารถโหลดซ้ำได้ด้วย:
import importlib
importlib.reload(test)
แต่ถ้าฉันทำต่อไปนี้:
from test import *
ไม่มีการอ้างอิงถึง "ทดสอบ" ในเนมสเปซดังนั้นจึงไม่มีวิธีการโหลดซ้ำหลังจากแก้ไข (เท่าที่ฉันสามารถบอกได้) ซึ่งเป็นปัญหาในเซสชันแบบโต้ตอบ ในขณะที่อย่างใดอย่างหนึ่งต่อไปนี้:
import test
import test as tt
จะเพิ่ม "test" หรือ "tt" (ตามลำดับ) เป็นชื่อโมดูลในเนมสเปซซึ่งจะอนุญาตให้โหลดซ้ำได้
ถ้าฉันทำ:
from test import *
ชื่อ "A" และ "B" จะปรากฏในเนมสเปซเป็นฟังก์ชันฟังก์ชั่นถ้าฉันแก้ไข test.py และทำซ้ำคำสั่งข้างต้นฟังก์ชั่นเวอร์ชั่นที่แก้ไขจะไม่ได้รับการโหลดซ้ำ
และคำสั่งต่อไปนี้จะแสดงข้อความแสดงข้อผิดพลาด
importlib.reload(test) # Error - name 'test' is not defined
หากมีคนรู้วิธีโหลดโมดูลที่โหลดด้วย "จากโมดูลนำเข้า *" โปรดโพสต์ มิฉะนั้นจะเป็นอีกเหตุผลหนึ่งที่หลีกเลี่ยงฟอร์ม:
from module import *
ตามที่แนะนำในเอกสารคุณไม่ควรใช้ (เกือบ) import *
ในรหัสการผลิต
ในขณะที่การนำเข้า*
จากโมดูลไม่ดีการนำเข้า * จากแพคเกจยิ่งแย่กว่านั้น โดยค่าเริ่มต้นfrom package import *
การนำเข้าชื่อใดก็ตามที่กำหนดโดยแพ็คเกจ__init__.py
รวมถึง submodules ของแพ็คเกจที่โหลดโดยimport
คำสั่งก่อนหน้า
อย่างไรก็ตามหาก__init__.py
รหัสของแพคเกจกำหนดรายการชื่อ__all__
มันจะถูกนำไปเป็นรายการของชื่อ submodule ที่ควรนำเข้าเมื่อfrom package import *
พบ
ลองพิจารณาตัวอย่างนี้ (สมมติว่าไม่มีการ__all__
กำหนดไว้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 *
คำสั่งสุดท้ายจะนำเข้าecho
และsurround
โมดูลลงใน namespace ปัจจุบัน (อาจแทนที่คำนิยามก่อนหน้า) เพราะพวกเขาจะถูกกำหนดในsound.effects
แพคเกจเมื่อimport
คำสั่งจะถูกดำเนินการ