Введение
В этом практическом занятии (лабораторной работе) вы научитесь создавать новый примитивный тип в Python и реализовывать для него основные методы. Вы также получите понимание объекта - протокола Python. В большинстве программ на Python для представления данных используются встроенные примитивные типы, такие как int, float и str. Однако Python позволяет создавать пользовательские типы, как это можно увидеть в модулях, таких как decimal и fractions в стандартной библиотеке.
В этом практическом занятии вы создадите новый примитивный тип с именем MutInt (Изменяемое целое число). В отличие от неизменяемых целых чисел Python, MutInt можно изменить после создания. Это упражнение продемонстрирует основные принципы, необходимые для создания полностью функционального примитивного типа в Python.
Создание базового класса MutInt
Начнем с создания базового класса для нашего типа изменяемого целого числа. В программировании класс представляет собой чертеж для создания объектов. На этом этапе мы создадим основу нашего нового примитивного типа. Примитивный тип - это базовый тип данных, предоставляемый языком программирования, и здесь мы создадим собственный пользовательский тип.
Откройте WebIDE и перейдите в каталог
/home/labex/project. WebIDE - это интегрированная среда разработки, в которой вы можете писать, редактировать и запускать свой код. Переход в этот каталог гарантирует, что все ваши файлы будут организованы в одном месте и могут корректно взаимодействовать друг с другом.Откройте файл
mutint.py, который был создан для вас на этапе настройки. В этом файле будет определен наш классMutInt.Добавьте следующий код для определения базового класса
MutInt:
## mutint.py
class MutInt:
"""
A mutable integer class that allows its value to be modified after creation.
"""
__slots__ = ['value']
def __init__(self, value):
"""Initialize with an integer value."""
self.value = value
Атрибут __slots__ используется для определения атрибутов, которые может иметь этот класс. Атрибуты - это, по сути, переменные, принадлежащие объекту класса. Используя __slots__, мы сообщаем Python, чтобы он использовал более эффективный по памяти способ хранения атрибутов. В данном случае наш класс MutInt будет иметь только один атрибут с именем value. Это означает, что каждый объект класса MutInt сможет хранить только одну часть данных, а именно целое число.
Метод __init__ является конструктором нашего класса. Конструктор - это специальный метод, который вызывается при создании объекта класса. Он принимает параметр value и сохраняет его в атрибуте value экземпляра. Экземпляр - это отдельный объект, созданный на основе чертежа класса.
Протестируем наш класс, создав скрипт на Python для его использования:
- Создайте новый файл с именем
test_mutint.pyв том же каталоге:
## test_mutint.py
from mutint import MutInt
## Create a MutInt object
a = MutInt(3)
print(f"Created MutInt with value: {a.value}")
## Modify the value (demonstrating mutability)
a.value = 42
print(f"Modified value to: {a.value}")
## Try adding (this will fail)
try:
result = a + 10
print(f"Result of a + 10: {result}")
except TypeError as e:
print(f"Error when adding: {e}")
В этом тестовом скрипте мы сначала импортируем класс MutInt из файла mutint.py. Затем создаем объект класса MutInt с начальным значением 3. Выводим начальное значение, затем изменяем его на 42 и выводим новое значение. Наконец, пытаемся добавить 10 к объекту MutInt, что приведет к ошибке, так как наш класс пока не поддерживает операцию сложения.
- Запустите тестовый скрипт, выполнив следующую команду в терминале:
python3 /home/labex/project/test_mutint.py
Терминал - это командная строка, в которой вы можете выполнять различные команды для взаимодействия с системой и вашим кодом. Выполнение этой команды запустит скрипт test_mutint.py.
Вы должны увидеть вывод, похожий на следующий:
Created MutInt with value: 3
Modified value to: 42
Error when adding: unsupported operand type(s) for +: 'MutInt' and 'int'
Наш класс MutInt успешно хранит и обновляет значение. Однако у него есть несколько ограничений:
- Он не выводится красиво при печати.
- Он не поддерживает математические операции, такие как сложение.
- Он не поддерживает сравнения.
- Он не поддерживает преобразования типов.
В следующих шагах мы пошагово устраним эти ограничения, чтобы наш класс MutInt вел себя более как настоящий примитивный тип.
Улучшение строкового представления
Когда вы выводите объект MutInt в Python, вы увидите такой вывод, как <__main__.MutInt object at 0x...>. Этот вывод не очень полезен, так как он не сообщает вам фактическое значение объекта MutInt. Чтобы сделать более понятным, что представляет собой объект, мы реализуем специальные методы для строкового представления.
- Откройте файл
mutint.pyв WebIDE и обновите его следующим кодом:
## mutint.py
class MutInt:
"""
A mutable integer class that allows its value to be modified after creation.
"""
__slots__ = ['value']
def __init__(self, value):
"""Initialize with an integer value."""
self.value = value
def __str__(self):
"""Return a string representation for printing."""
return str(self.value)
def __repr__(self):
"""Return a developer-friendly string representation."""
return f'MutInt({self.value!r})'
def __format__(self, fmt):
"""Support string formatting with format specifications."""
return format(self.value, fmt)
Мы добавили три важных метода в класс MutInt:
__str__(): Этот метод вызывается, когда вы используете функциюstr()на объекте или когда вы напрямую выводите объект. Он должен возвращать человекочитаемую строку.__repr__(): Этот метод предоставляет "официальное" строковое представление объекта. Он в основном используется для отладки и, желательно, должен возвращать строку, которая, если передать в функциюeval(), воссоздаст объект.__format__(): Этот метод позволяет использовать систему форматирования строк Python с объектамиMutInt. Вы можете использовать спецификации форматирования, такие как выравнивание и форматирование чисел.
- Создайте новый тестовый файл с именем
test_string_repr.pyдля тестирования этих новых методов:
## test_string_repr.py
from mutint import MutInt
## Create a MutInt object
a = MutInt(3)
## Test string representation
print(f"str(a): {str(a)}")
print(f"repr(a): {repr(a)}")
## Test direct printing
print(f"Print a: {a}")
## Test string formatting
print(f"Formatted with padding: '{a:*^10}'")
print(f"Formatted as decimal: '{a:d}'")
## Test mutability
a.value = 42
print(f"After changing value, repr(a): {repr(a)}")
В этом тестовом файле мы сначала импортируем класс MutInt. Затем создаем объект MutInt со значением 3. Мы тестируем методы __str__() и __repr__() с помощью функций str() и repr(). Мы также тестируем прямой вывод, форматирование строк и изменяемость объекта MutInt.
- Запустите тестовый скрипт:
python3 /home/labex/project/test_string_repr.py
Когда вы выполните эту команду, Python выполнит скрипт test_string_repr.py. Вы должны увидеть вывод, похожий на следующий:
str(a): 3
repr(a): MutInt(3)
Print a: 3
Formatted with padding: '****3*****'
Formatted as decimal: '3'
After changing value, repr(a): MutInt(42)
Теперь наши объекты MutInt выводятся красиво. Строковое представление показывает базовое значение, и мы можем использовать форматирование строк, как и с обычными целыми числами.
Разница между __str__() и __repr__() заключается в том, что __str__() предназначен для создания человекочитаемого вывода, в то время как __repr__() должен, желательно, создавать строку, которая, когда передается в eval(), воссоздает объект. Именно поэтому мы включили имя класса в метод __repr__().
Метод __format__() позволяет нашему объекту работать с системой форматирования Python, поэтому мы можем использовать спецификации форматирования, такие как выравнивание и форматирование чисел.
Добавление математических операций
В настоящее время наш класс MutInt не поддерживает математические операции, такие как сложение. В Python, чтобы включить такие операции для пользовательского класса, нам нужно реализовать специальные методы. Эти специальные методы также известны как "магические методы" или "дандер-методы", так как они окружены двойными подчеркиваниями. Давайте добавим функциональность сложения, реализовав соответствующие специальные методы для арифметических операций.
- Откройте файл
mutint.pyв WebIDE и обновите его следующим кодом:
## mutint.py
class MutInt:
"""
A mutable integer class that allows its value to be modified after creation.
"""
__slots__ = ['value']
def __init__(self, value):
"""Initialize with an integer value."""
self.value = value
def __str__(self):
"""Return a string representation for printing."""
return str(self.value)
def __repr__(self):
"""Return a developer-friendly string representation."""
return f'MutInt({self.value!r})'
def __format__(self, fmt):
"""Support string formatting with format specifications."""
return format(self.value, fmt)
def __add__(self, other):
"""Handle addition: self + other."""
if isinstance(other, MutInt):
return MutInt(self.value + other.value)
elif isinstance(other, int):
return MutInt(self.value + other)
else:
return NotImplemented
def __radd__(self, other):
"""Handle reversed addition: other + self."""
## For commutative operations like +, we can reuse __add__
return self.__add__(other)
def __iadd__(self, other):
"""Handle in-place addition: self += other."""
if isinstance(other, MutInt):
self.value += other.value
return self
elif isinstance(other, int):
self.value += other
return self
else:
return NotImplemented
Мы добавили три новых метода в класс MutInt:
__add__(): Этот метод вызывается, когда оператор+используется с нашим объектомMutIntслева. Внутри этого метода мы сначала проверяем, является ли операндotherэкземпляромMutIntилиint. Если это так, мы выполняем сложение и возвращаем новый объектMutIntс результатом. Если операндotherявляется чем-то другим, мы возвращаемNotImplemented. Это сообщает Python попробовать другие методы или вызватьTypeError.__radd__(): Этот метод вызывается, когда оператор+используется с нашим объектомMutIntсправа. Поскольку сложение является коммутативной операцией (т.е.a + bравноb + a), мы можем просто повторно использовать метод__add__.__iadd__(): Этот метод вызывается, когда оператор+=используется с нашим объектомMutInt. Вместо создания нового объекта он модифицирует существующий объектMutIntи возвращает его.
- Создайте новый тестовый файл с именем
test_math_ops.pyдля тестирования этих новых методов:
## test_math_ops.py
from mutint import MutInt
## Create MutInt objects
a = MutInt(3)
b = MutInt(5)
## Test regular addition
c = a + b
print(f"a + b = {c}")
## Test addition with int
d = a + 10
print(f"a + 10 = {d}")
## Test reversed addition
e = 7 + a
print(f"7 + a = {e}")
## Test in-place addition
print(f"Before a += 5: a = {a}")
a += 5
print(f"After a += 5: a = {a}")
## Test in-place addition with reference sharing
f = a ## f and a point to the same object
print(f"Before a += 10: a = {a}, f = {f}")
a += 10
print(f"After a += 10: a = {a}, f = {f}")
## Test unsupported operation
try:
result = a + 3.5 ## Adding a float is not supported
print(f"a + 3.5 = {result}")
except TypeError as e:
print(f"Error when adding float: {e}")
В этом тестовом файле мы сначала импортируем класс MutInt. Затем мы создаем несколько объектов MutInt и выполняем различные типы операций сложения. Мы также тестируем операцию сложения на месте и случай, когда выполняется неподдерживаемая операция (сложение с числом с плавающей точкой).
- Запустите тестовый скрипт:
python3 /home/labex/project/test_math_ops.py
Вы должны увидеть вывод, похожий на следующий:
a + b = MutInt(8)
a + 10 = MutInt(13)
7 + a = MutInt(10)
Before a += 5: a = MutInt(3)
After a += 5: a = MutInt(8)
Before a += 10: a = MutInt(8), f = MutInt(8)
After a += 10: a = MutInt(18), f = MutInt(18)
Error when adding float: unsupported operand type(s) for +: 'MutInt' and 'float'
Теперь наш класс MutInt поддерживает базовые операции сложения. Обратите внимание, что когда мы использовали +=, и a, и f были обновлены. Это показывает, что a += 10 модифицировал существующий объект, а не создал новый.
Это поведение с изменяемыми объектами аналогично встроенным изменяемым типам Python, таким как списки. Например:
a = [1, 2, 3]
b = a
a += [4, 5] ## Both a and b are updated
В отличие от этого, для неизменяемых типов, таких как кортежи, += создает новый объект:
c = (1, 2, 3)
d = c
c += (4, 5) ## c is a new object, d still points to the old one
Реализация операций сравнения
В настоящее время наши объекты MutInt не могут быть сравнены между собой или с обычными целыми числами. В Python операции сравнения, такие как ==, <, <=, >, >=, очень полезны при работе с объектами. Они позволяют нам определять отношения между разными объектами, что является важной частью многих сценариев программирования, таких как сортировка, фильтрация и условные операторы. Поэтому давайте добавим функциональность сравнения в наш класс MutInt, реализовав специальные методы для операций сравнения.
- Откройте файл
mutint.pyв WebIDE и обновите его следующим кодом:
## mutint.py
from functools import total_ordering
@total_ordering
class MutInt:
"""
A mutable integer class that allows its value to be modified after creation.
"""
__slots__ = ['value']
def __init__(self, value):
"""Initialize with an integer value."""
self.value = value
def __str__(self):
"""Return a string representation for printing."""
return str(self.value)
def __repr__(self):
"""Return a developer-friendly string representation."""
return f'MutInt({self.value!r})'
def __format__(self, fmt):
"""Support string formatting with format specifications."""
return format(self.value, fmt)
def __add__(self, other):
"""Handle addition: self + other."""
if isinstance(other, MutInt):
return MutInt(self.value + other.value)
elif isinstance(other, int):
return MutInt(self.value + other)
else:
return NotImplemented
def __radd__(self, other):
"""Handle reversed addition: other + self."""
return self.__add__(other)
def __iadd__(self, other):
"""Handle in-place addition: self += other."""
if isinstance(other, MutInt):
self.value += other.value
return self
elif isinstance(other, int):
self.value += other
return self
else:
return NotImplemented
def __eq__(self, other):
"""Handle equality comparison: self == other."""
if isinstance(other, MutInt):
return self.value == other.value
elif isinstance(other, int):
return self.value == other
else:
return NotImplemented
def __lt__(self, other):
"""Handle less-than comparison: self < other."""
if isinstance(other, MutInt):
return self.value < other.value
elif isinstance(other, int):
return self.value < other
else:
return NotImplemented
Мы внесли несколько важных улучшений:
Импортируем и используем декоратор
@total_orderingиз модуляfunctools. Декоратор@total_ordering- это мощный инструмент в Python. Он помогает нам сэкономить много времени и усилий при реализации методов сравнения для класса. Вместо того, чтобы вручную определять все шесть методов сравнения (__eq__,__ne__,__lt__,__le__,__gt__,__ge__), нам нужно определить только__eq__и один другой метод сравнения (в нашем случае__lt__). Затем декоратор автоматически сгенерирует оставшиеся четыре метода сравнения для нас.Добавляем метод
__eq__()для обработки операций сравнения на равенство (==). Этот метод используется для проверки, имеют ли два объектаMutIntили объектMutIntи целое число одинаковые значения.Добавляем метод
__lt__()для обработки операций сравнения "меньше чем" (<). Этот метод используется для определения, имеет ли один объектMutIntили объектMutIntпо сравнению с целым числом меньшее значение.Создайте новый тестовый файл с именем
test_comparisons.pyдля тестирования этих новых методов:
## test_comparisons.py
from mutint import MutInt
## Create MutInt objects
a = MutInt(3)
b = MutInt(3)
c = MutInt(5)
## Test equality
print(f"a == b: {a == b}") ## Should be True (same value)
print(f"a == c: {a == c}") ## Should be False (different values)
print(f"a == 3: {a == 3}") ## Should be True (comparing with int)
print(f"a == 5: {a == 5}") ## Should be False (different values)
## Test less than
print(f"a < c: {a < c}") ## Should be True (3 < 5)
print(f"c < a: {c < a}") ## Should be False (5 is not < 3)
print(f"a < 4: {a < 4}") ## Should be True (3 < 4)
## Test other comparisons (provided by @total_ordering)
print(f"a <= b: {a <= b}") ## Should be True (3 <= 3)
print(f"a > c: {a > c}") ## Should be False (3 is not > 5)
print(f"c >= a: {c >= a}") ## Should be True (5 >= 3)
## Test with a different type
print(f"a == '3': {a == '3'}") ## Should be False (different types)
В этом тестовом файле мы создаем несколько объектов MutInt и выполняем различные операции сравнения над ними. Мы также сравниваем объекты MutInt с обычными целыми числами и с другим типом (в данном случае строкой). Запустив эти тесты, мы можем убедиться, что наши методы сравнения работают как ожидается.
- Запустите тестовый скрипт:
python3 /home/labex/project/test_comparisons.py
Вы должны увидеть вывод, похожий на следующий:
a == b: True
a == c: False
a == 3: True
a == 5: False
a < c: True
c < a: False
a < 4: True
a <= b: True
a > c: False
c >= a: True
a == '3': False
Теперь наш класс MutInt поддерживает все операции сравнения.
Декоратор @total_ordering особенно полезен, так как он спасает нас от необходимости вручную реализовывать все шесть методов сравнения. Предоставив только __eq__ и __lt__, Python может автоматически вывести остальные четыре метода сравнения.
При реализации пользовательских классов, как правило, хорошей практикой является сделать их совместимыми как с объектами того же типа, так и с встроенными типами, где это имеет смысл. Вот почему наши методы сравнения обрабатывают как объекты MutInt, так и обычные целые числа. Таким образом, наш класс MutInt может быть использован более гибко в различных сценариях программирования.
Добавление преобразований типов (Type Conversions)
Наш класс MutInt в настоящее время поддерживает операции сложения и сравнения. Однако он не работает со встроенными в Python функциями преобразования, такими как int() и float(). Эти функции преобразования очень полезны в Python. Например, когда вы хотите преобразовать значение в целое число или число с плавающей точкой для различных вычислений или операций, вы полагаетесь на эти функции. Итак, давайте добавим возможности нашему классу MutInt для работы с ними.
- Откройте
mutint.pyв WebIDE и обновите его следующим кодом:
## mutint.py
from functools import total_ordering
@total_ordering
class MutInt:
"""
Изменяемый класс целых чисел, который позволяет изменять свое значение после создания.
"""
__slots__ = ['value']
def __init__(self, value):
"""Инициализация целочисленным значением."""
self.value = value
def __str__(self):
"""Возвращает строковое представление для печати."""
return str(self.value)
def __repr__(self):
"""Возвращает строковое представление, удобное для разработчиков."""
return f'MutInt({self.value!r})'
def __format__(self, fmt):
"""Поддержка форматирования строк со спецификациями формата."""
return format(self.value, fmt)
def __add__(self, other):
"""Обработка сложения: self + other."""
if isinstance(other, MutInt):
return MutInt(self.value + other.value)
elif isinstance(other, int):
return MutInt(self.value + other)
else:
return NotImplemented
def __radd__(self, other):
"""Обработка обратного сложения: other + self."""
return self.__add__(other)
def __iadd__(self, other):
"""Обработка сложения на месте (in-place addition): self += other."""
if isinstance(other, MutInt):
self.value += other.value
return self
elif isinstance(other, int):
self.value += other
return self
else:
return NotImplemented
def __eq__(self, other):
"""Обработка сравнения на равенство: self == other."""
if isinstance(other, MutInt):
return self.value == other.value
elif isinstance(other, int):
return self.value == other
else:
return NotImplemented
def __lt__(self, other):
"""Обработка сравнения "меньше чем": self < other."""
if isinstance(other, MutInt):
return self.value < other.value
elif isinstance(other, int):
return self.value < other
else:
return NotImplemented
def __int__(self):
"""Преобразование в int (integer)."""
return self.value
def __float__(self):
"""Преобразование в float (число с плавающей точкой)."""
return float(self.value)
__index__ = __int__ ## Поддержка индексации массивов и других операций, требующих индекс
def __lshift__(self, other):
"""Обработка сдвига влево: self << other."""
if isinstance(other, MutInt):
return MutInt(self.value << other.value)
elif isinstance(other, int):
return MutInt(self.value << other)
else:
return NotImplemented
def __rlshift__(self, other):
"""Обработка обратного сдвига влево: other << self."""
if isinstance(other, int):
return MutInt(other << self.value)
else:
return NotImplemented
Мы добавили три новых метода в класс MutInt:
__int__(): Этот метод вызывается, когда вы используете функциюint()для объекта нашего классаMutInt. Например, если у вас есть объектMutInta, и вы пишетеint(a), Python вызовет метод__int__()объектаa.__float__(): Аналогично, этот метод вызывается, когда вы используете функциюfloat()для нашего объектаMutInt.__index__(): Этот метод используется для операций, которые специально требуют целочисленный индекс. Например, когда вы хотите получить доступ к элементу в списке, используя индекс, или выполнить операции определения битовой длины (bit-length operations), Python требует целочисленный индекс.__lshift__(): Этот метод обрабатывает операции сдвига влево, когда объектMutIntнаходится слева от оператора<<.__rlshift__(): Этот метод обрабатывает операции сдвига влево, когда объектMutIntнаходится справа от оператора<<.
Метод __index__ имеет решающее значение для операций, требующих целочисленный индекс, таких как индексация списка, срезы (slicing) и операции определения битовой длины. В нашей простой реализации мы устанавливаем его таким же, как __int__, потому что значение нашего объекта MutInt можно напрямую использовать в качестве целочисленного индекса.
Методы __lshift__ и __rlshift__ необходимы для поддержки побитовых операций сдвига влево (bitwise left shift operations). Они позволяют нашим объектам MutInt участвовать в побитовых операциях, что является общим требованием для целочисленных типов.
- Создайте новый тестовый файл с именем
test_conversions.pyдля тестирования этих новых методов:
## test_conversions.py
from mutint import MutInt
## Создаем объект MutInt
a = MutInt(3)
## Тестируем преобразования
print(f"int(a): {int(a)}")
print(f"float(a): {float(a)}")
## Тестируем использование в качестве индекса
names = ['Dave', 'Guido', 'Paula', 'Thomas', 'Lewis']
print(f"names[a]: {names[a]}")
## Тестируем использование в битовых операциях (требуется __index__)
print(f"1 << a: {1 << a}") ## Сдвиг влево на 3
## Тестируем функции hex/oct/bin (требуется __index__)
print(f"hex(a): {hex(a)}")
print(f"oct(a): {oct(a)}")
print(f"bin(a): {bin(a)}")
## Изменяем и тестируем снова
a.value = 4
print(f"\nПосле изменения значения на 4:")
print(f"int(a): {int(a)}")
print(f"names[a]: {names[a]}")
- Запустите тестовый скрипт:
python3 /home/labex/project/test_conversions.py
Вы должны увидеть вывод, похожий на этот:
int(a): 3
float(a): 3.0
names[a]: Thomas
1 << a: 8
hex(a): 0x3
oct(a): 0o3
bin(a): 0b11
После изменения значения на 4:
int(a): 4
names[a]: Lewis
Теперь наш класс MutInt можно преобразовать в стандартные типы Python и использовать в операциях, требующих целочисленный индекс.
Метод __index__ особенно важен. Он был введен в Python, чтобы позволить объектам использоваться в ситуациях, когда требуется целочисленный индекс, таких как индексация списка, побитовые операции и различные функции, такие как hex(), oct() и bin().
С этими дополнениями наш класс MutInt теперь является довольно полным примитивным типом. Его можно использовать в большинстве контекстов, где использовалось бы обычное целое число, с дополнительным преимуществом - изменяемостью.
Полная реализация MutInt
Вот наша полная реализация MutInt со всеми добавленными нами функциями:
## mutint.py
from functools import total_ordering
@total_ordering
class MutInt:
"""
Изменяемый класс целых чисел, который позволяет изменять свое значение после создания.
"""
__slots__ = ['value']
def __init__(self, value):
"""Инициализация целочисленным значением."""
self.value = value
def __str__(self):
"""Возвращает строковое представление для печати."""
return str(self.value)
def __repr__(self):
"""Возвращает строковое представление, удобное для разработчиков."""
return f'MutInt({self.value!r})'
def __format__(self, fmt):
"""Поддержка форматирования строк со спецификациями формата."""
return format(self.value, fmt)
def __add__(self, other):
"""Обработка сложения: self + other."""
if isinstance(other, MutInt):
return MutInt(self.value + other.value)
elif isinstance(other, int):
return MutInt(self.value + other)
else:
return NotImplemented
def __radd__(self, other):
"""Обработка обратного сложения: other + self."""
return self.__add__(other)
def __iadd__(self, other):
"""Обработка сложения на месте (in-place addition): self += other."""
if isinstance(other, MutInt):
self.value += other.value
return self
elif isinstance(other, int):
self.value += other
return self
else:
return NotImplemented
def __eq__(self, other):
"""Обработка сравнения на равенство: self == other."""
if isinstance(other, MutInt):
return self.value == other.value
elif isinstance(other, int):
return self.value == other
else:
return NotImplemented
def __lt__(self, other):
"""Обработка сравнения "меньше чем": self < other."""
if isinstance(other, MutInt):
return self.value < other.value
elif isinstance(other, int):
return self.value < other
else:
return NotImplemented
def __int__(self):
"""Преобразование в int (integer)."""
return self.value
def __float__(self):
"""Преобразование в float (число с плавающей точкой)."""
return float(self.value)
__index__ = __int__ ## Поддержка индексации массивов и других операций, требующих индекс
def __lshift__(self, other):
"""Обработка сдвига влево: self << other."""
if isinstance(other, MutInt):
return MutInt(self.value << other.value)
elif isinstance(other, int):
return MutInt(self.value << other)
else:
return NotImplemented
def __rlshift__(self, other):
"""Обработка обратного сдвига влево: other << self."""
if isinstance(other, int):
return MutInt(other << self.value)
else:
return NotImplemented
Эта реализация охватывает ключевые аспекты создания нового примитивного типа в Python. Чтобы сделать его еще более полным, вы могли бы реализовать дополнительные методы для других операций, таких как вычитание, умножение, деление и т. д.
Резюме
В этом практическом занятии вы узнали, как создавать свои собственные примитивные типы в Python. В частности, вы научились создавать изменяемый класс целых чисел, аналогичный встроенным типам, реализовывать специальные методы для отображения объектов, добавлять поддержку математических и операций сравнения, а также обеспечивать преобразования типов для различных контекстов Python.
Эти концепции являются важными для понимания объектной модели Python и могут быть использованы для создания пользовательских типов, которые хорошо интегрируются с встроенными операциями. Чтобы расширить свои знания, попробуйте реализовать больше математических операций, добавить поддержку других встроенных функций и изучить сложные типы, такие как пользовательские коллекции. Пользовательские типы в Python - это мощный инструмент для расширения языка под конкретные нужды.