Главная страница

ээдд. Прохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен. Николай Прохоренок Владимир Дронов


Скачать 7.92 Mb.
НазваниеНиколай Прохоренок Владимир Дронов
Дата05.05.2023
Размер7.92 Mb.
Формат файлаpdf
Имя файлаПрохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен.pdf
ТипДокументы
#1111379
страница28 из 83
1   ...   24   25   26   27   28   29   30   31   ...   83
Для создания перечислений применяются два класса, определенные в модуле enum
:

Enum
— базовый класс для создания классов-перечислений, чьи элементы могут хранить значения произвольного типа.
Для примера определим класс-перечисление
Versions
, имеющий два элемента:
V2_7
со значением "2.7"
и
V3_6
со значением "3.6"
(листинг 15.5). Отметим, что элементы пере- числений представляют собой атрибуты объекта класса.

Глава 15. Итераторы, контейнеры и перечисления
283
Листинг 15.5. Перечисление с элементами произвольного типа from enum import Enum class Versions(Enum):
V2_7 = "2.7"
V3_6 = "3.6"

IntEnum
— базовый класс для создания перечислений, способных хранить лишь цело- численные значения.
Листинг 15.6 представляет код перечисления
Colors с тремя элементами, хранящими целые числа.
Листинг 15.6. Перечисление с целочисленными элементами from enum import IntEnum class Colors(IntEnum):
Red = 1
Green = 2
Blue = 3
Имена элементов перечислений должны быть уникальны (что и неудивительно — ведь фактически это атрибуты объекта класса). Однако разные элементы все же могут хранить одинаковые значения (листинг 15.7).
Листинг 15.7. Перечисление с элементами, хранящими одинаковые значения from enum import Enum class Versions(Enum):
V2_7 = "2.7"
V3_6 = "3.6"
MostFresh = "3.6"
Чтобы объявить, что наше перечисление может хранить лишь уникальные значения, мы можем использовать декоратор unique
, также определенный в модуле enum
(листинг 15.8).
Листинг 15.8. Использование декоратора unique from enum import Enum, unique
@unique class Versions(Enum):
V2_7 = "2.7"
V3_6 = "3.6"
Если мы попытаемся определить в классе, для которого был указан декоратор unique
, эле- менты с одинаковыми значениями, то получим сообщение об ошибке.
Определив перечисление, можно использовать его элементы в вычислениях:
>>> e = Versions.V3_6
>>> e


284
Часть I. Основы языка Python
>>> e.value
'3.6'
>>> e == Versions.V2_7
False
Отметим, что для этого нам не придется создавать экземпляр класса. Это сделает сам
Python, неявно создав экземпляр с тем же именем, что мы дали классу (вся необходимая для этого функциональность определена в базовых классах перечислений
Enum и
IntEnum
).
Все классы перечислений принадлежат типу
EnumMeta из модуля enum
:
>>> type(Colors)

>>> from enum import EnumMeta
>>> type(Colors) == EnumMeta
True
Однако элементы перечислений уже являются экземплярами их классов:
>>> type(Colors.Red)

>>> type(Colors.Red) == Colors
True
Над элементами перечислений можно производить следующие операции:
 обращаться к ним по их именам, использовав знакомую нам запись с точкой:
>>> Versions.V3_6

>>> e = Versions.V3_6
>>> e

 обращаться к ним в стиле словарей, использовав в качестве ключа имя элемента:
>>> Versions["V3_6"]

 обращаться к ним по их значениям, указав их в круглых скобках после имени класса перечисления:
>>> Versions("3.6")

 получать имена соответствующих им атрибутов класса и их значения, воспользовавшись свойствами name и value соответственно:
>>> Versions.V2_7.name, Versions.V2_7.value
('V2_7', '2.7')
 использовать в качестве итератора (необходимая для этого функциональность определе- на в базовых классах):
>>> list(Colors)
[, , ]
>>> for c in Colors: print(c.value, end = " ")
1 2 3
 использовать в выражениях с применением операторов равенства, неравенства, in и not in
:

Глава 15. Итераторы, контейнеры и перечисления
285
>>> e = Versions.V3_6
>>> e == Versions.V3_6
True
>>> e != Versions.V2_7
True
>>> e in Versions
True
>>> e in Colors
False
Отметим, что элементы разных перечислений всегда не равны друг другу, даже если хранят одинаковые значения;
 использовать элементы перечислений — подклассов
