Sử dụng 'mô-đun nhập' hoặc 'từ nhập mô-đun'?


411

Tôi đã cố gắng tìm một hướng dẫn toàn diện về việc sử dụng nó là tốt nhất import modulehay from module import? Tôi mới bắt đầu với Python và tôi đang cố gắng bắt đầu với những thực tiễn tốt nhất trong tâm trí.

Về cơ bản, tôi đã hy vọng nếu có ai có thể chia sẻ kinh nghiệm của họ, những nhà phát triển khác có sở thích gì và cách tốt nhất để tránh bất kỳ vấn đề nào xảy ra?


5
Tôi chỉ muốn cho bạn biết, rằng câu trả lời được chọn là sai. Nó nói rằng sự khác biệt là chủ quan trong khi có sự khác biệt. Điều này có thể có thể dẫn đến khó phát hiện lỗi. Xem câu trả lời của Michael Ray Lovetts.
Mayou36


2
Có một sự khác biệt giữa việc nhập các định danh cụ thể có tên 'from module import X,Y,Zso với'from module import * . Cái sau gây ô nhiễm không gian tên của bạn và có thể cho kết quả không thể đoán trước tùy thuộc vào những gì đang diễn ra trong mô-đun. Tệ hơn nữa là đang làm from module import *với nhiều mô-đun.
smci

Câu trả lời:


474

Sự khác biệt giữa import modulefrom module import foochủ yếu là chủ quan. Chọn một trong những bạn thích nhất và nhất quán trong việc sử dụng nó. Dưới đây là một số điểm để giúp bạn quyết định.

import module

  • Ưu điểm:
    • Ít bảo trì importbáo cáo của bạn . Không cần thêm bất kỳ nhập khẩu bổ sung nào để bắt đầu sử dụng một mục khác từ mô-đun
  • Nhược điểm:
    • Nhập module.foomã của bạn có thể tẻ nhạt và dư thừa (tedium có thể được giảm thiểu bằng cách sử dụng import module as mosau đó nhập mo.foo)

from module import foo

  • Ưu điểm:
    • Ít gõ hơn để sử dụng foo
    • Kiểm soát nhiều hơn các mục của mô-đun có thể được truy cập
  • Nhược điểm:
    • Để sử dụng một mục mới từ mô-đun, bạn phải cập nhật importtuyên bố của mình
    • Bạn mất bối cảnh về foo. Ví dụ, nó không rõ ràng ceil()so với những gìmath.ceil()

Hoặc là phương pháp được chấp nhận, nhưng không sử dụng from module import *.

Đối với bất kỳ bộ mã lớn hợp lý nào, nếu bạn import *có thể sẽ gắn nó vào mô-đun, không thể xóa được. Điều này là do khó xác định mục nào được sử dụng trong mã đến từ 'mô-đun', giúp bạn dễ dàng đi đến điểm mà bạn nghĩ rằng bạn không sử dụng importnữa nhưng cực kỳ khó chắc chắn.


66
+1 để không khuyến khích sử dụng "từ nhập mô-đun *", nó chỉ làm xáo trộn không gian tên.
Christian Witts

22
làm lộn xộn không gian tên không phải là phần rắc rối nhất của "nhập *", đó là giảm khả năng đọc: Bất kỳ xung đột tên nào sẽ hiển thị trong thử nghiệm (đơn vị). Nhưng tất cả các tên bạn sử dụng từ mô-đun nhập khẩu sẽ trống, với một gợi ý là chúng đến từ. Tôi hoàn toàn không thích "nhập *".
Jürgen A. Erhard

21
Không phải Zen của Python nói rõ ràng là tốt hơn ngầm?
Antony Koch

8
from module import *có thể đặc biệt hữu ích, nếu sử dụng nó như : if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *. Sau đó, mô đun mẹ của bạn có khả năng chứa các tên hàm độc lập của hệ điều hành, nếu các tên hàm trong module_lin & module_win có cùng tên. Nó giống như điều kiện kế thừa một trong hai lớp.
anishsane

