ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 835
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
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
Чтобы использовать атрибуты и методы класса, необходимо создать экземпляр класса со- гласно следующему синтаксису:
<Экземпляр класса> = <Название класса>([<Параметры>])
При обращении к методам класса используется такой формат:
1 ... 19 20 21 22 23 24 25 26 ... 83
<Экземпляр класса>.<Имя метода>([<Параметры>])
Обратите внимание на то, что при вызове метода не нужно передавать ссылку на экземпляр класса в качестве параметра, как это делается в определении метода внутри класса. Ссылку на экземпляр класса интерпретатор передает автоматически.
Обращение к атрибутам класса осуществляется аналогично:
<Экземпляр класса>.<Имя атрибута>
Определим класс
MyClass с атрибутом x
и методом print_x()
, выводящим значение этого атрибута, а затем создадим экземпляр класса и вызовем метод (листинг 13.2).
Листинг 13.2. Создание атрибута и метода class MyClass: def __init__(self): # Конструктор self.x = 10 # Атрибут экземпляра класса def print_x(self): # self — это ссылка на экземпляр класса print(self.x) # Выводим значение атрибута c = MyClass() # Создание экземпляра класса
# Вызываем метод print_x() c.print_x() # self не указывается при вызове метода print(c.x) # К атрибуту можно обратиться непосредственно
Для доступа к атрибутам и методам можно использовать и следующие функции:
getattr()
— возвращает значение атрибута по его названию, заданному в виде строки.
С помощью этой функции можно сформировать имя атрибута динамически во время выполнения программы. Формат функции: getattr(<Объект>, <Атрибут>[, <Значение по умолчанию>])
Если указанный атрибут не найден, возбуждается исключение
AttributeError
. Чтобы избежать вывода сообщения об ошибке, в третьем параметре можно указать значение, которое будет возвращаться, если атрибут не существует;
setattr()
— задает значение атрибута. Название атрибута указывается в виде строки.
Формат функции: setattr(<Объект>, <Атрибут>, <Значение>)
246
Часть I. Основы языка Python
Вторым параметром функции setattr()
можно передать имя несуществующего атрибу- та — в этом случае атрибут с указанным именем будет создан;
delattr(<Объект>, <Атрибут>)
— удаляет атрибут, чье название указано в виде строки;
hasattr(<Объект>, <Атрибут>)
— проверяет наличие указанного атрибута. Если атрибут существует, функция возвращает значение
True
Продемонстрируем работу функций на примере (листинг 13.3).
Листинг 13.3. Функции getattr(), setattr() и hasattr() class MyClass: def __init__(self): self.x = 10 def get_x(self): return self.x c = MyClass() # Создаем экземпляр класса print(getattr(c, "x")) # Выведет: 10 print(getattr(c, "get_x")()) # Выведет: 10 print(getattr(c, "y", 0)) # Выведет: 0, т. к. атрибут не найден setattr(c, "y", 20) # Создаем атрибут y print(getattr(c, "y", 0)) # Выведет: 20 delattr(c, "y") # Удаляем атрибут y print(getattr(c, "y", 0)) # Выведет: 0, т. к. атрибут не найден print(hasattr(c, "x")) # Выведет: True print(hasattr(c, "y")) # Выведет: False
Все атрибуты класса в языке Python являются открытыми (public), т. е. доступными для не- посредственного изменения как из самого класса, так и из других классов и из основного кода программы.
Кроме того, атрибуты допускается создавать динамически после создания класса — можно создать как атрибут объекта класса, так и атрибут экземпляра класса. Рассмотрим это на примере (листинг 13.4).
Листинг 13.4. Атрибуты объекта класса и экземпляра класса class MyClass: # Определяем пустой класс pass
MyClass.x = 50 # Создаем атрибут объекта класса c1, c2 = MyClass(), MyClass() # Создаем два экземпляра класса c1.y = 10 # Создаем атрибут экземпляра класса c2.y = 20 # Создаем атрибут экземпляра класса print(c1.x, c1.y) # Выведет: 50 10 print(c2.x, c2.y) # Выведет: 50 20
В этом примере мы определяем пустой класс, разместив в нем оператор pass
. Далее создаем атрибут объекта класса: x
. Этот атрибут будет доступен всем создаваемым экземплярам класса. Затем создаем два экземпляра класса и добавляем одноименные атрибуты: y
. Значе- ния этих атрибутов будут разными в каждом экземпляре класса. Но если создать новый эк- земпляр (например, c3
), то атрибут y
в нем определен не будет. Таким образом, с помощью