2008-10-11 34 views
70

Tôi hơi bối rối bởi vô số cách mà bạn có thể nhập mô-đun bằng Python.Quy tắc chung về nhập khẩu Python là gì?

import X 
import X as Y 
from A import B 

Tôi đã đọc về phạm vi và không gian tên, nhưng tôi muốn một số lời khuyên thực tế về chiến lược tốt nhất, theo hoàn cảnh và lý do gì. Việc nhập khẩu có nên xảy ra ở cấp mô-đun hoặc cấp phương pháp/chức năng không? Trong số __init__.py hoặc trong chính mã mô-đun?

Câu hỏi của tôi không thực sự được trả lời bởi "Python packages - import by class, not file" mặc dù nó rõ ràng là có liên quan.

+0

Xem http://stackoverflow.com/questions/187453/import-package-vs-import-packagespecifictype –

+0

Xem http://stackoverflow.com/questions/186472/from-x-import-a-versus-import -x-xa –

Trả lời

63

Trong mã sản xuất tại công ty chúng tôi, chúng tôi cố gắng làm theo các quy tắc sau đây.

Chúng tôi đặt hàng nhập khẩu vào đầu của tập tin, ngay sau khi docstring file chính, ví dụ:

""" 
Registry related functionality. 
""" 
import wx 
# ... 

Bây giờ, nếu chúng tôi nhập khẩu một lớp học đó là một trong số ít trong module nhập khẩu, chúng tôi nhập khẩu tên trực tiếp, do đó, trong mã, chúng tôi chỉ phải sử dụng phần cuối cùng, ví dụ:

from RegistryController import RegistryController 
from ui.windows.lists import ListCtrl, DynamicListCtrl 

Có các mô-đun, tuy nhiên, có chứa hàng chục lớp, ví dụ danh sách tất cả các ngoại lệ có thể. Sau đó chúng tôi nhập khẩu các mô-đun riêng của mình và tham chiếu đến nó trong các mã:

from main.core import Exceptions 
# ... 
raise Exceptions.FileNotFound() 

Chúng tôi sử dụng import X as Y như hiếm khi càng tốt, bởi vì nó làm cho tìm kiếm sử dụng một mô-đun hoặc lớp khó khăn đặc biệt. Đôi khi, tuy nhiên, bạn phải sử dụng nó nếu bạn muốn nhập khẩu hai lớp có cùng tên, nhưng tồn tại trong các module khác nhau, ví dụ:

from Queue import Queue 
from main.core.MessageQueue import Queue as MessageQueue 

Theo nguyên tắc chung, chúng ta không làm hàng nhập khẩu bên trong phương pháp - chúng đơn giản làm cho mã chậm hơn và ít đọc được hơn. Một số có thể thấy đây là cách tốt để dễ dàng giải quyết vấn đề nhập khẩu theo chu kỳ, nhưng giải pháp tốt hơn là sắp xếp lại mã.

+4

"chúng đơn giản làm cho mã chậm hơn" không đúng. Nó đã được thử nghiệm ở đây: http://stackoverflow.com/a/4789963/617185 – kmonsoor

12

Tôi thường sử dụng import X ở cấp mô-đun. Nếu bạn chỉ cần một đối tượng duy nhất từ ​​một mô-đun, hãy sử dụng from X import Y.

Chỉ sử dụng import X as Y trong trường hợp bạn đang đối mặt với xung đột tên.

tôi chỉ sử dụng nhập khẩu vào mức độ chức năng nhập khẩu những thứ tôi cần khi module được sử dụng như các mô-đun chính, như:

def main(): 
    import sys 
    if len(sys.argv) > 1: 
    pass 

HTH

0

import X as Y hữu ích nếu bạn có các triển khai khác nhau của cùng một mô-đun/lớp học.

Với một số lồng nhau try..import..except ImportError..import, bạn có thể ẩn việc triển khai khỏi mã của mình. Xem lxml etree import example:

try: 
    from lxml import etree 
    print("running with lxml.etree") 
except ImportError: 
    try: 
    # Python 2.5 
    import xml.etree.cElementTree as etree 
    print("running with cElementTree on Python 2.5+") 
    except ImportError: 
    try: 
     # Python 2.5 
     import xml.etree.ElementTree as etree 
     print("running with ElementTree on Python 2.5+") 
    except ImportError: 
     try: 
     # normal cElementTree install 
     import cElementTree as etree 
     print("running with cElementTree") 
     except ImportError: 
     try: 
      # normal ElementTree install 
      import elementtree.ElementTree as etree 
      print("running with ElementTree") 
     except ImportError: 
      print("Failed to import ElementTree from any known place") 
2

Tôi thường cố gắng sử dụng thường xuyên import modulename, trừ khi tên mô-đun là dài, hoặc sử dụng thường xuyên ..

Ví dụ, tôi sẽ làm gì ..

from BeautifulSoup import BeautifulStoneSoup as BSS 

..so tôi có thể làm soup = BSS(html) thay vì BeautifulSoup.BeautifulStoneSoup(html)

Hoặc ..

from xmpp import XmppClientBase 

