Математический анализ. 3е издание
Скачать 4.86 Mb.
|
543 загрузит модуль, находящийся на том же уровне в иерархии катало гов, что и пакет mypkg, – то есть модуль spam, находящийся в каталоге, родительском по отношению к пакету mypkg. В общем случае действия программного кода в модуле A.B.C будут следующими: from . import D # Импортирует A.B.D from .. import E # Импортирует A.E from ..F import G # Импортирует A.F.G Синтаксис относительного импорта и предложенные изменения по использованию «абсолютного импорта по умолчанию» – это достаточ но сложные концепции, которые лишь частично реализованы в Py thon 2.4. Поэтому мы больше не будем углубляться в эту тему, и за бо лее подробной информацией обращайтесь к набору стандартных руко водств по языку Python. Концепции проектирования модулей Как и в случае с функциями, при проектировании модулей использу ются свои правила: вам необходимо подумать о том, какие функции и в какие модули будут входить, предусмотреть механизмы взаимо действия между модулями и т. д. Все это станет более понятным, когда вы начнете создавать крупные программы на языке Python, а пока оз накомьтесь с несколькими основными положениями: • В языке Python вы всегда находитесь в модуле. Нет никакого спосо ба написать программный код, который не находился бы в каком нибудь модуле. Фактически даже программный код, который вво дится в интерактивной оболочке, на самом деле относится к встроен ному модулю с именем __main__ – единственная уникальная особен ность интерактивной оболочки состоит в том, что программный код после выполнения сразу же удаляется, а результаты выражений выводятся автоматически. • Минимизируйте взаимозависимость модулей: глобальные пере! менные. Как и функции, модули работают лучше, когда они напи саны как самостоятельные закрытые компоненты. Следуйте прави лу: модули должны быть максимально независимы от глобальных имен в других модулях. • Максимизируйте согласованность внутри модуля: общая цель. Уменьшить взаимозависимость модулей можно за счет увеличения согласованности отдельного модуля – если все компоненты модуля используются для достижения общей цели, маловероятно, что та кой модуль будет зависеть от внешних имен. • Модули должны редко изменять переменные в других модулях. Мы демонстрировали справедливость этого правила на примере про граммного кода в главе 16. Но будет совсем нелишним повторить его: использование глобальных переменных из других модулей (в кон це концов, это один из способов, каким клиенты импортируют 544 Глава 21. Дополнительные возможности модулей службы) – совершенно нормальное явление, тогда как внесение из менений в глобальные переменные в других модулях служит при знаком проблем с проектированием. Конечно, из этого правила есть исключения, но вы должны стремиться обмениваться данными че рез такие механизмы, как аргументы и возвращаемые значения функций, не прибегая к прямому изменению переменных в других модулях. В противном случае глобальные значения могут попасть в зависимость от порядка выполнения инструкций присваивания в других файлах, и такие модули будет сложнее понять и приспосо бить к повторному использованию в других программах. Для иллюстрации на рис. 21.1 приводится окружение, в котором дейст вуют модули. Модули содержат переменные, функции, классы и другие модули (если импортируют их). В функциях имеются свои собственные локальные переменные. С классами – еще одной разновидностью объ ектов, которые находятся в модулях, – вы познакомитесь в главе 22. Модули – это объекты: метапрограммы Поскольку модули экспортируют большую часть своих свойств в виде встроенных атрибутов, это позволяет легко создавать программы, ко торые управляют другими программами. Такие менеджеры программ импортирование импортирование Переменные Функции Классы/Типы Переменные Функции Классы/Типы Другие модули (на языке Python или C) Другие модули (на языке Python или C) Модули Переменные Функции Классы Члены классов Методы Переменные Рис. 21.1. Среда выполнения модуля. Модули импортируются и сами могут импортировать и использовать другие модули, которые могут быть написаны на языке Python или на других языках программирования, таких как C. Модули содержат переменные, функции и классы, с помощью которых решают возложенные на них задачи. Их функции и классы также могут содержать свои собственные переменные и другие программные элементы. Но надо помнить, что на самом верхнем уровне программы – это всего лишь наборы модулей Концепции проектирования модулей 545 мы обычно называем метапрограммами, потому что они работают по верх других программ. Этот прием также называется интроспекцией, потому что программы могут просматривать внутреннее устройство объектов и действовать, исходя из этого. Интроспекция – это дополни тельная особенность, которая может быть полезна при создании инст рументальных средств программирования. Например, чтобы получить значение атрибута с именем name в модуле с именем M, мы можем использовать полное имя атрибута или обра титься к нему с помощью словаря атрибутов модуля (экспортируется в виде встроенного атрибута __dict__). Кроме того, интерпретатор экс портирует список всех загруженных модулей в виде словаря sys.mod ules (то есть в виде атрибута modules модуля sys) и предоставляет встро енную функцию getattr, которая позволяет получать доступ к атрибу там по строкам с их именами (напоминает выражение object.attr, только attr – это строка времени выполнения). Благодаря этому все следующие выражения представляют один и тот же атрибут и объект: M.name # Полное имя объекта M.__dict__['name'] # Доступ с использованием словаря пространства имен sys.modules['M'].name # Доступ через таблицу загруженных модулей getattr(M, 'name') # Доступ с помощью встроенной функции Обеспечивая доступ к внутреннему устройству модулей, интерпретатор помогает создавать программы, управляющие другими программами. 1 Например, ниже приводится модуль с именем mydir.py, в котором ис пользованы эти идеи для реализации измененной версии встроенной функции dir. Этот модуль определяет и экспортирует функцию с име нем listing, которая принимает объект модуля в качестве аргумента и выводит отформатированный листинг пространства имен модуля: # Модуль, который выводит содержимое пространства имен других модулей verbose = 1 def listing(module): if verbose: print ""*30 print "name:", module.__name__, "file:", module.__file__ print ""*30 count = 0 1 Как мы видели в главе 16, функция может получить доступ к вмещающему модулю с помощью таблицы sys.modules, что позволяет имитировать дейст вие инструкции global. Например, эффект действия инструкций global X; X=0 внутри функции можно реализовать (хотя для этого придется ввести с клавиатуры значительно больше символов!) так: import sys; glob=sys.mod ules[__name__]; glob.X=0 . Не забывайте, что каждый модуль имеет атрибут __name__ ; внутри функции, принадлежащей модулю, он выглядит как гло бальное имя. Этот прием обеспечивает еще один способ изменения одно именных локальных и глобальных переменных внутри функции. 546 Глава 21. Дополнительные возможности модулей for attr in module.__dict__.keys(): # Сканировать пространство имен print "%02d) %s" % (count, attr), if attr[0:2] == "__": print " else: print getattr(module, attr) # То же, что и .__dict__[attr] count = count+1 if verbose: print ""*30 print module.__name__, "has %d names" % count print ""*30 if __name__ == "__main__": import mydir listing(mydir) # Код самопроверки: вывести свое # пространство имен В модуле, в самом конце, реализована логика самопроверки, которая за ставляет модуль импортировать самого себя и вывести содержимое сво его пространства имен. Ниже показан результат работы этого модуля: C:\python> python mydir.py name: mydir file: mydir.py 00) __file__ 01) __name__ 02) listing 03) __doc__ 04) __builtins__ 05) verbose 1 mydir has 6 names С функцией getattr и родственными ей мы встретимся еще раз позд нее. Самое важное здесь, что mydir – это программа, которая позволяет исследовать другие программы. Так как интерпретатор не скрывает внутреннее устройство модулей, вы можете реализовать обработку лю бых объектов единообразно. 1 1 Инструменты, такие как mydir.listing, могут быть предварительно загру жены в пространство имен интерактивной оболочки импортированием их в файле, указанном в переменной окружения PYTHONSTARTUP. Так как про граммный код этого файла выполняется в интерактивном пространстве имен (модуль __main__), такой способ импортирования часто используемых инструментов позволит вам сэкономить время на вводе инструкций вруч ную. Дополнительная информация приводится в приложении A. Типичные проблемы при работе с модулями 547 Типичные проблемы при работе с модулями В этом разделе мы рассмотрим обычный набор пограничных ситуа ций, которые делают жизнь интересной для тех, кто только начинает осваивать язык Python. Некоторые из них настолько неочевидны, что трудно привести к ним примеры, но в большинстве своем они иллюст рируют важные сведения о языке. Порядок следования инструкций на верхнем уровне имеет значение Когда модуль впервые импортируется (или загружается повторно), интерпретатор выполняет инструкции в нем одну за другой, сверху вниз. Из этого следует несколько замечаний, которые касаются опере жающих ссылок на переменные, которые следует подчеркнуть особо: • Инструкции программного кода на верхнем уровне в файле модуля (не вложенные в функцию) выполняются, как только интерпретатор достигает их в процессе импортирования. По этой причине он не мо жет ссылаться на имена, присваивание которым производится ниже. • Программный код внутри функций не выполняется, пока функция не будет вызвана, – разрешение имен внутри функций не произво дится до момента их вызова, поэтому они обычно могут ссылаться на имена, расположенные в любой части файла. Вообще опережающие ссылки доставляют беспокойство только в про граммном коде верхнего уровня, который выполняется немедленно; функции могут ссылаться на любые имена. Ниже приводится пример, демонстрирующий опережающие ссылки: func1() # Ошибка: имя "func1" еще не существует def func1(): print func2() # OK: поиск имени "func2" будет выполнен позднее func1() # Ошибка: имя "func2" еще не существует def func2(): return "Hello" func1() # OK: "func1" и "func2" определены Когда этот файл будет импортироваться (или запускаться как само стоятельная программа), интерпретатор Python будет выполнять его инструкции сверху вниз. Первый вызов func1 потерпит неудачу, пото му что инструкция def для имени func1 еще не была выполнена. Вызов func2 внутри func1 будет работать без ошибок при условии, что к мо менту вызова func1 инструкция def func2 уже будет выполнена (этого еще не произошло к моменту второго вызова func1 на верхнем уровне). Последний вызов func1 в конце файла будет выполнен успешно, пото му что оба имени, func1 и func2, уже определены. 548 Глава 21. Дополнительные возможности модулей Смешивание инструкций def с программным кодом верхнего уровня не только осложняет его чтение, но еще и ставит его работоспособность в зависимость от порядка следования инструкций. Если вам необходи мо объединять в модуле программный код, выполняемый непосредст венно, с инструкциями def, возьмите за правило помещать инструкции def в начало файла, а программный код верхнего уровня – в конец фай ла. При таком подходе ваши функции гарантированно будут определе ны к моменту выполнения программного кода, который их использует. Импортирование модулей по имени в виде строки Имя модуля в инструкции import или from является именем перемен ной. Тем не менее иногда ваша программа будет получать имя модуля, который следует импортировать, в виде строки во время выполнения (например, в случае, когда пользователь выбирает имя модуля внутри графического интерфейса). К сожалению, невозможно напрямую ис пользовать инструкции импорта для загрузки модуля, имя которого задано в виде строки, – в этих инструкциях интерпретатор ожидает получить имя переменной, а не строку. Например: >>> import "string" File " import "string" ^ SyntaxError: invalid syntax Точно так же невозможно импортировать модуль, если просто присво ить строку переменной: x = "string" import x Чтобы решить эту проблему, необходим специальный инструмент, вы полняющий динамически загрузку модулей, имена которых создают ся в виде строк во время выполнения. Обычно для этого конструирует ся строка программного кода, содержащая инструкцию import, кото рая затем передается инструкции exec для исполнения: >>> modname = "string" >>> exec "import " + modname # Выполняется как строка программного кода >>> string # Модуль был импортирован в пространство имен Инструкция exec (и родственная ей функция eval, используемая для вычисления значений выражений) скомпилирует строку в код и пере даст его интерпретатору для исполнения. В языке Python компилятор байткода доступен непосредственно во время выполнения, поэтому можно писать программы, которые конструируют и выполняют другие программы, как в этом случае. По умолчанию инструкция exec выпол няет программный код в текущей области видимости, но существует возможность передавать ей необязательные словари пространств имен. Типичные проблемы при работе с модулями 549 Единственный настоящий недостаток инструкции exec состоит в том, что она должна компилировать инструкцию import всякий раз, когда она запускается, – если импортировать приходится достаточно часто, программный код может работать немного быстрее при использовании встроенной функции __import__, которая выполняет загрузку модуля, получая его имя в виде строки. Результат получается тот же самый, но функция __import__ возвращает объект модуля, поэтому его надо при своить переменной, чтобы сохранить: >>> modname = "string" >>> string = __import__(modname) >>> string Инструкция from создает копии, а не ссылки Несмотря на то что инструкция from широко применяется, она часто становится источником самых разных проблем. При выполнении при сваивания именам в области видимости импортирующего модуля она не создает синонимы, а копирует имена. Результат будет тем же самым, что и для любых других инструкций присваивания в языке Python, но есть одно тонкое отличие, особенно когда программный код, исполь зующий объекты совместно, находится в разных файлах. Например, предположим, что у нас имеется следующий модуль (nested1.py): X = 99 def printer(): print X Если импортировать эти два имени с помощью инструкции from в дру гом модуле (nested2.py), будут получены копии этих имен, а не ссылки на них. Изменение имени в импортирующем модуле приведет к изме нениям только локальной версии этого имени, а имя в модуле nested1.py будет иметь прежнее значение: from nested1 import X, printer # Копировать имена X = 88 # Изменит только локальную версию "X"! printer() # X в nested1 попрежнему будет равно 99 % python nested2.py 99 Однако, если выполнить импорт всего модуля с помощью инструкции import и затем изменить значение с использованием полного имени, это приведет к изменению имени в файле nested1.py. Полное имя на правляет интерпретатор к имени в указанном объекте модуля, а не к имени в импортирующем модуле (nested3.py): import nested1 # Импортировать модуль целиком nested1.X = 88 # OK: изменяется имя X в nested1 nested1.printer() % python nested3.py 88 550 Глава 21. Дополнительные возможности модулей Инструкция from * может затушевывать смысл переменных Я упоминал об этом в главе 19, но оставил подробности до этого момен та. Поскольку в инструкции from module import * не указываются необ ходимые имена переменных, она может непреднамеренно перезаписать имена, уже используемые в области видимости импортирующего моду ля. Хуже того, это может осложнить поиск модуля, откуда исходит пе ременная, вызвавшая проблемы. Это особенно верно, когда форма инст рукции from * используется более чем в одном импортированном файле. Например, если инструкция from * применяется к трем модулям, то у вас не будет иного способа узнать, какая в действительности вызыва ется функция, кроме как выполнить поиск в трех разных файлах мо дулей (каждый из которых может находиться в отдельном каталоге): >>> from module1 import * # Плохо: может незаметно перезаписать мои имена >>> from module2 import * # Еще хуже: нет никакого способа понять, >>> from module3 import * # что мы получили! >>> . . . >>> func() # Ну??? Решение опять же заключается в том, чтобы так не делать: старайтесь явно перечислять требуемые атрибуты в инструкции from и ограничи вайте применение формы from * одним модулем на файл. В этом случае любые неопределенные имена, согласно дедуктивному методу, долж ны находиться в модуле, который импортируется единственной инст рукцией from *. Этой проблемы вообще можно избежать, если всегда использовать инструкцию import вместо from, но это слишком сложно – как и многое другое в программировании, инструкция from – очень удобный инструмент при разумном использовании. |