IntEnum в арифметических выраже- ниях и в качестве индексов перечислений. В этом случае они будут автоматически пре- образовываться в целые числа, соответствующие их значениям:
>>> Colors.Red + 1 # Значение Colors.Red - 1 2
>>> Colors.Green != 3 # Значение Colors.Green - 2
True
>>> ["a", "b", "c"][Colors.Red]
'b'
Помимо элементов, классы перечислений могут включать атрибуты экземпляра класса и методы — как экземпляров, так и объектов класса. При этом методы экземпляра класса все- гда вызываются у элемента перечисления (и, соответственно, первым параметром ему пере- дается ссылка на экземпляр класса, представляющий элемент перечисления, у которого был вызван метод), а методы объекта класса — у самого класса перечисления. Для примера давайте рассмотрим код класса перечисления
VersionExtended
(листинг 15.9).
Листинг 15.9. Перечисление, включающее атрибуты и методы from enum import Enum class VersionExtended(Enum):
V2_7 = "2.7"
V3_6 = "3.6"
# Методы экземпляра класса.
# Вызываются у элемента перечисления def describe(self): return self.name, self.value def __str__(self): return str(__class__.__name__) + "." + self.name + ": " +
 self.value
# Метод объекта класса.
# Вызывается у самого класса перечисления
@classmethod def getmostfresh(cls): return cls.V3_6

286
Часть I. Основы языка Python
В методе
__str__()
мы использовали встроенную переменную
__class__
, хранящую ссылку на объект текущего класса. Атрибут
__name__
этого объекта содержит имя класса в виде строки.
Осталось лишь проверить готовый класс в действии, для чего мы введем следующий код:
>>> d = VersionExtended.V2_7.describe()
>>> print(d[0] + ", " + d[1])
V2_7, 2.7
>>> print(VersionExtended.V2_7)
VersionExtended.V2_7: 2.7
>>> print(VersionExtended.getmostfresh())
VersionExtended.V3_6: 3.6
Осталось отметить одну важную деталь. На основе класса перечисления можно создавать подклассы только в том случае, если этот класс не содержит атрибутов объекта класса, т. е. собственно элементов перечисления. Если же класс перечисления содержит элементы, попытка определения его подкласса приведет к ошибке:
>>> class ExtendedColors(Colors): pass
Traceback (most recent call last):
File "
", line 1, in class ExtendedColors(Colors):
NameError: name 'Colors' is not defined
П
РИМЕЧАНИЕ
В составе стандартной библиотеки Python уже давно присутствует модуль struct, позво- ляющий создавать нечто похожее на перечисления. Однако он не столь удобен в работе, как инструменты, предлагаемые модулем enum.

ГЛ А В А
16
Работа с файлами и каталогами
Очень часто нужно сохранить какие-либо данные. Если эти данные имеют небольшой объем, их можно записать в файл.
16.1. Открытие файла
Прежде чем работать с файлом, необходимо создать объект файла с помощью функции open()
. Функция имеет следующий формат: open(<Путь к файлу>[, mode='r'][, buffering=-1][, encoding=None][, errors=None][, newline=None][, closefd=True])
В первом параметре указывается путь к файлу. Путь может быть абсолютным или относи- тельным. При указании абсолютного пути в Windows следует учитывать, что в Python слэш является специальным символом. По этой причине слэш необходимо удваивать или вместо обычных строк использовать неформатированные строки:
>>> "C:\\temp\\new\\file.txt" # Правильно 'C:\\temp\\new\\file.txt'
>>> r"C:\temp\new\file.txt" # Правильно 'C:\\temp\\new\\file.txt'
>>> "C:\temp\new\file.txt" # Неправильно!!!
'C:\temp\new\x0cile.txt'
Обратите внимание на последний пример. В этом пути из-за того, что слэши не удвоены, возникло присутствие сразу трех специальных символов:
\t
,
\n и
\f
(отображается как
\x0c
). После преобразования этих специальных символов путь будет выглядеть следующим образом:
C:<Табуляция>emp<Перевод строки>ew<Перевод формата>ile.txt
Если такую строку передать в функцию open()
, это приведет к исключению
OSError
:
>>> open("C:\temp\new\file.txt")
Traceback (most recent call last):
File "
", line 1, in open("C:\temp\new\file.txt")
OSError: [Errno 22] Invalid argument: 'C:\temp\new\x0cile.txt'
Вместо абсолютного пути к файлу можно указать относительный путь, который определя- ется с учетом местоположения текущего рабочего каталога. Относительный путь будет авто-

288
Часть I. Основы языка Python матически преобразован в абсолютный путь с помощью функции abspath()
из модуля os.path
Возможны следующие варианты:
 если открываемый файл находится в текущем рабочем каталоге, можно указать только имя файла:
