'mô-đun nhập' so với 'từ chức năng nhập mô-đun'


143

Tôi đã luôn luôn sử dụng phương pháp này:

from sys import argv

và sử dụng argvvới chỉ argv . Nhưng có một quy ước sử dụng này:

import sys

và sử dụng argv bởi sys.argv

Phương thức thứ hai làm cho mã tự ghi lại và tôi (thực sự) tuân thủ nó. Nhưng lý do tôi thích phương pháp đầu tiên là vì nó nhanh vì chúng ta chỉ nhập hàm cần thiết chứ không phải nhập toàn bộ mô-đun (chứa nhiều hàm vô dụng hơn mà python sẽ lãng phí thời gian nhập chúng). Lưu ý rằng tôi chỉ cần argv và tất cả các chức năng khác từ sys là vô dụng đối với tôi.

Vì vậy, câu hỏi của tôi là. Liệu phương pháp đầu tiên thực sự làm cho kịch bản nhanh? Phương pháp nào được ưa thích nhất? Tại sao?



Câu trả lời:


175

Nhập khẩu mô-đun không lãng phí bất cứ điều gì ; mô-đun luôn được nhập đầy đủ (vào sys.modulesánh xạ), do đó, khi bạn sử dụng import syshoặc from sys import argvkhông có tỷ lệ cược.

Sự khác biệt duy nhất giữa hai câu lệnh là tên nào bị ràng buộc; import sysliên kết tên sysvới mô-đun (so sys-> sys.modules['sys']), trong khi from sys import argvliên kết một tên khác argv, chỉ thẳng vào thuộc tính có trong mô-đun (vì vậy argv-> sys.modules['sys'].argv). Phần còn lại của sysmô-đun vẫn còn đó, cho dù bạn có sử dụng bất cứ thứ gì khác từ mô-đun hay không.

Cũng không có sự khác biệt hiệu suất giữa hai phương pháp. Vâng, sys.argvphải tìm kiếm hai điều; nó phải tra cứu systrong không gian tên toàn cầu của bạn (tìm mô-đun), sau đó tra cứu thuộc tính argv. Và có, bằng cách sử dụng, from sys import argvbạn có thể bỏ qua việc tra cứu thuộc tính, vì bạn đã có một tham chiếu trực tiếp đến thuộc tính. Nhưng importcâu lệnh vẫn phải thực hiện công việc đó, nó tìm kiếm thuộc tính tương tự khi nhập và bạn sẽ chỉ cần sử dụng argv một lần . Nếu bạn phải sử dụng argvhàng ngàn lần trong một vòng lặp thì có lẽ điều đó có thể tạo ra sự khác biệt, nhưng trong trường hợp cụ thể này thì thực sự không phải vậy.

Thay vào đó, sự lựa chọn giữa cái này hay cái khác, nên dựa trên phong cách mã hóa .

Trong một mô-đun lớn , tôi chắc chắn sẽ sử dụng import sys; mã tài liệu quan trọng, và sử dụng sys.argvmột nơi nào đó trong một mô-đun lớn làm cho nó rõ ràng hơn những gì bạn đang đề cập đến hơn argvbao giờ hết.

Nếu nơi duy nhất bạn sử dụng argvlà trong một '__main__'khối để gọi một main()hàm, bằng mọi cách, hãy sử dụng from sys import argvnếu bạn cảm thấy hạnh phúc hơn về điều đó:

if __name__ == '__main__':
    from sys import argv
    main(argv)

Tôi vẫn sẽ sử dụng import sysở đó một mình. Tất cả mọi thứ đều bình đẳng (và chính xác là về hiệu suất số lượng ký tự được sử dụng để viết nó), điều đó dễ dàng hơn đối với tôi.

Nếu bạn đang nhập một cái gì đó khác hoàn toàn, thì có lẽ hiệu suất sẽ phát huy tác dụng. Nhưng chỉ khi bạn sử dụng một tên cụ thể trong một mô-đun nhiều lần , trong một vòng lặp quan trọng chẳng hạn. Nhưng sau đó, việc tạo một tên cục bộ (trong một hàm) sẽ nhanh hơn:

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)

1
Ngoài ra còn có tình huống bạn có một gói với các gói con hoặc mô-đun lộ ra một thuộc tính của một trong những gói / mô-đun đó trong gói cấp cao nhất. Việc sử dụng from...importcho phép bạn thực hiện package.attributethay vì package.subpackage_or_module.attribute, điều này có thể hữu ích nếu bạn có các nhóm logic hoặc khái niệm trong gói nhưng muốn làm cho mọi thứ thuận tiện hơn một chút cho người dùng gói của bạn. ( numpytôi làm điều gì đó như thế này, tôi tin thế.)
JAB

