'модуль імпорту' проти 'від функції імпорту модуля'


143

Я завжди використовував цей метод:

from sys import argv

і використовувати argvлише аргумент . Але існує умова використання цього:

import sys

і використовуючи argv by sys.argv

Другий метод робить код самодокументованим, і я (дійсно) його дотримуюся. Але я вважаю за краще перший метод - це швидкий той факт, що ми імпортуємо лише ту функцію, яка потрібна, а не імпортуємо весь модуль (який містить більше марних функцій, пітон яких витратить час на їх імпорт). Зауважте, що мені потрібні лише argv, а всі інші функції від sys мені марні.

Тож мої запитання є. Чи справді перший метод робить сценарій швидким? Якому методу найбільше перевагу? Чому?


2
Дивіться також stackoverflow.com/q/710551/321973
Tobias Kienzler

Повідомлення, пов’язані з цим - Розум from … import …синтаксису в Python
RBT

Відповіді:


175

Імпорт модуль не витрачає нічого ; модуль завжди повністю імпортується (у sys.modulesкартографування), тож ви використовуєте його import sysчи from sys import argvне створює жодних шансів.

Єдина різниця між двома твердженнями - це те, що ім'я пов'язане; import sysприв'язує ім'я sysдо модуля (так sys-> sys.modules['sys']), в той час як from sys import argvпов'язує інше ім'я argv, вказуючи прямо на атрибут, що міститься всередині модуля (так argv-> sys.modules['sys'].argv). Решта sysмодуля все ще є, ви використовуєте що-небудь ще з модуля чи ні.

Також немає різниці в ефективності між двома підходами. Так, sys.argvтреба шукати дві речі; він повинен шукати sysу вашому глобальному просторі імен (знаходить модуль), а потім шукати атрибут argv. І так, за допомогою from sys import argvви можете пропустити пошук атрибутів, оскільки у вас вже є пряме посилання на атрибут. Але importоператор все ж повинен виконувати цю роботу, він шукає той самий атрибут при імпорті, і вам потрібно буде використовувати argv колись один раз . Якщо вам довелося використовувати argvтисячі разів у циклі, це, можливо, призведе до зміни, але в цьому конкретному випадку це дійсно не відбувається.

Тоді вибір між тим чи іншим повинен базуватися на стилі кодування .

У великому модулі я б точно використовував import sys; документація коду має значення, а використання sys.argvдесь у великому модулі робить набагато зрозумілішим те, про що ви маєте на увазі, ніж будь- argvколи.

Якщо єдине місце, яке ви використовуєте, argv- це '__main__'блок для виклику main()функції, будь-яким чином використовуйте, from sys import argvякщо ви відчуваєте себе щасливішим:

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

Я б все одно користувався import sysтам сам. Якщо всі речі рівні (а саме вони, за рівнем продуктивності та кількістю символів, які використовуються для його написання), мені це просто простіше для очей.

Якщо ви імпортуєте щось інше взагалі, то, можливо, продуктивність приходить у гру. Але тільки якщо ви використовуєте певне ім'я в модулі багато разів , наприклад, у критичному циклі. Але тоді створення локальної назви (у межах функції) все одно буде швидше:

 import somemodule

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

1
Існує також ситуація, коли у вас є пакет із підпакетами або модулями, який розкриває атрибут одного з цих підпакетів / модулів у пакеті верхнього рівня. Використання from...importдозволяє робити це, package.attributeа не package.subpackage_or_module.attribute, що може бути корисно, якщо у вас є логічні або концептуальні групування в пакеті, але ви хочете зробити речі трохи зручнішими для користувачів вашого пакету. ( numpyя вважаю, щось подібне, я вважаю.)
JAB

У джанго у вас є багато плям, де такі речі from django.core.management.base import BaseCommandкраще, а все інше (особливо import django) призведе до нечитабельного коду. Тож як мені подобається ця відповідь, я думаю, що є деякі бібліотеки (і особливо деякі рамки), в яких конвенція полягає в порушенні чистого імпорту. Як завжди, використовуйте своє судження про те, що найкраще в тій чи іншій ситуації. Але помиляйтесь на стороні явного (іншими словами, я згоден здебільшого).
нейронет

1
@JAB: ви можете використовувати , import ... asщоб знайти пакет з іншим ім'ям: import package.subpackage_or_module as shortname. from parent import subробить, по суті, те саме.
Martijn Pieters

43

Є дві причини на користь використання, import moduleа не from module import function.

По-перше, це простір імен. Імпорт функції в глобальний простір імен ризикує зіткнення імен.

По-друге, це не стосується стандартних модулів, але важливо для ваших власних модулів, особливо під час розробки. Це варіант для reload()модуля. Врахуйте це:

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

З іншого боку

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

Що стосується швидкості ...

ми імпортуємо лише ту функцію, яка потрібна, а не імпортуємо весь модуль (який містить більше непотрібних функцій, які пітон витратить час на імпорт)