>>> import os.path # Подключаем модуль
>>> # Файл в текущем рабочем каталоге (C:\book\)
>>> os.path.abspath(r"file.txt")
'C:\\book\\file.txt'
 если открываемый файл расположен во вложенной папке, перед именем файла через слэш указываются имена вложенных папок:
>>> # Открываемый файл в C:\book\folder1\
>>> os.path.abspath(r"folder1/file.txt")
'C:\\book\\folder1\\file.txt'
>>> # Открываемый файл в C:\book\folder1\folder2\
>>> os.path.abspath(r"folder1/folder2/file.txt")
'C:\\book\\folder1\\folder2\\file.txt'
 если папка с файлом расположена ниже уровнем, перед именем файла указываются две точки и слэш (
"../"
):
>>> # Открываемый файл в C:\
>>> os.path.abspath(r"../file.txt")
'C:\\file.txt'
 если в начале пути расположен слэш, путь отсчитывается от корня диска. В этом случае местоположение текущего рабочего каталога не имеет значения:
>>> # Открываемый файл в C:\book\folder1\
>>> os.path.abspath(r"/book/folder1/file.txt")
'C:\\book\\folder1\\file.txt'
>>> # Открываемый файл в C:\book\folder1\folder2\
>>> os.path.abspath(r"/book/folder1/folder2/file.txt")
'C:\\book\\folder1\\folder2\\file.txt'
Как можно видеть, в абсолютном и относительном путях можно указать как прямые, так и обратные слэши. Все они будут автоматически преобразованы с учетом значения атрибута sep из модуля os.path
. Значение этого атрибута зависит от используемой операционной системы. Выведем значение атрибута sep в операционной системе Windows:
>>> os.path.sep
'\\'
>>> os.path.abspath(r"C:/book/folder1/file.txt")
'C:\\book\\folder1\\file.txt'
При использовании относительного пути необходимо учитывать местоположение текущего рабочего каталога, т. к. рабочий каталог не всегда совпадает с каталогом, в котором нахо- дится исполняемый файл. Если файл запускается с помощью двойного щелчка на его знач- ке, то каталоги будут совпадать. Если же файл запускается из командной строки, то теку- щим рабочим каталогом будет каталог, из которого запускается файл.
Рассмотрим все это на примере, для чего в каталоге
C:\book создадим следующую структуру файлов:

Глава 16. Работа с файлами и каталогами
289
C:\book\ test.py folder1\
__init__.py module1.py
Содержимое файла
C:\book\test.py приведено в листинге 16.1.
Листинг 16.1. Содержимое файла C:\book\test.py
# -*- coding: utf-8 -*- import os, sys print("%-25s%s" % ("Файл:", os.path.abspath(__file__))) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt"))) print("-" * 40) import folder1.module1 as m m.get_cwd()
Файл
C:\book\folder1\__init__.py создаем пустым. Как вы уже знаете, этот файл указывает интерпретатору Python, что данный каталог является пакетом с модулями. Содержимое файла
C:\book\folder1\module1.py приведено в листинге 16.2.
Листинг 16.2. Содержимое файла C:\book\folder1\module1.py
# -*- coding: utf-8 -*- import os, sys def get_cwd(): print("%-25s%s" % ("Файл:", os.path.abspath(__file__))) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt")))
Запускаем командную строку, переходим в каталог
C:\book и запускаем файл test.py
:
C:\>cd C:\book
C:\book>test.py
Файл: C:\book\test.py
Текущий рабочий каталог: C:\book
Каталог для импорта: C:\book
Путь к файлу: C:\book\file.txt
----------------------------------------
Файл: C:\book\folder1\module1.py
Текущий рабочий каталог: C:\book
Каталог для импорта: C:\book
Путь к файлу: C:\book\file.txt
В этом примере текущий рабочий каталог совпадает с каталогом, в котором расположен файл test.py
. Однако обратите внимание на текущий рабочий каталог внутри модуля module1.py
. Если внутри этого модуля в функции open()
указать имя файла без пути, поиск файла будет произведен в каталоге
C:\book
, а не
C:\book\folder1