Trong django, bạn có vô số điểm mà mọi thứ như from django.core.management.base import BaseCommandtốt hơn, và bất cứ điều gì khác (đặc biệt import django) sẽ dẫn đến mã không thể đọc được. Vì vậy, trong khi tôi thích câu trả lời này, tôi nghĩ rằng có một số thư viện (và đặc biệt là một số khung công tác) trong đó quy ước là vi phạm nhập khẩu trần. Như mọi khi, sử dụng phán đoán của bạn về những gì tốt nhất trong một tình huống nhất định. Nhưng lỗi về phía rõ ràng (nói cách khác tôi đồng ý phần lớn).
nơ ron

1
@JAB: bạn vẫn có thể sử dụng import ... asđể tìm gói đến một tên khác : import package.subpackage_or_module as shortname. from parent import subkhông, về cơ bản, điều tương tự.
Martijn Pieters

43

Có hai lý do có lợi cho việc sử dụng import modulehơn là from module import function.

Đầu tiên là không gian tên. Nhập một hàm vào không gian tên toàn cầu có nguy cơ va chạm tên.

Thứ hai là không liên quan đến các mô-đun tiêu chuẩn, nhưng có ý nghĩa đối với các mô-đun của riêng bạn, đặc biệt là trong quá trình phát triển. Đó là tùy chọn cho reload()một mô-đun. Xem xét điều này:

from module import func
...
reload(module)
# func still points to the old code

Mặt khác

import module
...
reload(module)
# module.func points to the new code

Còn về tốc độ ...

chúng tôi chỉ nhập chức năng cần thiết chứ không nhập toàn bộ mô-đun (chứa nhiều chức năng vô dụng hơn mà python sẽ lãng phí thời gian nhập chúng)

Cho dù bạn nhập mô-đun hoặc nhập hàm từ mô-đun, Python sẽ phân tích toàn bộ mô-đun. Cả hai cách mô-đun được nhập khẩu. "Nhập một chức năng" không gì khác hơn là ràng buộc chức năng với một tên. Trong thực tế import modulelà công việc ít hơn cho phiên dịch viên from module import func.


6
tải lại () là một nội dung trong Python 2; đó không còn là trường hợp của Python 3.
André

Tôi nghĩ rằng cũng có ý nghĩa để làm với phụ thuộc nhập khẩu tròn?
ADP

18

Tôi sử dụng from imports bất cứ khi nào nó cải thiện khả năng đọc. Ví dụ: tôi thích (dấu chấm phẩy chỉ để tiết kiệm không gian ở đây):

from collections import defaultdict
from foomodule import FooBar, FooBaz
from twisted.internet.protocol import Factory
defaultdict(); FooBar(); FooBaz(); Factory()

thay vì:

import collections
import foomodule
import twisted.internet.protocol
collections.defaultdict(); foomodule.FooBar(); foomodule.FooBaz()
twisted.internet.protocol.Factory()

Cái sau khó đọc hơn (và viết) đối với tôi vì nó chứa quá nhiều thông tin dư thừa. Ngoài ra, thật hữu ích khi biết trước những phần tôi đang sử dụng.

Tôi thích imports thường xuyên nếu tôi sử dụng nhiều tên ngắn từ một mô-đun:

import sys
sys.argv; sys.stderr; sys.exit()

Hoặc nếu một tên quá chung chung đến nỗi nó không có ý nghĩa ngoài không gian tên của nó:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

Đây là câu trả lời yêu thích của tôi. 'Rõ ràng là tốt hơn so với ngầm' đôi khi mâu thuẫn với khả năng đọc, đơn giản và DRY. Đặc biệt là khi sử dụng một khung như Django.
nơ ron

18

Theo tôi sử dụng thường xuyên importcải thiện khả năng đọc. Khi xem lại mã Python, tôi thích xem hàm hoặc lớp đã cho đến từ đâu được sử dụng. Nó tiết kiệm cho tôi từ việc cuộn lên đầu mô-đun để có được thông tin đó.

Đối với tên mô-đun dài, tôi chỉ sử dụng astừ khóa và đặt cho chúng các bí danh ngắn:

import collections as col
import foomodule as foo
import twisted.internet.protocol as twip

my_dict = col.defaultdict()
foo.FooBar()
twip_fac = twip.Factory()

Như một ngoại lệ, tôi luôn sử dụng from module import somethingký hiệu khi giao dịch với __future__mô-đun. Bạn không thể làm theo cách khác khi bạn muốn tất cả các chuỗi được unicode theo mặc định trong Python 2, ví dụ:

from __future__ import unicode_literals
from __future__ import print_function

Amen! "Nhập dưới dạng" là sự kết hợp chiến thắng :-)
pyjama

4

Mặc dù import sysfrom sys import agrvcả hai nhập toàn bộ sysmô-đun, cái sau sử dụng liên kết tên để chỉ có argvthể truy cập mô-đun vào phần còn lại của mã.

Đối với một số người, đây sẽ là phong cách ưa thích vì nó chỉ giúp truy cập chức năng mà bạn đã nêu rõ ràng.