19
@ biến mất. Có một cách khác để làm điều đó. nhập module_win như một cái gì đó. Sau đó, luôn luôn sử dụng cái gì
đó.method_name

163

Có một chi tiết khác ở đây, không được đề cập, liên quan đến việc ghi vào một mô-đun. Cấp điều này có thể không phổ biến lắm, nhưng thỉnh thoảng tôi cần nó.

Do cách tham chiếu và ràng buộc tên hoạt động trong Python, nếu bạn muốn cập nhật một số biểu tượng trong một mô-đun, giả sử foo.bar, từ bên ngoài mô-đun đó và có mã nhập khác "xem" thay đổi đó, bạn phải nhập foo a Một cách chắc chắn. Ví dụ:

mô-đun foo:

bar = "apples"

mô-đun a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

mô đun b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

Tuy nhiên, nếu bạn nhập tên biểu tượng thay vì tên mô-đun, điều này sẽ không hoạt động.

Ví dụ: nếu tôi làm điều này trong mô-đun a:

from foo import bar
bar = "oranges"

Không có mã bên ngoài nào sẽ thấy thanh là "cam" vì cài đặt thanh của tôi chỉ ảnh hưởng đến tên "thanh" bên trong mô-đun a, nó không "chạm vào" đối tượng mô-đun foo và cập nhật "thanh" của nó.


Với ví dụ cuối cùng đó, bạn vẫn có thể gọi 'foo.bar = "cam"' để cập nhật 'thanh' bên trong 'foo' chứ?
Velocirabbit

4
Không, trong ví dụ trước, tên 'foo' không xác định
Ghislain Leveque

31
Câu trả lời NÀY cung cấp câu trả lời "đúng" cho câu hỏi: sự khác biệt giữa hai biến thể nhập khẩu
Mayou36

3
Đã viết một số đoạn để chứng minh câu trả lời này là hoàn toàn đúng, nhưng lý do đằng sau này là gì?
huangbeidu

Tôi nghĩ những gì bạn đang nói là nhập tên biểu tượng để có biến cục bộ nhưng nhập tên mô-đun để có biến toàn cục ???
WinEunuuchs2Unix 17/12/18

79

Mặc dù nhiều người đã giải thích về importvs import from, tôi muốn cố gắng giải thích thêm một chút về những gì xảy ra dưới mui xe và nơi tất cả những nơi nó thay đổi.


import foo:

Nhập khẩu foovà tạo một tham chiếu đến mô-đun đó trong không gian tên hiện tại. Sau đó, bạn cần xác định đường dẫn mô-đun đã hoàn thành để truy cập một thuộc tính hoặc phương thức cụ thể từ bên trong mô-đun.

Vd foo.barnhưng khôngbar

from foo import bar:

Nhập khẩu foovà tạo tài liệu tham khảo cho tất cả các thành viên được liệt kê ( bar). Không đặt biến foo.

Vd barnhưng không bazhayfoo.baz

from foo import *:

Nhập khẩu foovà tạo tham chiếu đến tất cả các đối tượng công khai được xác định bởi mô-đun đó trong không gian tên hiện tại (mọi thứ được liệt kê trong __all__nếu __all__tồn tại, nếu không thì mọi thứ không bắt đầu bằng _). Không đặt biến foo.

Ví dụ barbazkhông _quxhoặc foo._qux.


Bây giờ hãy xem khi chúng ta làm import X.Y:

>>> import sys
>>> import os.path

Kiểm tra sys.modulesvới tên osos.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Kiểm tra globals()và ký tự locals()không gian tên với osos.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

Từ ví dụ trên, chúng tôi thấy rằng chỉ osđược chèn vào không gian tên cục bộ và toàn cầu. Vì vậy, chúng ta sẽ có thể sử dụng:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

Nhưng không phải path.

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Khi bạn xóa oskhông gian tên từ locals (), bạn sẽ không thể truy cập oscũng như os.pathmặc dù chúng tồn tại trong sys.modules:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Bây giờ hãy nói về import from:

from:

>>> import sys
>>> from os import path

Kiểm tra sys.modulesvới osos.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Chúng tôi thấy rằng trong sys.moduleschúng tôi đã tìm thấy giống như chúng tôi đã làm trước đây bằng cách sử dụngimport name

OK, chúng ta hãy kiểm tra xem nó trông như thế nào trong locals()và các globals()không gian tên:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

Bạn có thể truy cập bằng cách sử dụng tên pathkhông phải bởi os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Hãy xóa 'đường dẫn' khỏi locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Một ví dụ cuối cùng sử dụng bí danh:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

Và không có đường dẫn xác định:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

8
Trong khi đây là dài dòng, đây thực sự là câu trả lời tốt nhất trong danh sách cho một câu hỏi khá phức tạp. Nó cung cấp mã thực tế để giúp giải thích các phần phụ "dưới mui xe", quan trọng hơn kiểu, đối với vấn đề cụ thể này. Tôi ước tôi có thể nâng cao nó hơn một lần!
Mike Williamson

Có sử dụng as SYMBOLthay đổi làm thế nào câu trả lời này hoạt động ở tất cả?
Maximilian Burszley

40

Cả hai cách đều được hỗ trợ vì một lý do: có những lúc một cách phù hợp hơn cách khác.

  • import module: tốt đẹp khi bạn đang sử dụng nhiều bit từ mô-đun. Hạn chế là bạn sẽ cần đủ điều kiện mỗi tham chiếu với tên mô-đun.

  • from module import ...: rất vui khi các mục đã nhập có thể sử dụng trực tiếp mà không cần tiền tố tên mô-đun. Hạn chế là bạn phải liệt kê từng thứ bạn sử dụng và không rõ ràng về mã nguồn từ đâu.

Việc sử dụng nào phụ thuộc vào việc làm cho mã rõ ràng và dễ đọc, và có nhiều hơn một chút để làm với sở thích cá nhân. Tôi nghiêng về phía import modulenói chung bởi vì trong mã, nó rất rõ ràng một đối tượng hoặc chức năng đến từ đâu. Tôi sử dụng from module import ...khi tôi đang sử dụng một số đối tượng / chức năng rất nhiều trong mã.


1
Có cách nào để sử dụng from M import Xvà vẫn nhận được lợi ích của việc sử dụng vòng loại bằng cách nào đó không? Có vẻ như bạn có thể có được điều tốt nhất của cả hai thế giới nếu bạn vẫn có thể làm M.Xsau lần nhập đó.
động vật chân đốt

@artgropod: Kinda. Bạn có thể làm class m: from something.too.long import x, y, z. Sẽ không thực sự khuyên điều đó mặc dù.
Lie Ryan

35

Cá nhân tôi luôn sử dụng

from package.subpackage.subsubpackage import module

và sau đó truy cập mọi thứ như

module.function
module.modulevar

v.v ... Lý do là cùng một lúc bạn có lệnh gọi ngắn và bạn xác định rõ ràng không gian tên mô-đun của mỗi thường trình, một điều rất hữu ích nếu bạn phải tìm kiếm việc sử dụng một mô-đun nhất định trong nguồn của mình.

Không cần phải nói, không sử dụng nhập *, vì nó gây ô nhiễm không gian tên của bạn và nó không cho bạn biết chức năng đã cho đến từ đâu (từ mô-đun nào)

Tất nhiên, bạn có thể gặp rắc rối nếu bạn có cùng tên mô-đun cho hai mô-đun khác nhau trong hai gói khác nhau, như

from package1.subpackage import module
from package2.subpackage import module

trong trường hợp này, tất nhiên bạn gặp rắc rối, nhưng sau đó có một gợi ý mạnh mẽ rằng bố cục gói của bạn bị sai sót, và bạn phải suy nghĩ lại về nó.


