Không nên sử dụng import *
trong Python.
Bất cứ ai có thể xin vui lòng chia sẻ lý do cho điều đó, để tôi có thể tránh nó làm lần sau?
import *
không hoạt động với tôi ở vị trí đầu tiên trong Python 2 hoặc 3.
Không nên sử dụng import *
trong Python.
Bất cứ ai có thể xin vui lòng chia sẻ lý do cho điều đó, để tôi có thể tránh nó làm lần sau?
import *
không hoạt động với tôi ở vị trí đầu tiên trong Python 2 hoặc 3.
Câu trả lời:
Bởi vì nó đặt rất nhiều thứ vào không gian tên của bạn (có thể che khuất một số đối tượng khác từ lần nhập trước và bạn sẽ không biết về nó).
Bởi vì bạn không biết chính xác những gì được nhập và không thể dễ dàng tìm thấy từ mô-đun nào một thứ nhất định đã được nhập (khả năng đọc).
Bởi vì bạn không thể sử dụng các công cụ tuyệt vời như pyflakes
để phát hiện tĩnh các lỗi trong mã của mình.
numpy.any
bóng any
khi họ làm from numpy import *
hoặc một công cụ "hữu ích" làm điều đó cho họ.
import *
làm cho thứ tự của các import
câu lệnh trở nên quan trọng ... ngay cả đối với các mô-đun thư viện tiêu chuẩn thường không quan tâm đến thứ tự nhập . Một cái gì đó ngây thơ như bảng chữ cái các import
tuyên bố của bạn có thể phá vỡ kịch bản của bạn khi một nạn nhân trước đây của cuộc chiến nhập khẩu trở thành người sống sót duy nhất. (Ngay cả khi tập lệnh của bạn hoạt động ngay bây giờ và không bao giờ thay đổi, đôi khi nó có thể bị lỗi nếu mô-đun được nhập giới thiệu một tên mới thay thế cho tên bạn đang dựa vào.)
Theo Zen của Python :
Rõ ràng là tốt hơn so với ngầm.
... chắc chắn không thể tranh luận với điều đó, chắc chắn?
use strict
(JavaScript var
). Bên cạnh, dĩ nhiên Python không phải là lỗi chính tả (thực tế nó được gõ rất mạnh). Dù sao, ngay cả khi bạn đã đúng, điều này vẫn sẽ mâu thuẫn với Zen của Python, được trích dẫn trong câu trả lời này.
Bạn không vượt qua **locals()
chức năng, phải không?
Kể từ khi Python thiếu một "bao gồm" tuyên bố, và các self
tham số là rõ ràng, và nguyên tắc xác định phạm vi khá đơn giản, nó thường là rất dễ dàng để chỉ một ngón tay vào một biến và cho biết nơi đối tượng đó đến từ - mà không đọc các module khác và không có bất cứ loại nào của IDE (dù sao cũng bị giới hạn trong cách hướng nội, bởi thực tế ngôn ngữ rất năng động).
Sự import *
phá vỡ tất cả những điều đó.
Ngoài ra, nó có một khả năng cụ thể để che giấu lỗi.
import os, sys, foo, sqlalchemy, mystuff
from bar import *
Bây giờ, nếu mô-đun thanh có bất kỳ thuộc tính " os
", " mystuff
", v.v ..., chúng sẽ ghi đè lên các thuộc tính được nhập rõ ràng và có thể chỉ ra những thứ rất khác nhau. Xác định __all__
trong thanh thường là khôn ngoan - điều này nói rõ những gì sẽ được nhập hoàn toàn - nhưng vẫn khó theo dõi các đối tượng đến từ đâu, mà không đọc và phân tích mô-đun thanh và theo dõi nhập khẩu của nó . Một mạng lưới import *
là điều đầu tiên tôi sửa chữa khi tôi sở hữu một dự án.
Đừng hiểu lầm tôi: nếu import *
mất tích, tôi sẽ khóc để có nó. Nhưng nó phải được sử dụng cẩn thận. Một trường hợp sử dụng tốt là cung cấp giao diện mặt tiền trên một mô-đun khác. Tương tự như vậy, việc sử dụng các câu lệnh nhập có điều kiện hoặc nhập bên trong các không gian tên hàm / lớp, đòi hỏi một chút kỷ luật.
Tôi nghĩ trong các dự án từ trung bình đến lớn, hoặc các dự án nhỏ có nhiều người đóng góp, cần tối thiểu vệ sinh về mặt phân tích thống kê - chạy ít nhất là pyflakes hoặc thậm chí tốt hơn là một pylint được cấu hình đúng - để bắt một số loại lỗi trước đó chúng xảy ra
Tất nhiên vì đây là python - hãy thoải mái phá vỡ các quy tắc và khám phá - nhưng hãy cảnh giác với các dự án có thể tăng gấp 10 lần, nếu mã nguồn bị thiếu kỷ luật thì đó sẽ là một vấn đề.
execfile()
. May mắn thay, nó hiếm khi được sử dụng và đi trong 3.x.
**vars()
bao gồm toàn cầu nếu chức năng được gọi là trong một tập tin khác? : P
Đó là bởi vì bạn đang làm ô nhiễm không gian tên. Bạn sẽ nhập tất cả các hàm và các lớp trong không gian tên của riêng bạn, có thể xung đột với các hàm bạn tự xác định.
Hơn nữa, tôi nghĩ rằng việc sử dụng một tên đủ điều kiện rõ ràng hơn cho nhiệm vụ bảo trì; bạn thấy trên chính dòng mã nơi một hàm xuất phát, vì vậy bạn có thể kiểm tra các tài liệu dễ dàng hơn nhiều.
Trong mô-đun foo:
def myFunc():
print 1
Trong mã của bạn:
from foo import *
def doThis():
myFunc() # Which myFunc is called?
def myFunc():
print 2
http://docs.python.org/tutorial/modules.html
Lưu ý rằng nói chung, thực tế nhập
*
từ một mô-đun hoặc gói được tán thành, vì nó thường gây ra mã kém đọc .
Đây là tất cả các câu trả lời tốt. Tôi sẽ nói thêm rằng khi dạy người mới viết mã bằng Python, việc xử lý import *
rất khó khăn. Ngay cả khi bạn hoặc họ không viết mã, nó vẫn là một vấp ngã.
Tôi dạy trẻ em (khoảng 8 tuổi) lập trình bằng Python để thao túng Minecraft. Tôi muốn cung cấp cho họ một môi trường mã hóa hữu ích để làm việc với ( Trình soạn thảo nguyên tử ) và dạy phát triển dựa trên REPL (thông qua bpython ). Trong Atom tôi thấy rằng các gợi ý / hoàn thành hoạt động hiệu quả như bpython. May mắn thay, không giống như một số công cụ phân tích thống kê khác, Atom không bị lừa import *
.
Tuy nhiên, hãy lấy ví dụ này ... Trong trình bao bọc này, chúng có from local_module import *
một mô-đun bao gồm danh sách các khối này . Hãy bỏ qua nguy cơ va chạm không gian tên. Bằng cách from mcpi.block import *
họ làm cho toàn bộ danh sách các loại khối tối nghĩa này một cái gì đó mà bạn phải nhìn vào để biết những gì có sẵn. Nếu họ đã sử dụng thay vào đó from mcpi import block
, thì bạn có thể nhập walls = block.
và sau đó một danh sách tự động hoàn thành sẽ bật lên.
Hiểu những điểm hợp lệ mọi người đặt ở đây. Tuy nhiên, tôi có một lập luận rằng, đôi khi, "nhập sao" có thể không phải lúc nào cũng là một thực tiễn tồi:
const.py
:
import const
, thì với mỗi hằng số, tôi phải gọi nó là const.SOMETHING
, đó có lẽ không phải là cách thuận tiện nhất.from const import SOMETHING_A, SOMETHING_B ...
, thì rõ ràng nó quá dài dòng và đánh bại mục đích của cấu trúc.from const import *
có thể là một lựa chọn tốt hơn.Nó là một thực hành BAD rất vì hai lý do:
Đối với điểm 1 : Chúng ta hãy xem một ví dụ về điều này:
from module1 import *
from module2 import *
from module3 import *
a = b + c - d
Ở đây, khi nhìn thấy mã, sẽ không ai có ý tưởng về mô-đun nào b
, c
và d
thực sự thuộc về.
Mặt khác, nếu bạn làm như thế:
# 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
Nó sạch sẽ hơn nhiều đối với bạn, và người mới tham gia nhóm của bạn sẽ có ý tưởng tốt hơn.
Đối với điểm 2 : Hãy nói cả hai module1
và module2
có biến là b
. Khi tôi làm:
from module1 import *
from module2 import *
print b # will print the value from module2
Ở đây giá trị từ module1
bị mất. Sẽ khó gỡ lỗi tại sao mã không hoạt động ngay cả khi b
được khai báo trongmodule1
và tôi đã viết mã mong mã của tôi sử dụngmodule1.b
Nếu bạn có cùng một biến trong các mô-đun khác nhau và bạn không muốn nhập toàn bộ mô-đun, bạn thậm chí có thể làm:
from module1 import b as mod1b
from module2 import b as mod2b
Để thử nghiệm, tôi đã tạo một mô-đun test.txt với 2 chức năng A và B, tương ứng in "A 1" và "B 1". Sau khi nhập test.txt với:
import test
. . . Tôi có thể chạy 2 hàm là test.A () và test.B () và "test" hiển thị dưới dạng một mô-đun trong không gian tên, vì vậy nếu tôi chỉnh sửa test.txt tôi có thể tải lại bằng:
import importlib
importlib.reload(test)
Nhưng nếu tôi làm như sau:
from test import *
không có tham chiếu đến "kiểm tra" trong không gian tên, vì vậy không có cách nào để tải lại nó sau khi chỉnh sửa (theo như tôi có thể nói), đây là một vấn đề trong phiên tương tác. Trong khi một trong những điều sau đây:
import test
import test as tt
sẽ thêm "test" hoặc "tt" (tương ứng) làm tên mô-đun trong không gian tên, cho phép tải lại.
Nếu tôi làm:
from test import *
tên "A" và "B" hiển thị trong không gian tên dưới dạng hàm . Nếu tôi chỉnh sửa test.txt và lặp lại lệnh trên, các phiên bản sửa đổi của các chức năng sẽ không được tải lại.
Và lệnh sau gợi ra một thông báo lỗi.
importlib.reload(test) # Error - name 'test' is not defined
Nếu ai đó biết cách tải lại mô-đun được tải bằng "từ nhập mô-đun *", vui lòng gửi. Nếu không, đây sẽ là một lý do khác để tránh hình thức:
from module import *
Như được đề xuất trong các tài liệu, bạn nên (hầu như) không bao giờ sử dụng import *
trong mã sản xuất.
Trong khi nhập *
từ một mô-đun là xấu, nhập * từ một gói thậm chí còn tồi tệ hơn. Theo mặc định, from package import *
nhập bất kỳ tên nào được xác định bởi gói __init__.py
, bao gồm mọi mô hình con của gói đã được tải trước đóimport
câu lệnh .
Tuy nhiên, nếu __init__.py
mã của gói xác định một danh sách có tên __all__
, thì nó được coi là danh sách các tên mô hình con nên được nhập khi from package import *
gặp phải.
Xem xét ví dụ này (giả sử không có __all__
định nghĩa trong 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 *
Câu lệnh cuối cùng sẽ nhập các mô-đun echo
và surround
mô-đun vào không gian tên hiện tại (có thể ghi đè các định nghĩa trước đó) vì chúng được định nghĩa trong sound.effects
gói khi import
câu lệnh được thi hành.