Tuy nhiên, nó giới thiệu xung đột tên tiềm năng. Điều gì nếu bạn có một mô-đun khác được đặt tên argv? Lưu ý rằng bạn cũng có thể nhập hàm và đổi tên from sys import argv as sys_argvmột cách rõ ràng, một quy ước đáp ứng nhập rõ ràng và ít có khả năng đưa ra các xung đột không gian tên.


2
Vậy làm thế nào là if sys_argv:tốt hơn if sys.argv:? Tôi biết câu lệnh thứ hai có nghĩa là gì, tôi không biết hình thức đầu tiên có nghĩa là gì mà không quay lại nhập khẩu kỳ quái.
msw

1

Gần đây tôi đã hỏi câu hỏi này với chính mình. Tôi hẹn giờ với các phương pháp khác nhau.

yêu cầu thư viện

def r():
    import requests
    return 'hello'
timeit r() # output: 1000000 loops, best of 3: 1.55 µs per loop

def rg():
    from requests import get
    return 'hello'
timeit rg() # output: 100000 loops, best of 3: 2.53 µs per loop

thư viện beautifulsoup

def bs():
    import bs4
    return 'hello' 
timeit bs() # output: 1000000 loops, best of 3: 1.53 µs per loop

def be():
    from bs4 import BeautifulSoup
    return 'hello'
timeit be() # output: 100000 loops, best of 3: 2.59 µs per loop

thư viện json

def js():
    import json
    return 'hello'
timeit js() # output: 1000000 loops, best of 3: 1.53 µs per loop

def jl():
    from json import loads
    return 'hello'
timeit jl() # output: 100000 loops, best of 3: 2.56 µs per loop

thư viện sys

def s():
    import sys
    return 'hello'
timeit s() # output: 1000000 loops, best of 3: 1.55 µs per loop

def ar():
    from sys import argv
    return 'hello'
timeit ar() # output: 100000 loops, best of 3: 2.87 µs per loop

Dường như với tôi một chút khác biệt trong hiệu suất.


Bạn đang thêm vào một tra cứu thuộc tính. Để so sánh import modulevới from module import namechính xác, thêm tra cứu tên đó vào import moduletrường hợp. Ví dụ như thêm dòng sys.argvvào arthử nghiệm, vv Vẫn sẽ là một sự khác biệt, bởi vì những việc đã làm là một chút khác nhau, như bytecode khác nhau được tạo ra và codepaths khác nhau được thực hiện.
Martijn Pieters

2
Lưu ý rằng tôi trực tiếp giải quyết sự khác biệt đó trong câu trả lời của tôi; sẽ có một sự khác biệt giữa việc sử dụng import syssau đó sử dụng sys.argvhàng ngàn thời gian trong một vòng lặp so với from sys import argvsau đó chỉ sử dụng argv. Nhưng bạn thì không. Đối với những việc bạn làm chỉ một lần ở cấp độ toàn cầu của mô-đun, bạn thực sự nên tối ưu hóa để dễ đọc, không phải là sự khác biệt vi mô về thời gian.
Martijn Pieters

1
À! Và tôi nghĩ rằng tôi đã vào một cái gì đó! :) Tôi chỉ lướt qua câu trả lời của bạn. Hình như tôi đã nhảy súng vào đó. Cảm thấy tốt để được khiêm tốn.
tmthyjames

-1

Nhìn vào các đoạn mã được xuất bản, nhập toàn bộ các mô-đun và tham khảo gần như module.functionlà tiêu chuẩn, ít nhất là cho các mô-đun tiêu chuẩn. Một ngoại lệ dường như làdatetime

from datetime import datetime, timedelta

vì vậy bạn có thể nói datetime.now()chứ không phải datetime.datetime.now().

Nếu bạn lo lắng về hiệu suất, bạn luôn có thể nói (ví dụ)

argv = sys.argv

và sau đó thực hiện mã quan trọng hiệu suất của bạn vì việc tra cứu mô-đun đã được thực hiện. Tuy nhiên, mặc dù điều này sẽ hoạt động với các hàm / phương thức, hầu hết các IDE sẽ bị lẫn lộn và sẽ không (ví dụ) hiển thị một liên kết / chữ ký nguồn cho hàm khi nó được gán cho một biến.


-2

Tôi chỉ muốn thêm rằng nếu bạn làm một cái gì đó như

from math import sin

(hoặc bất kỳ thư viện tích hợp nào khác như syshoặc posix), sau đó sinsẽ được bao gồm trong tài liệu cho mô-đun của bạn (tức là khi bạn làm >>> help(mymodule)hoặc $ pydoc3 mymodule. Để tránh điều này, hãy nhập bằng:

import math
from math import sin as _sin

PS: một thư viện tích hợp là một thư viện được biên dịch từ mã C và được kèm theo Python. argparse, osiokhông được xây dựng-in gói

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.