Незалежно від того, чи імпортуєте ви модуль чи імпортуєте функцію з модуля, Python проаналізує весь модуль. У будь-якому випадку імпортується модуль. "Імпорт функції" - це не що інше, як прив'язка функції до імені. Насправді import moduleменше роботи для перекладача, ніж from module import func.


6
reload () був вбудованим в Python 2; це вже не стосується Python 3.
Андре

Я думав, що також є наслідки, пов'язані з круговою залежністю від імпорту?
ADP

18

Я використовую from imports, коли це покращує читабельність. Наприклад, я віддаю перевагу (крапки з комою є лише для економії місця тут):

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

замість:

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

Останнє для мене важче читати (і писати), оскільки воно містить стільки зайвої інформації. Також корисно заздалегідь знати, які частини модуля я використовую.

Я віддаю перевагу регулярним imports, якщо я використовую багато коротких імен з модуля:

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

Або якщо ім’я настільки загальне, що воно не має сенсу поза його простором імен:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

Це моя улюблена відповідь. "Явне краще, ніж неявне", іноді конфліктує з читабельністю, простотою та сухістю. Особливо при використанні такої рамки, як Django.
нейронет

18

На мою думку, використання регулярних importполіпшує читабельність. Переглядаючи код Python, мені подобається бачити, звідки дана функція або клас походить саме там, де вона використовується. Це врятує мене від прокрутки до верхньої частини модуля, щоб отримати цю інформацію.

Щодо довгих назв модулів, я просто використовую asключове слово та даю їм короткі псевдоніми:

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

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

Як виняток, я завжди використовую from module import somethingпозначення, коли я маю справу з __future__модулем. Ви просто не можете зробити це іншим способом, коли ви хочете, щоб усі рядки були заздалегідь unicode в Python 2, наприклад

from __future__ import unicode_literals
from __future__ import print_function

Амінь! "import as" - виграшна комбінація :-)
paj28

4

Хоча import sysі from sys import agrvобидва імпортують весь sysмодуль, останній використовує прив'язку до імені, тому argvдля решти коду доступний лише модуль.

Для деяких людей це буде кращим стилем, оскільки він робить доступним лише ту функцію, яку ви прямо вказали.

Однак це вводить потенційні конфлікти імен. Що робити, якщо у вас був названий інший модуль argv? Зауважте, ви також можете явно імпортувати функцію та перейменувати за from sys import argv as sys_argvдопомогою конвенції, яка відповідає явній імпорту і є меншою ймовірністю зіткнення простору імен.


2
То як же if sys_argv:краще, ніж if sys.argv:? Я знаю, що означає друге твердження, я не маю поняття, що означає перша форма, не маючи зворотного зв'язку з химерним імпортом.
msw

1

Нещодавно я задав це питання собі. Я приурочував різні методи.

бібліотека запитів

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

красива бібліотека

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

json library

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

sys library

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

Мені здається, що є невелика різниця у виконанні.


Ви додаєте в пошуку атрибутів. Щоб порівняти import moduleз from module import nameправильно, додайте пошук цього імені до import moduleсправи. Наприклад, додайте рядок sys.argvдо arтесту і т. Д. Буде різниця, оскільки виконана робота дещо відрізняється, оскільки генерується різний байт-код і виконуються різні кодові шляхи.
Martijn Pieters

2
Зауважте, що я прямо вирішую цю різницю у своїй відповіді; буде різниця між використанням import sysпотім використанням sys.argvтисячі разів у циклі, а from sys import argvпотім просто використанням argv. Але ти цього не робиш. Для речей, які ви робите лише один раз на глобальному рівні вашого модуля, ви дійсно повинні оптимізувати читабельність, а не мікроскопічні відмінності в термінах.
Martijn Pieters

1
А-а-а! І я думав, що я на чомусь! :) Я лише обійняв вашу відповідь. Схоже, я стрибав пістолет на тому. Відчуває себе приниженим.
tmthyjames

-1

Переглядаючи опубліковані фрагменти коду, імпорт цілих модулів і посилання на них module.functionє майже стандартними, принаймні для стандартних модулів. Здається, єдиний винятокdatetime

from datetime import datetime, timedelta

тож можна сказати, datetime.now()а не datetime.datetime.now().

Якщо вас турбує ефективність роботи, ви завжди можете сказати (наприклад)

argv = sys.argv

а потім зробіть критичний код для вашої продуктивності, оскільки пошук модуля вже зроблений. Однак, хоча це буде працювати з функціями / методами, більшість IDE заплутаються і не будуть (наприклад) відображати джерельне посилання / підпис функції, коли вона призначена змінній.


-2

Я просто хочу додати, що якщо ти робиш щось подібне

from math import sin

(або будь-яку іншу вбудовану бібліотеку на кшталт sysабо posix), то sinвона буде включена в документацію для вашого модуля (тобто, коли ви це робите >>> help(mymodule)або $ pydoc3 mymodule.

import math
from math import sin as _sin

PS: вбудована бібліотека - це бібліотека, яка компілюється з коду С і входить до Python. argparse, osі ioне є вбудованими пакетами

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.