290
Часть I. Основы языка Python
Теперь перейдем в корень диска
C:
и опять запустим файл test.py
:
C:\book>cd C:\
C:\>C:\book\test.py
Файл: C:\book\test.py
Текущий рабочий каталог: C:\
Каталог для импорта: C:\book
Путь к файлу: C:\file.txt
----------------------------------------
Файл: C:\book\folder1\module1.py
Текущий рабочий каталог: C:\
Каталог для импорта: C:\book
Путь к файлу: C:\file.txt
В этом случае текущий рабочий каталог не совпадает с каталогом, в котором расположен файл test.py
. Если внутри файлов test.py и module1.py в функции open()
указать имя файла без пути, поиск файла будет производиться в корне диска
C:
, а не в каталогах с этими фай- лами.
Чтобы поиск файла всегда производился в каталоге с исполняемым файлом, необходимо этот каталог сделать текущим с помощью функции chdir()
из модуля os
. Для примера соз- дадим файл test2.py
(листинг 16.3).
Листинг 16.3. Пример использования функции chdir()
# -*- coding: utf-8 -*- import os, sys
# Делаем каталог с исполняемым файлом текущим os.chdir(os.path.dirname(os.path.abspath(__file__))) print("%-25s%s" % ("Файл:", __file__)) print("%-25s%s" % ("Текущий рабочий каталог:", os.getcwd())) print("%-25s%s" % ("Каталог для импорта:", sys.path[0])) print("%-25s%s" % ("Путь к файлу:", os.path.abspath("file.txt")))
Обратите внимание на четвертую строку. С помощью атрибута
__file__
мы получаем путь к исполняемому файлу вместе с именем файла. Атрибут
__file__
не всегда содержит пол- ный путь к файлу. Например, если запуск осуществляется следующим образом:
C:\book>C:\Python36\python test2.py то атрибут будет содержать только имя файла без пути. Чтобы всегда получать полный путь к файлу, следует передать значение атрибута в функцию abspath()
из модуля os.path
. Далее мы извлекаем путь (без имени файла) с помощью функции dirname()
и передаем его функ- ции chdir()
. Теперь, если в функции open()
указать название файла без пути, поиск будет производиться в каталоге с этим файлом. Запустим файл test2.py с помощью командной строки:
C:\>C:\book\test2.py
Файл: C:\book\test2.py
Текущий рабочий каталог: C:\book
Каталог для импорта: C:\book
Путь к файлу: C:\book\file.txt

Глава 16. Работа с файлами и каталогами
291
Функции, предназначенные для работы с каталогами, мы еще рассмотрим подробно в сле- дующих разделах. Сейчас же важно запомнить, что текущим рабочим каталогом будет каталог, из которого запускается файл, а не каталог, в котором расположен исполняе- мый файл. Кроме того, пути поиска файлов не имеют никакого отношения к путям поиска модулей.
Необязательный параметр mode в функции open()
может принимать следующие значения:
 r
— только чтение (значение по умолчанию). После открытия файла указатель устанав- ливается на начало файла. Если файл не существует, возбуждается исключение
FileNotFoundError
;
 r+
— чтение и запись. После открытия файла указатель устанавливается на начало фай- ла. Если файл не существует, то возбуждается исключение
FileNotFoundError
;
 w
— запись. Если файл не существует, он будет создан. Если файл существует, он будет перезаписан. После открытия файла указатель устанавливается на начало файла;
 w+
— чтение и запись. Если файл не существует, он будет создан. Если файл существует, он будет перезаписан. После открытия файла указатель устанавливается на начало файла;
 a
— запись. Если файл не существует, он будет создан. Запись осуществляется в конец файла. Содержимое файла не удаляется;
 a+
— чтение и запись. Если файл не существует, он будет создан. Запись осуществляется в конец файла. Содержимое файла не удаляется;
 x
— создание файла для записи. Если файл уже существует, возбуждается исключение
FileExistsError
;
 x+
— создание файла для чтения и записи. Если файл уже существует, возбуждается ис- ключение
FileExistsError
После указания режима может следовать модификатор:
 b
— файл будет открыт в бинарном режиме. Файловые методы принимают и возвраща- ют объекты типа bytes
;
 t
— файл будет открыт в текстовом режиме (значение по умолчанию в Windows). Фай- ловые методы принимают и возвращают объекты типа str
. В этом режиме будет автома- тически выполняться обработка символа конца строки — так, в Windows при чтении вместо символов
\r\n будет подставлен символ
\n
. Для примера создадим файл file.txt и запишем в него две строки:
>>> f = open(r"file.txt", "w") # Открываем файл на запись
>>> f.write("String1\nString2") # Записываем две строки в файл
15
>>> f.close() # Закрываем файл
Поскольку мы указали режим w
, то, если файл не существует, он будет создан, а если существует, то будет перезаписан.
Теперь выведем содержимое файла в бинарном и текстовом режимах:
>>> # Бинарный режим (символ \r остается)
>>> with open(r"file.txt", "rb") as f: for line in f: print(repr(line)) b'String1\r\n' b'String2'
1   ...   24   25   26   27   28   29   30   31   ...   83


написать администратору сайта