..instead nhập khẩu toàn bộ của XMPP khi tôi chỉ sử dụng XmppClientBase

Sử dụng import x as y rất tiện lợi nếu bạn muốn nhập một trong hai tên phương thức rất dài hoặc để ngăn chặn hiện tượng nhập/biến/lớp/phương thức hiện có (như vậy mething bạn nên cố gắng tránh hoàn toàn, nhưng nó không phải luôn luôn có thể)

Nói rằng tôi muốn chạy một hàm main() từ kịch bản khác, nhưng tôi đã có một) chức năng (chính ..

from my_other_module import main as other_module_main 

..wouldn't thay thế chức năng main tôi với my_other_module của main

Oh, có một điều - không làm from x import * - nó làm cho mã của bạn rất khó hiểu, vì bạn không thể dễ dàng nhìn thấy nơi một phương pháp đến từ (from x import *; from y import *; my_func() - nơi my_func được định nghĩa?)

Trong mọi trường hợp, bạn có thể chỉ làm import modulename và sau đó làm modulename.subthing1.subthing2.method("test") ...

Những thứ from x import y as z hoàn toàn là để thuận tiện - sử dụng nó bất cứ khi nào nó sẽ làm cho mã của bạn dễ dàng hơn để đọc hoặc viết!

+2

IMHO, có một số quan niệm sai ở đây ... 1) * "nhập toàn bộ xmpp khi tôi chỉ sử dụng ..." *: này ngụ ý sai rằng phương pháp này là "nhẹ hơn", nhưng Python sẽ tải và khởi động toàn bộ mô-đun, bất kể bạn đã nhập bao nhiêu đối tượng. Đối với "ô nhiễm không gian tên", cả hai sẽ thêm một mục * duy nhất vào không gian tên cục bộ: 'xmpp' hoặc' XmppClientBase'. Vì vậy, lý do này không hợp lệ – MestreLion

+2

2) * "vì bạn không thể dễ dàng thấy phương thức xuất phát từ" *: True for * import, nhưng * cũng * đúng cho cách tiếp cận của bạn bằng cách sử dụng 'as' chỉ để rút ngắn tên mô-đun/đối tượng . 'BSS()' xuất phát từ đâu? Sử dụng 'from' cũng bị (một chút) của điều này:' từ mymod nhập MyClass'. Bây giờ 300 dòng phía trước bạn thấy 'lớp MyOtherClass (MyClass):' ... bây giờ, nơi mà MyClass đến từ một lần nữa? Người đọc buộc phải luôn quay trở lại tiêu đề để xem kiểm tra xem đối tượng nào được nhập từ – MestreLion

5

Những người khác đã bao phủ phần lớn mặt đất ở đây nhưng tôi chỉ muốn thêm một trường hợp tôi sẽ sử dụng import X as Y (tạm thời), khi tôi đang thử phiên bản mới của lớp học hoặc mô-đun. Vì vậy, nếu chúng tôi đang di chuyển sang triển khai mô-đun mới, nhưng không muốn cắt mã nguồn cùng một lúc, chúng tôi có thể viết mô-đun xyz_new và thực hiện việc này trong các tệp nguồn mà chúng tôi đã di chuyển :

import xyz_new as xyz 

sau đó, khi chúng ta cắt trên toàn bộ cơ sở mã, chúng tôi chỉ cần thay thế các mô-đun xyz với xyz_new và thay đổi tất cả các hàng nhập khẩu trở lại

import xyz 
+0

Bạn đã đánh tôi với nó. –

3

kHÔNG làm điều này:

from X import * 

trừ khi bạn hoàn toàn chắc chắn rằng bạn sẽ sử dụng mọi thứ trong mô-đun đó. Và thậm chí sau đó, bạn có lẽ nên xem xét lại bằng cách sử dụng một cách tiếp cận khác nhau.

Ngoài ra, đó chỉ là vấn đề về phong cách.

from X import Y 

là tốt và giúp bạn tiết kiệm rất nhiều đánh máy. Tôi có xu hướng sử dụng mà khi tôi đang sử dụng một cái gì đó ở trong đó khá thường xuyên Nhưng nếu bạn đang nhập khẩu rất nhiều từ mô-đun đó, bạn có thể kết thúc với một tuyên bố nhập khẩu trông như thế này:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P 

Bạn nhận được ý kiến.Đó là khi nhập khẩu như

import X 

trở nên hữu ích. Hoặc là hoặc nếu tôi không thực sự sử dụng bất cứ điều gì trong X rất thường xuyên.

+0

'từ lần nhập X *' không có sử dụng - ví dụ: với pyparsing. –

+0

Tôi đồng ý. Nhưng nói chung, nó không phải là một thói quen tốt để có được vào. Không có gì làm phiền tôi nhiều hơn là phải theo dõi chức năng nào đến từ mô-đun nào bởi vì có rất nhiều từ các câu lệnh kiểu x import *. –

34

Hãy để tôi chỉ cần dán một phần của cuộc hội thoại trên mailing list django-dev bắt đầu bởi Guido van Rossum:

[...] Ví dụ, nó là một phần của hướng dẫn phong cách Google Python [1] rằng tất cả nhập khẩu phải nhập một mô-đun, không phải lớp hoặc chức năng từ mô-đun đó. Có nhiều lớp và chức năng hơn các mô-đun , do đó, nhớ lại nơi một điều cụ thể xuất phát từ nhiều phần là dễ dàng hơn nếu nó được đặt trước bằng tên mô-đun. Thường thì nhiều mô-đun xảy ra để xác định những thứ có cùng tên - do đó, người đọc mã không phải quay lại đầu tệp để xem từ đó mô-đun tên đã cho được nhập.

Nguồn:http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

+0

IMO đây nên là cách ưa thích để đi về nhập khẩu mọi thứ, đặc biệt là trong các dự án lớn. –

1

Khi bạn có một thư viện tốt bằng văn bản, mà đôi khi là trường hợp trong python, anh nên chỉ nhập nó và sử dụng nó như nó. Thư viện được viết tốt có xu hướng lấy cuộc sống và ngôn ngữ của riêng nó, dẫn đến mã dễ đọc, nơi bạn hiếm khi tham khảo thư viện. Khi một thư viện được viết tốt, bạn không cần phải đổi tên hay bất cứ điều gì khác quá thường xuyên.

import gat 

node = gat.Node() 
child = node.children() 

Đôi khi bạn không thể viết theo cách này, hoặc sau đó bạn muốn gỡ bỏ mọi thứ từ thư viện bạn đã nhập.

from gat import Node, SubNode 

node = Node() 
child = SubNode(node) 

Đôi khi bạn làm điều này cho rất nhiều thứ, nếu chuỗi nhập của bạn tràn 80 cột, Đó là ý tưởng tốt để làm điều này:

from gat import (
    Node, SubNode, TopNode, SuperNode, CoolNode, 
    PowerNode, UpNode 
) 

Chiến lược tốt nhất là để giữ cho tất cả các hàng nhập khẩu trên đầu tệp. Được ưu tiên đặt hàng theo thứ tự bảng chữ cái, nhập khẩu-câu lệnh trước, sau đó từ các câu lệnh nhập.

Bây giờ tôi cho bạn biết tại sao đây là quy ước tốt nhất.

Python hoàn toàn có thể có một nhập tự động, mà sẽ nhìn từ nhập khẩu chính cho giá trị khi nó không thể được tìm thấy từ không gian tên chung. Nhưng đây không phải là một ý tưởng hay. Tôi giải thích ngay tại sao. Bên cạnh việc thực hiện phức tạp hơn việc nhập khẩu đơn giản, các lập trình viên sẽ không suy nghĩ quá nhiều về các sự cố và tìm ra nơi bạn nhập khẩu những thứ nên được thực hiện theo cách khác hơn là chỉ nhìn vào nhập khẩu.

Cần tìm hiểu các trường hợp là một lý do khiến mọi người ghét "từ ... nhập *". Một số ví dụ xấu mà bạn cần phải làm điều này tồn tại mặc dù, ví dụ opengl -wrappings.

Vì vậy, các định nghĩa nhập thực sự có giá trị như xác định depedencies của chương trình. Đó là cách bạn nên khai thác chúng. Từ đó bạn có thể nhanh chóng kiểm tra xem một số hàm lạ được nhập từ đâu.

0

Tôi với Jason trong thực tế không sử dụng

from X import * 

Nhưng trong trường hợp của tôi (tôi không phải là một chuyên gia lập trình, do đó, mã của tôi không đáp ứng được phong cách mã hóa quá tốt) Tôi thường làm trong các chương trình của tôi một tập tin với tất cả các hằng số như phiên bản chương trình, tác giả, thông báo lỗi và tất cả những thứ đó, vì vậy các tập tin chỉ định nghĩa, sau đó tôi thực hiện việc nhập khẩu

from const import * 

đó tiết kiệm cho tôi rất nhiều thời gian. Nhưng đó là tệp duy nhất có nhập đó, và đó là vì tất cả bên trong tệp đó chỉ là các khai báo biến.

Thực hiện loại nhập đó trong một tệp có các lớp và định nghĩa có thể hữu ích, nhưng khi bạn phải đọc mã, bạn dành nhiều thời gian để định vị các hàm và lớp.

8

Có người ở trên nói rằng

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P 

tương đương với

import X 

import X cho phép điều chỉnh trực tiếp đến A-P, trong khi from X import ... tạo ra các bản sao của A-P. Đối với from X import A..P bạn không nhận được cập nhật cho các biến nếu chúng được sửa đổi. Nếu bạn sửa đổi chúng, bạn chỉ sửa đổi bản sao của mình, nhưng X không biết về các sửa đổi của bạn.

Nếu A-P có chức năng, bạn sẽ không biết sự khác biệt.

+0

Cụ thể, nếu bạn muốn sử dụng 'mock' trong các bài kiểm tra đơn vị để giả sử 'X.A', thì nó chỉ hoạt động nếu bạn sử dụng' import X'. – RemcoGerlich

Các vấn đề liên quan