10
Trong trường hợp cuối cùng, bạn luôn có thể sử dụng: nhập pkgN.sub.module làm modN cung cấp cho bạn các tên riêng biệt cho mỗi mô-đun. Bạn cũng có thể sử dụng mẫu 'nhập tên mô-đun dưới dạng mod1' để rút ngắn tên dài hoặc để chuyển đổi giữa các lần triển khai của cùng một API (ví dụ: các mô-đun API DB) với một thay đổi tên duy nhất.
Jeff Shannon

15
import module

Là tốt nhất khi bạn sẽ sử dụng nhiều chức năng từ các mô-đun.

from module import function

Là tốt nhất khi bạn muốn tránh gây ô nhiễm không gian tên toàn cầu với tất cả các chức năng và loại từ một mô-đun khi bạn chỉ cần function.


7
Chắc chắn điều duy nhất trong không gian tên toàn cầu nếu bạn 'nhập mô-đun' là 'mô-đun'? Bạn chỉ làm ô nhiễm không gian tên nếu bạn làm 'từ .. nhập *'.
John Fouhy

10

Tôi vừa phát hiện ra một sự khác biệt tinh tế hơn giữa hai phương pháp này.

Nếu mô-đun foosử dụng nhập sau:

from itertools import count

Sau đó, mô-đun barcó thể do sử dụng nhầm countnhư thể nó được xác định trong foo, không phải trong itertools:

import foo
foo.count()

Nếu foosử dụng:

import itertools

sai lầm vẫn có thể xảy ra, nhưng ít có khả năng được thực hiện. barcần phải:

import foo
foo.itertools.count()

Điều này gây ra một số rắc rối cho tôi. Tôi đã có một mô-đun do nhầm lẫn đã nhập một ngoại lệ từ một mô-đun không xác định nó, chỉ nhập nó từ mô-đun khác (sử dụng from module import SomeException). Khi việc nhập không còn cần thiết và loại bỏ, mô-đun vi phạm đã bị hỏng.


10

Đây là một sự khác biệt không được đề cập. Điều này được sao chép nguyên văn từ http://docs.python.org/2/tutorial/modules.html

Lưu ý rằng khi sử dụng

from package import item

mục này có thể là một mô hình con (hoặc gói con) của gói hoặc một số tên khác được định nghĩa trong gói, như hàm, lớp hoặc biến. Câu lệnh nhập trước tiên kiểm tra xem mục có được xác định trong gói không; nếu không, nó giả sử nó là một mô-đun và cố gắng tải nó. Nếu không tìm thấy nó, một ngoại lệ ImportError được đưa ra.

Ngược lại, khi sử dụng cú pháp như

import item.subitem.subsubitem

mỗi mục ngoại trừ cuối cùng phải là một gói; mục cuối cùng có thể là một mô-đun hoặc một gói nhưng không thể là một lớp hoặc hàm hoặc biến được định nghĩa trong mục trước đó.


Một điều nữa tôi nhận thấy là nếu mục cũng là một mô hình con bên trong gói thì "từ mục nhập gói" hoạt động nhưng "gói nhập" gói.item.subitem = ... không hoạt động với gói init .py của gói, trừ khi chúng ta có "mục nhập" trong tệp init của gói.
Amitoz Dandiana

6

Vì tôi cũng là người mới bắt đầu, tôi sẽ cố gắng giải thích điều này một cách đơn giản: Trong Python, chúng tôi có ba loại importcâu lệnh là:

1. Nhập khẩu chung:

import math

kiểu nhập này là sở thích cá nhân của tôi, nhược điểm duy nhất của kỹ thuật nhập này là nếu bạn cần sử dụng bất kỳ chức năng nào của mô-đun, bạn phải sử dụng cú pháp sau:

math.sqrt(4)

tất nhiên, nó làm tăng nỗ lực gõ nhưng khi mới bắt đầu, nó sẽ giúp bạn theo dõi mô-đun và chức năng liên quan đến nó (một trình soạn thảo văn bản tốt sẽ giảm đáng kể nỗ lực gõ và được khuyến nghị).

