2013-10-10 3 views
2

Я изучаю Python и сегодня, набирая код, я пытался решить, куда положить инструкцию import.Где импортировать?

Я могу поставить оператор импорта практически в любом месте, где бы он ни появлялся, но как это влияет на производительность, пространство имен и все остальное, что я еще не знаю?

ответ

3

Официальный GoodPractice это поставить все свои импорта в начале модуля или скрипта, начиная со стандартных Lib модулей/пакетов, то третья часть, то для конкретного проекта, ср http://www.python.org/dev/peps/pep-0008/#imports

Практически, иногда приходится отложить импорт в функцию в виде быстрого & грязного обходного пути для циклической зависимости (правильный способ решения круговой зависимости состоит в том, чтобы извлечь соответствующие части в другом модуле, но с некоторыми фреймворками вам может потребоваться обходное решение Q & D) ,

Отсрочка импорта в функцию для «характеристик» не является хорошей идеей ИМХО, но в очередной раз вам иногда приходится нарушать правила.

Импорт модуля на самом деле означает:

search the module_or_package in `sys.modules` 
if not found: 
    search the module_or_package_source in `sys.path` 
    if not found: 
     raise an ImportError 
    create a `module` instance from the module_or_package_source 
    # -> imply executing the top-level source code, which may raise anything 
    store the `module` instance in `sys.modules` 
bind the `module` name (or whatever name was imported from it) in the current namespace 

WRT/что «текущее пространство имен» означает, что это действительно так: пространство имен («глобальный», функция в «локальный» или тело class заявлении, в модуля), в котором Выполняется инструкция import. Вот простой сценарий со всеми тремя примерами:

try: 
    re 
except NameError, e: 
    print "name 're' is not yet defined in the module's namespace" 
    print "module namespace : %s" % globals() 

import re 
print "name 're' is now defined in the module's namespace" 
print "module namespace : %s" % globals() 


def foo(): 
    try: 
     os 
    except NameError, e: 
     print "name 'os' is not yet defined in the function's namespace" 
     print "function namespace : %s" % locals() 
     print "name 'os' is not defined in the module's namespace neither" 
     print "module namespace : %s" % globals() 

    import os 
    print "name 'os' is now defined in the function's namespace" 
    print "function namespace : %s" % locals() 
    print "name 'os' is still not defined in the module's namespace" 
    print "module namespace : %s" % globals() 

foo() 

print "After calling foo(), name 'os' is still not defined in the module's namespace" 
print "module namespace : %s" % globals() 

class Foo(object): 
    try: 
     os 
    except NameError, e: 
     print "name 'os' is not yet defined in the class namespace" 
     print "but we cannot inspect this namespace now so you have to take me on words" 
     print "but if you read the code you'll notice we can only get there if we have a NameError, so we have an indirect proof at least ;)" 
     print "name 'os' is not defined in the module's namespace neither obvisouly" 
     print "module namespace : %s" % globals() 

    import os 
    print "name 'os' is now defined in the class namespace" 
    print "we still cannot inspect this namespace now but wait..." 
    print "name 'os' is still not defined in the module's namespace neither" 
    print "module namespace : %s" % globals() 

print "class namespace is now accessible via Foo.__dict__" 
print "Foo.__dict__ is %s" % (Foo.__dict__) 
print "'os' is now an attribute of Foo - Foo.os = %s" % Foo.os 
print "name 'os' is still not defined in the module's namespace" 
print "module namespace : %s" % globals() 
+0

Я читаю это о пространствах имен python: http://www.diveintopython.net/html_processing/locals_and_globals.html Итак, когда вы ссылаетесь на «текущее пространство имен», вы ссылаетесь на «глобальное» пространство имен, а не на «локальное» пространство имен даже если он вызван изнутри функции? –

+0

@EmilDavtyan: нет, я имею в виду текущее пространство имен - то, где выполняется оператор импорта - независимо от того, что это (локаль объекта, глобальный класс оператора класса). –

+0

Посмотрите здесь простой сценарий об импорте и пространствах имен: http://pastie.org/8392105 –

3

Когда вы используете import, вы фактически выполняете его (модуль). Поэтому, если вы можете контролировать выполнение этого (например, вам нужно только import, если какое-то условие работает), тогда поместите его куда угодно.

if some_condition: 
    import foo 

Если вам всегда нужно (без условий), то положите его в начало файла.

Для начала я бы предложил всегда поставить инструкцию import в верхней части файла.

+3

Модуль выполнен только при первом импорте («первый» для текущего процесса Python). Затем он кэшируется в 'sys.modules', и последующий импорт будет выполнять только часть привязки пространства имен. –

0

