ээдд. Прохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен. Николай Прохоренок Владимир Дронов
Скачать 7.92 Mb.
|
__all__ = ["x", "_s"] Затем напишем программу, которая будет его импортировать (листинг 12.17). Листинг 12.17. Код основной программы # -*- coding: utf-8 -*- from module3 import * print(sorted(vars().keys())) # Получаем список всех идентификаторов input() После запуска основной программы (с помощью двойного щелчка на значке файла) полу- чим следующий результат: ['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_s', 'x'] Как видно из примера, были импортированы только переменные _s и x . Если бы мы не ука- зали идентификаторы внутри списка __all__ , результат был бы другим: ['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'x', 'y', 'z'] Обратите внимание на то, что переменная _s в этом случае не импортируется, т. к. ее имя начинается с символа подчеркивания. Глава 12. Модули и пакеты 237 12.3. Пути поиска модулей До сих пор мы размещали модули в одной папке с файлом основной программы. В этом случае нет необходимости настраивать пути поиска модулей, т. к. папка с исполняемым файлом автоматически добавляется в начало списка путей. Получить полный список путей поиска позволяет следующий код: >>> import sys # Подключаем модуль sys >>> sys.path # path содержит список путей поиска модулей Список из переменной sys.path содержит пути поиска, получаемые из следующих источ- ников: путь к папке с файлом основной программы; значение переменной окружения PYTHONPATH . Для добавления переменной в меню Пуск выбираем пункт Панель управления (или Настройка | Панель управления). В от- крывшемся окне выбираем пункт Система и щелкаем на ссылке Дополнительные параметры системы. Переходим на вкладку Дополнительно и нажимаем кнопку Переменные среды. В разделе Переменные среды пользователя нажимаем кнопку Создать. В поле Имя переменной вводим PYTHONPATH , а в поле Значение переменной задаем пути к папкам с модулями через точку с запятой — например, C:\folder1;C: \folder2 . Закончив, не забудем нажать кнопки ОK обоих открытых окон. После этого изменения перезагружать компьютер не нужно, достаточно заново запустить программу; пути поиска стандартных модулей; содержимое файлов с расширением pth , расположенных в каталогах поиска стандартных модулей, — например, в каталоге C:\Python36\Lib\site-packages . Названия таких файлов могут быть произвольными, главное, чтобы они имели расширение pth . Каждый путь (абсолютный или относительный) должен быть расположен на отдельной строке. Для примера создайте файл mypath.pth в каталоге C:\Python36\Lib\site-packages со сле- дующим содержимым: # Это комментарий C:\folder1 C:\folder2 П РИМЕЧАНИЕ Обратите внимание на то, что каталоги должны существовать, в противном случае они не будут добавлены в список sys.path. При поиске модуля список sys.path просматривается от начала к концу. Поиск прекраща- ется после первого найденного модуля. Таким образом, если в каталогах C:\folder1 и C:\folder2 существуют одноименные модули, то будет использоваться модуль из папки C:\folder1 , т. к. он расположен первым в списке путей поиска. Список sys.path можно изменять программно с помощью соответствующих методов. На- пример, добавить каталог в конец списка можно с помощью метода append() , а в его нача- ло — с помощью метода insert() (листинг 12.18). Листинг 12.18. Изменение списка путей поиска модулей # -*- coding: utf-8 -*- import sys sys.path.append(r"C:\folder1") # Добавляем в конец списка 238 Часть I. Основы языка Python sys.path.insert(0, r"C:\folder2") # Добавляем в начало списка print(sys.path) input() В этом примере мы добавили папку C:\folder2 в начало списка. Теперь, если в каталогах C:\folder1 и C:\folder2 существуют одноименные модули, будет использоваться модуль из папки C:\folder2 , а не из папки C:\folder1 , как в предыдущем примере. Обратите внимание на символ r перед открывающей кавычкой. В этом режиме специальные последовательности символов не интерпретируются. Если используются обычные строки, то необходимо удвоить каждый слэш в пути: sys.path.append("C:\\folder1\\folder2\\folder3") В Python 3.6 появилась возможность указать полностью свои пути для поиска модулей, при этом список, хранящийся в переменной sys.path , будет проигнорирован. Для этого доста- точно поместить в папку, где установлен Python, файл с именем python<первые две цифры номера версии Python>._pth (так, для Python 3.6 этот файл должен иметь имя python36._pth ) или python._pth , в котором записать все нужные пути в том же формате, который использу- ется при создании файлов pth . Первый файл будет использоваться программами, вызываю- щими библиотеку времени выполнения Python, в частности, Python Shell. А второй файл будет считан при запуске Python-программы щелчком мыши на ее файле. В НИМАНИЕ ! В файл python<первые две цифры номера версии Python>._pth обязательно следует вклю- чить пути для поиска модулей, составляющих стандартную библиотеку Python (их можно получить из списка, хранящегося в переменной sys.path). Если этого не сделать, утилита Python Shell вообще не запустится. 12.4. Повторная загрузка модулей Как вы уже знаете, модуль загружается только один раз при первой операции импорта. Все последующие операции импортирования этого модуля будут возвращать уже загруженный объект модуля, даже если сам модуль был изменен. Чтобы повторно загрузить модуль, сле- дует воспользоваться функцией reload() из модуля imp . Формат функции: from imp import reload reload(<Объект модуля>) В качестве примера создадим модуль tests2.py, поместив его в папку C:\book (листинг 12.19). Листинг 12.19. Содержимое файла tests2.py # -*- coding: utf-8 -*- x = 150 Подключим этот модуль в окне Python Shell редактора IDLE и выведем текущее значение переменной x : >>> import sys >>> sys.path.append(r"C:\book") # Добавляем путь к папке с модулем >>> import tests2 # Подключаем модуль tests2.py >>> print(tests2.x) # Выводим текущее значение 150 Глава 12. Модули и пакеты 239 Не закрывая окно Python Shell, изменим значение переменной x на 800 , а затем попробуем заново импортировать модуль и вывести текущее значение переменной: >>> # Изменяем значение в модуле на 800 >>> import tests2 >>> print(tests2.x) # Значение не изменилось 150 Как видно из примера, значение переменной x не изменилось. Теперь перезагрузим модуль с помощью функции reload() : >>> from imp import reload >>> reload(tests2) # Перезагружаем модуль >>> print(tests2.x) # Значение изменилось 800 При использовании функции reload() следует учитывать, что идентификаторы, импор- тированные с помощью инструкции from , перезагружены не будут. Кроме того, повторно не загружаются скомпилированные модули, написанные на других языках программиро- вания, — например, на языке C. 12.5. Пакеты Пакетом называется папка с модулями, в которой расположен файл инициализации __init__.py . Файл инициализации может быть пустым или содержать код, который будет выполнен при первой операции импортирования любого модуля, входящего в состав паке- та. В любом случае он обязательно должен присутствовать внутри папки с модулями. В качестве примера создадим следующую структуру файлов и папок: main.py # Основной файл с программой folder1\ # Папка на одном уровне вложенности с main.py __init__.py # Файл инициализации module1.py # Модуль folder1\module1.py folder2\ # Вложенная папка __init__.py # Файл инициализации module2.py # Модуль folder1\folder2\module2.py module3.py # Модуль folder1\folder2\module3.py Содержимое файлов __init__.py приведено в листинге 12.20. Листинг 12.20. Содержимое файлов __init__.py # -*- coding: utf-8 -*- print("__init__ из", __name__) Содержимое модулей module1.py , module2.py и module3.py приведено в листинге 12.21. Листинг 12.21. Содержимое модулей module1.py, module2.py и module3.py # -*- coding: utf-8 -*- msg = "Модуль {0}".format(__name__) 240 Часть I. Основы языка Python Теперь импортируем эти модули в основном файле main.py и получим значение переменной msg разными способами. Файл main.py будем запускать с помощью двойного щелчка на значке файла. Содержимое файла main.py приведено в листинге 12.22. Листинг 12.22. Содержимое файла main.py # -*- coding: utf-8 -*- # Доступ к модулю folder1\module1.py import folder1.module1 as m1 # Выведет: __init__ из folder1 print(m1.msg) # Выведет: Модуль folder1.module1 from folder1 import module1 as m2 print(m2.msg) # Выведет: Модуль folder1.module1 from folder1.module1 import msg print(msg) # Выведет: Модуль folder1.module1 # Доступ к модулю folder1\folder2\module2.py import folder1.folder2.module2 as m3 # Выведет: __init__ из folder1.folder2 print(m3.msg) # Выведет: Модуль folder1.folder2.module2 from folder1.folder2 import module2 as m4 print(m4.msg) # Выведет: Модуль folder1.folder2.module2 from folder1.folder2.module2 import msg print(msg) # Выведет: Модуль folder1.folder2.module2 input() Как видно из примера, пакеты позволяют распределить модули по папкам. Чтобы импорти- ровать модуль, расположенный во вложенной папке, необходимо указать путь к нему, пере- числив имена папок через точку. Если модуль расположен в папке C:\folder1\folder2\ , то путь к нему из C:\ должен быть записан так: folder1.folder2 . При использовании инструкции import путь к модулю должен включать не только имена папок, но и название модуля без расширения: import folder1.folder2.module2 Получить доступ к идентификаторам внутри импортированного модуля можно следующим образом: print(folder1.folder2.module2.msg) Так как постоянно указывать столь длинный идентификатор очень неудобно, можно создать псевдоним, указав его после ключевого слова as , и обращаться к идентификаторам модуля через него: import folder1.folder2.module2 as m print(m.msg) При использовании инструкции from можно импортировать как объект модуля, так и опре- деленные идентификаторы из модуля. Чтобы импортировать объект модуля, его название следует указать после ключевого слова import : Глава 12. Модули и пакеты 241 from folder1.folder2 import module2 print(module2.msg) Для импортирования только определенных идентификаторов название модуля указывается в составе пути, а после ключевого слова import через запятую указываются идентифика- торы: from folder1.folder2.module2 import msg print(msg) Если необходимо импортировать все идентификаторы из модуля, то после ключевого слова import указывается символ * : from folder1.folder2.module2 import * print(msg) Инструкция from позволяет также импортировать сразу несколько модулей из пакета. Для этого внутри файла инициализации __init__.py в атрибуте __all__ необходимо указать спи- сок модулей, которые будут импортироваться с помощью выражения from < Пакет> import * В качестве примера изменим содержимое файла __init__.py из каталога folder1\folder2\ : # -*- coding: utf-8 -*- __all__ = ["module2", "module3"] Теперь создадим файл main2.py (листинг 12.23) и запустим его. Листинг 12.23. Содержимое файла main2.py # -*- coding: utf-8 -*- from folder1.folder2 import * print(module2.msg) # Выведет: Модуль folder1.folder2.module2 print(module3.msg) # Выведет: Модуль folder1.folder2.module3 input() Как видно из примера, после ключевого слова from указывается лишь путь к папке без име- ни модуля. В результате выполнения инструкции from все модули, указанные в списке __all__ , будут импортированы в пространство имен модуля main.py До сих пор мы рассматривали импортирование модулей из основной программы. Теперь рассмотрим импорт модулей внутри пакета. Для такого случая инструкция from поддержи- вает относительный импорт модулей. Чтобы импортировать модуль, расположенный в той же папке, перед названием модуля указывается точка: from .module import * Чтобы импортировать модуль, расположенный в родительской папке, перед названием мо- дуля указываются две точки: from ..module import * Если необходимо обратиться уровнем еще выше, то указываются три точки: from ...module import * Чем выше уровень, тем больше точек необходимо указать. После ключевого слова from можно указывать одни только точки — в этом случае имя модуля вводится после ключевого слова import : from .. import module 242 Часть I. Основы языка Python Рассмотрим относительный импорт на примере. Для этого создадим в папке C:\folder1\ folder2\ модуль module4.py , чей код показан в листинге 12.24. Листинг 12.24. Содержимое модуля module4.py # -*- coding: utf-8 -*- # Импорт модуля module2.py из текущего каталога from . import module2 as m1 var1 = "Значение из: {0}".format(m1.msg) from .module2 import msg as m2 var2 = "Значение из: {0}".format(m2) # Импорт модуля module1.py из родительского каталога from .. import module1 as m3 var3 = "Значение из: {0}".format(m3.msg) from ..module1 import msg as m4 var4 = "Значение из: {0}".format(m4) Теперь создадим файл main3.py (листинг 12.25) и запустим его с помощью двойного щелчка мышью. Листинг 12.25. Содержимое файла main3.py # -*- coding: utf-8 -*- from folder1.folder2 import module4 as m print(m.var1) # Значение из: Модуль folder1.folder2.module2 print(m.var2) # Значение из: Модуль folder1.folder2.module2 print(m.var3) # Значение из: Модуль folder1.module1 print(m.var4) # Значение из: Модуль folder1.module1 input() При импортировании модуля внутри пакета с помощью инструкции import важно помнить, что в Python производится абсолютный импорт. Если при запуске Python-программы двой- ным щелчком на ее файле в список sys.path автоматически добавляется путь к каталогу с исполняемым файлом, то при импорте внутри пакета этого не происходит. Поэтому если изменить содержимое модуля module4.py показанным далее способом, то мы получим со- общение об ошибке или загрузим совсем другой модуль: # -*- coding: utf-8 -*- import module2 # Ошибка! Поиск модуля по абсолютному пути var1 = "Значение из: {0}".format(module2.msg) var2 = var3 = var4 = 0 В этом примере мы попытались импортировать модуль module2.py из модуля module4.py При этом файл main3.py (см. листинг 12.25) мы запускаем с помощью двойного щелчка. Поскольку импорт внутри пакета выполняется по абсолютному пути, поиск модуля module2.py не будет производиться в папке folder1\folder2\ . В результате модуль не будет найден. Если в путях поиска модулей находится модуль с таким же именем, то будет им- портирован модуль, который мы и не предполагали подключать. Глава 12. Модули и пакеты 243 Чтобы подключить модуль, расположенный в той же папке внутри пакета, необходимо вос- пользоваться относительным импортом с помощью инструкции from : from . import module2 Или указать полный путь относительно корневого каталога пакета: import folder1.folder2.module2 as module2 ГЛ А В А 13 Объектно-ориентированное программирование Объектно-ориентированное программирование (ООП) — это способ организации програм- мы, позволяющий использовать один и тот же код многократно. В отличие от функций и модулей, ООП позволяет не только разделить программу на фрагменты, но и описать пред- меты реального мира в виде удобных сущностей — объектов, а также организовать связи между этими объектами. Основным «кирпичиком» ООП является класс — сложный тип данных, включающий набор переменных и функций для управления значениями, хранящимися в этих переменных. Пе- ременные называют атрибутами или свойствами, а функции — методами. Класс является фабрикой объектов, т. е. позволяет создать неограниченное количество экземпляров, осно- ванных на этом классе. 13.1. Определение класса и создание экземпляра класса Класс описывается с помощью ключевого слова class по следующей схеме: class <Название класса>[(<Класс1>[, ..., <КлассN>])]: [""" Строка документирования """] <Описание атрибутов и методов> Инструкция создает новый объект и присваивает ссылку на него идентификатору, указан- ному после ключевого слова class . Это означает, что название класса должно полностью соответствовать правилам именования переменных. После названия класса в круглых скоб- ках можно указать один или несколько базовых классов через запятую. Если же класс не наследует базовые классы, то круглые скобки можно не указывать. Следует заметить, что все выражения внутри инструкции class выполняются при создании класса, а не его экзем- пляра. Для примера создадим класс, внутри которого просто выводится сообщение (листинг 13.1). Листинг 13.1. Создание определения класса # -*- coding: utf-8 -*- class MyClass: """ Это строка документирования """ print("Инструкции выполняются сразу") input() Глава 13. Объектно-ориентированное программирование 245 Этот пример содержит лишь определение класса MyClass и не создает экземпляр класса. Как только поток выполнения достигнет инструкции class , сообщение, указанное в функции print() , будет сразу выведено. Создание атрибута класса аналогично созданию обычной переменной. Метод внутри класса создается так же, как и обычная функция, — с помощью инструкции def . Методам класса в первом параметре, который обязательно следует указать явно, автоматически передается ссылка на экземпляр класса. Общепринято этот параметр называть именем self , хотя это и не обязательно. Доступ к атрибутам и методам класса внутри определяемого метода произ- водится через переменную self с помощью точечной нотации — к атрибуту x из метода класса можно обратиться так: self.x Чтобы использовать атрибуты и методы класса, необходимо создать экземпляр класса со- гласно следующему синтаксису: <Экземпляр класса> = <Название класса>([<Параметры>]) При обращении к методам класса используется такой формат: |