Nỗ lực gõ có thể được giảm thêm bằng cách sử dụng câu lệnh nhập này:

import math as m

bây giờ, thay vì sử dụng math.sqrt()bạn có thể sử dụng m.sqrt().

2. Nhập khẩu chức năng:

from math import sqrt

kiểu nhập này phù hợp nhất nếu mã của bạn chỉ cần truy cập một hoặc một vài chức năng từ mô-đun, nhưng để sử dụng bất kỳ mục mới nào từ mô-đun, bạn phải cập nhật câu lệnh nhập.

3. Nhập khẩu phổ quát:

from math import * 

Mặc dù nó làm giảm đáng kể nỗ lực gõ nhưng không được khuyến khích vì nó sẽ điền mã của bạn với các hàm khác nhau từ mô-đun và tên của chúng có thể xung đột với tên của các hàm do người dùng xác định. thí dụ:

Nếu bạn có một hàm của sqrt có tên rất riêng của bạn và bạn nhập toán học, thì hàm của bạn an toàn: có sqrt của bạn và có math.sqrt. Tuy nhiên, nếu bạn thực hiện nhập toán học *, bạn có một vấn đề: cụ thể là hai hàm khác nhau có cùng tên chính xác. Nguồn: Codecademy


5
import package
import module

Với import, mã thông báo phải là một mô-đun (một tệp chứa các lệnh Python) hoặc một gói (một thư mục trong sys.pathtệp chứa tệp __init__.py.)

Khi có các gói con:

import package1.package2.package
import package1.package2.module

các yêu cầu đối với thư mục (gói) hoặc tệp (mô-đun) là như nhau, nhưng thư mục hoặc tệp phải ở bên trong package2phải ở bên trong package1và cả hai package1package2phải chứa __init__.pytệp. https://docs.python.org/2/tutorial/modules.html

Với fromphong cách nhập khẩu:

from package1.package2 import package
from package1.package2 import module

gói hoặc mô-đun nhập vào không gian tên của tệp chứa importcâu lệnh dưới dạng module(hoặc package) thay vì package1.package2.module. Bạn luôn có thể liên kết với một tên thuận tiện hơn:

a = big_package_name.subpackage.even_longer_subpackage_name.function

Chỉ fromkiểu nhập cho phép bạn đặt tên cho một chức năng hoặc biến cụ thể:

from package3.module import some_function

được cho phép, nhưng

import package3.module.some_function 

không được phép.


4

Để thêm vào những gì mọi người đã nói về from x import *: bên cạnh việc làm cho việc đặt tên từ đâu trở nên khó khăn hơn, điều này sẽ loại bỏ các trình kiểm tra mã như Pylint. Họ sẽ báo cáo những tên đó là các biến không xác định.


3

Câu trả lời của riêng tôi cho vấn đề này phụ thuộc chủ yếu vào đầu tiên, tôi sẽ sử dụng bao nhiêu mô-đun khác nhau. Nếu tôi chỉ sử dụng một hoặc hai, tôi sẽ thường sử dụng from... importvì nó tạo ra ít lần nhấn phím hơn trong phần còn lại của tệp, nhưng nếu tôi sẽ sử dụng nhiều mô-đun khác nhau, tôi chỉ thích importbởi vì điều đó có nghĩa là mỗi tham chiếu mô-đun là tự ghi lại. Tôi có thể thấy mỗi biểu tượng đến từ đâu mà không phải săn lùng xung quanh.

Usuaully Tôi thích kiểu tự ghi tài liệu của nhập đơn giản và chỉ thay đổi từ .. nhập khi số lần tôi phải nhập tên mô-đun tăng lên trên 10 đến 20, ngay cả khi chỉ có một mô-đun được nhập.


1

Một trong những khác biệt đáng kể mà tôi phát hiện ra là điều đáng ngạc nhiên không ai nói đến là việc sử dụng nhập khẩu đơn giản mà bạn có thể truy cập private variableprivate functionstừ mô-đun đã nhập, điều này không thể thực hiện được với câu lệnh nhập khẩu .

