Улучшение классов с помощью возможностей итерации
Теперь мы сделали так, чтобы наш класс Structure
и его подклассы поддерживали итерацию. Итерация - это мощная концепция в Python, которая позволяет поочередно перебирать элементы коллекции. Когда класс поддерживает итерацию, он становится более гибким и может работать с множеством встроенных функций Python. Давайте рассмотрим, как поддержка итерации позволяет использовать многие мощные возможности Python.
Использование итерации для преобразования в последовательности
В Python есть встроенные функции, такие как list()
и tuple()
. Эти функции очень полезны, так как они могут принимать в качестве входных данных любой итерируемый объект. Итерируемый объект - это то, что можно перебирать в цикле, например, список, кортеж или, теперь, экземпляры нашего класса Structure
. Поскольку наш класс Structure
теперь поддерживает итерацию, мы можем легко преобразовать его экземпляры в списки или кортежи.
- Давайте попробуем эти операции с экземпляром класса
Stock
. Класс Stock
является подклассом класса Structure
. Запустите следующую команду в терминале:
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print('As list:', list(s)); print('As tuple:', tuple(s))"
Эта команда сначала импортирует класс Stock
, создает его экземпляр, а затем преобразует этот экземпляр в список и кортеж с помощью функций list()
и tuple()
соответственно. Вывод показывает экземпляр, представленный в виде списка и кортежа:
As list: ['GOOG', 100, 490.1]
As tuple: ('GOOG', 100, 490.1)
Распаковка
Python имеет очень полезную функцию, называемую распаковкой. Распаковка позволяет взять итерируемый объект и сразу же присвоить его элементы отдельным переменным. Поскольку наш экземпляр класса Stock
является итерируемым, мы можем использовать эту функцию распаковки с ним.
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); name, shares, price = s; print(f'Name: {name}, Shares: {shares}, Price: {price}')"
В этом коде мы создаем экземпляр класса Stock
, а затем распаковываем его элементы в три переменные: name
, shares
и price
. Затем мы выводим эти переменные. Вывод показывает значения этих переменных:
Name: GOOG, Shares: 100, Price: 490.1
Добавление возможностей сравнения
Когда класс поддерживает итерацию, становится проще реализовать операции сравнения. Операции сравнения используются для проверки равенства двух объектов. Давайте добавим метод __eq__()
в наш класс Structure
для сравнения экземпляров.
- Откройте снова файл
structure.py
. Метод __eq__()
- это специальный метод в Python, который вызывается, когда вы используете оператор ==
для сравнения двух объектов. Добавьте следующий код в класс Structure
в файле structure.py
:
def __eq__(self, other):
return isinstance(other, type(self)) and tuple(self) == tuple(other)
Этот метод сначала проверяет, является ли объект other
экземпляром того же класса, что и self
, с помощью функции isinstance()
. Затем он преобразует как self
, так и other
в кортежи и проверяет, равны ли эти кортежи.
Полностью обновленный файл structure.py
должен выглядеть следующим образом:
class StructureMeta(type):
def __new__(cls, name, bases, clsdict):
fields = clsdict.get('_fields', [])
for name in fields:
clsdict[name] = property(lambda self, name=name: getattr(self, '_'+name))
return super().__new__(cls, name, bases, clsdict)
class Structure(metaclass=StructureMeta):
_fields = []
def __init__(self, *args):
if len(args) != len(self._fields):
raise TypeError(f'Expected {len(self._fields)} arguments')
for name, val in zip(self._fields, args):
setattr(self, '_'+name, val)
def __iter__(self):
for name in self._fields:
yield getattr(self, name)
def __eq__(self, other):
return isinstance(other, type(self)) and tuple(self) == tuple(other)
-
После добавления метода __eq__()
сохраните файл structure.py
.
-
Давайте протестируем возможность сравнения. Запустите следующую команду в терминале:
python3 -c "from stock import Stock; a = Stock('GOOG', 100, 490.1); b = Stock('GOOG', 100, 490.1); c = Stock('AAPL', 200, 123.4); print(f'a == b: {a == b}'); print(f'a == c: {a == c}')"
Этот код создает три экземпляра класса Stock
: a
, b
и c
. Затем он сравнивает a
с b
и a
с c
с помощью оператора ==
. Вывод показывает результаты этих сравнений:
a == b: True
a == c: False
- Теперь, чтобы убедиться, что все работает правильно, нам нужно запустить модульные тесты. Модульные тесты - это набор кода, который проверяет, работает ли различные части вашей программы так, как ожидается. Запустите следующую команду в терминале:
python3 teststock.py
Если все работает правильно, вы должны увидеть вывод, указывающий на то, что тесты прошли успешно:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Добавив всего два простых метода (__iter__()
и __eq__()
), мы значительно улучшили наш класс Structure
, сделав его более "питоническим" и удобным в использовании.