Когда модуль сначала импортируется, Python ищет модуль и, если он найден, он создает объект модуля.

В зависимости от размера модуля и частоты, с которой он используется в коде, вы можете импортировать его раз и навсегда в верхней части файла или вы можете импортировать его, когда особое условие выполнено.

Системная память всегда ограничена. Если существует высокая вероятность того, что указанное условие для модуля будет выполнено в очень небольшом числе случаев, имеет смысл импортировать на основе проверки состояния.

Это может быть особенно полезно, если вам нужно импортировать в свой код несколько тяжелых модулей, каждый из которых будет хранить много памяти, но они необходимы в разных местах. Таким образом, вместо того, чтобы делать это как

import module1 
import module2 

def foo1() 
    module1.function() 
def foo2() 
    module2.function() 
foo1() 
foo2() 

Попробуйте что-то вроде

def foo1() 
    import module1 
    module1.function() 
def foo2() 
    import module2 
    module2.function() 
foo1() 
foo2() 

Если питон модули достаточно просты, то имеет смысл включить их в верхней части файла - это пути, кто-то, кто чтение кода также получает предварительное понимание того, какие все модули использует ваш текущий код.

0

Импорт обычно размещается в верхней части файла, как на других языках программирования. Наличие их всех вместе позволяет легко увидеть зависимости модуля с первого взгляда.

Однако, поскольку код import выполняет код модуля, это может быть дорогостоящая операция, и по этой причине вы иногда увидите импорт внутри функций. NLTK является заведомо тяжелый модуль, поэтому, когда я использую это, я иногда делаю

def _tokenize(text): 
    import nltk 
    return nltk.word_tokenize(text) 

def process_some_text(text): 
    if isinstance(text, basestring): 
     text = _tokenize(text) 
    # now do the actual processing 

Поскольку импорт кэшируются только первый вызов _tokenize делает импорт. Это также приводит к тому, что зависимость становится необязательной, поскольку import не предпринимается, пока вызывающий абонент не запросит соответствующие функции.

+1

На самом деле это «сделать зависимую опцию» на самом деле означает, что код будет терпеть неудачу в любое непредсказуемое время, а не при запуске процесса (это тот случай, когда все ваши импортники находятся на верхнем уровне). –

+0

@brunodesthuilliers: это может быть документировано, и «ImportError» можно поймать и перевести в более дружественное сообщение об ошибке. –

+0

да, но, по опыту, он просто разрушит процесс (никогда не видел, чтобы такой случай был явно документирован и не обрабатывался). –

0

Вы можете поместить его в любом месте в файле до, который вы используете.Вы должныне обычно помещают его в циклы (как это не будет делать то, что вы ожидаете), но может положить его в условные обозначения. Когда выполняется инициализационный код импортированных модулей, вы можете сэкономить немного времени, просто загрузив его, если вы знаете, что он вам понадобится.

Вы могут включить его в функции, но если в функции, то это будет только в пределах этой функции. например

>>> def f1(): 
... import sys 
... print sys.version 
... 
>>> def f2(): 
... print sys.version 
... 
>>> f2() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in f2 
NameError: global name 'sys' is not defined 
>>> f1() 
2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] 
>>> f2() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in f2 
NameError: global name 'sys' is not defined 
>>> 

Хорошее соглашение, которое следует соблюдать, - это разместить его в верхней части файлов, чтобы он всегда был доступен и легко найти.

Вы также можете найти, особенно для тестирования компонентов пакета, которые могут потребоваться для изменения sys.path до импорта, чтобы его можно было импортировать на ранней стадии.

Соглашение Я лично считаю полезным, чтобы все ваши системы импортировались сначала, а затем импортировали пакеты проекта, а затем местный импорт с соответствующими комментариями между ними.

Если вы importимя_модуля, fromмодульimportподмодуль или importмодульasпсевдоним затем импортировать заказ не должен делать никаких серьезных различий но если вы fromмодульimport * затем все ставки не учитываются as var то модули могут определять одно и то же имя, а последнее - то, что вы получаете - это лишь одна из причин, по которым он не поощряется.

+2

Модуль выполняется только один раз при первом импорте («первый» для текущего процесса Python). Затем он кэшируется в 'sys.modules', и последующий импорт будет выполнять только часть привязки пространства имен. –

+0

@brunodesthuilliers - Причина, по которой я сказал _should_, не состояла в том, что это случай, когда код не будет делать то, на что похоже. –

+2

Я просто уточнил, что «как выполняется инициализационный код импортированных модулей» утверждение - немало новичков считают, что 'import' будет каждый раз перезагружать/выполнять модуль (или работает как директива #include или еще что-то). –

Смежные вопросы