nhập mô tả hình ảnh ở đây

Mã trong hình ảnh:

cài đặt

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

từ_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

0

Mô-đun nhập - Bạn không cần nỗ lực bổ sung để lấy thứ khác từ mô-đun. Nó có nhược điểm như gõ thừa

Nhập mô-đun từ - Nhập ít hơn & Kiểm soát nhiều hơn các mục của mô-đun có thể được truy cập. Để sử dụng một mục mới từ mô-đun, bạn phải cập nhật câu lệnh nhập của mình.


0

Có một số mô-đun dựng sẵn chứa hầu hết các hàm trần ( base64 , math , os , shutil , sys , time , ...) và chắc chắn nên sử dụng các hàm trần này liên kết với một số không gian tên và do đó cải thiện khả năng đọc của bạn mã. Xem xét mức độ khó hơn để hiểu ý nghĩa của các hàm này mà không có không gian tên của chúng:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

hơn khi chúng bị ràng buộc với một số mô-đun:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

Đôi khi, bạn thậm chí cần không gian tên để tránh xung đột giữa các mô-đun khác nhau ( json.load so với pickle.load )


Mặt khác, có một số mô-đun chứa hầu hết các lớp ( configparser , datetime , tempfile , zipfile , ...) và nhiều trong số chúng làm cho tên lớp của chúng đủ tự giải thích:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

do đó, có thể có một cuộc tranh luận về việc sử dụng các lớp này với không gian tên mô-đun bổ sung trong mã của bạn có thêm một số thông tin mới hay chỉ kéo dài mã.


0

Tôi muốn thêm vào điều này, có một số điều cần xem xét trong các cuộc gọi nhập khẩu:

Tôi có cấu trúc như sau:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

chính:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis cho thấy sự khác biệt:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

Cuối cùng, chúng trông giống nhau (STORE_NAME là kết quả trong mỗi ví dụ), nhưng điều này đáng chú ý nếu bạn cần xem xét bốn lần nhập vòng tròn sau:

ví dụ 1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

Những công việc này

ví dụ2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

Không có con xúc xắc

ví dụ3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

Vấn đề tương tự ... nhưng rõ ràng từ x nhập y không giống như nhập nhập xy như y

ví dụ4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

Cái này cũng hoạt động


0

Đây là cấu trúc thư mục của thư mục hiện tại của tôi:

.  
└─a  
   └─b  
     └─c
  1. Các importtuyên bố nhớ tất cả các tên trung gian .
    Những tên này phải đủ điều kiện:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. Câu from ... import ...lệnh chỉ nhớ tên đã nhập .
    Tên này phải không đủ điều kiện:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • Lưu ý: Tất nhiên, tôi đã khởi động lại bàn điều khiển Python giữa các bước 1 và 2.

0

Như Jan Wrobel đề cập, một khía cạnh của hàng nhập khẩu khác nhau là cách thức nhập khẩu được tiết lộ.

Mô-đun mymath

from math import gcd
...

Sử dụng mymath :

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

Nếu tôi gcdchỉ nhập để sử dụng nội bộ, không tiết lộ cho người dùng mymath, điều này có thể gây bất tiện. Tôi có điều này khá thường xuyên, và trong hầu hết các trường hợp tôi muốn "giữ cho các mô-đun của mình sạch sẽ".

Ngoài đề xuất của Jan Wrobel để che giấu điều này nhiều hơn một chút bằng cách sử dụng import maththay vào đó, tôi đã bắt đầu che giấu việc nhập khẩu khỏi tiết lộ bằng cách sử dụng dấu gạch dưới hàng đầu:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

Trong các dự án lớn hơn, "thực tiễn tốt nhất" này cho phép tôi kiểm soát chính xác những gì được tiết lộ cho các lần nhập tiếp theo và những gì không. Điều này giữ cho các mô-đun của tôi sạch sẽ và trả lại ở một quy mô dự án nhất định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.