Числа в Python — CodeChick
В этой статье вы узнаете, какие типы чисел есть в Python, научитесь приводить один тип к другому и производить с числами математические операции.
Какие числа поддерживаются
Python поддерживает комплексные (complex), целые числа (integer) и числа с плавающей точкой (float).
Целые числа и числа с плавающей точкой отличаются наличием или отсутствием десятичного разделителя. Например, 5 — целое число, а 5.0 — число с плавающей точкой.
Целые числа могут быть любой длины. Точность чисел с плавающей точкой обеспечивается только до 15 знака, на 16 могут возникать неточности.
Комплексные числа записываются следующим образом: x + yj. Здесь x — действительная часть, а y — мнимая.
Чтобы узнать, к какому типу относится переменная, используйте функцию type(). Если вы хотите узнать, принадлежит ли переменная определенному классу, используйте isinstance().
a = 5 print(type(a)) print(type(5.0)) c = 5 + 3j print(c + 3) print(isinstance(c, complex))
Вывод:
<class 'int'>
<class 'float'>
(8+3j)
True
Системы счисления
Числа, с которыми мы ежедневно сталкиваемся, представлены в десятичной системе счисления. Но программисты чащего всего работают с двоичной (основанием 2), шестнадцатеричной (основание 16) и восьмеричной (основание 8) системами счисления.
Эти числа в Python могут быть представлены с помощью соответствующего префикса. Они записаны в таблице ниже.
Система счисления | Префикс |
Двоичная |
'0B' |
Восьмеричная |
|
Шестнадцатеричная |
|
Вот как это выглядит:
# выведет 107 print(0b1101011) # выведет 253, т.к. 251 + 2) = 253 print(0xFB + 0b10) # выведет 13 print(0o15)
Вывод:
107
253
13
Приведение типов
В Python один тип числа можно конвертировать в другой. Это называется приведением типов.
Операции вроде сложения или вычитания неявно, то есть автоматически, приводят целочисленный тип к числу с плавающей точкой, если один из операндов является числом с плавающей точкой.
>>> 1 + 2.0 3.0
Как видите, при сложении 1 (это целое число) приводится к 1.0 (это число с плавающей точкой). Результат тоже будет числом с плавающей точкой.
Чтобы выполнить явное преобразование, вы можете использовать встроенные функции int(), float(), complex(). С помощью них к численным типам можно приводить даже строки.
>>> int(2.3)
2
>>> int(-2.8)
-2
>>> float(5)
5.0
>>> complex('3+5j')
(3+5j)
При приведении числа с плавающей точкой к целому десятичная часть удаляется.
Говорят, что она «обрезается».
Модуль decimal
Встроенный класс float порой может выдавать удивительные результаты. Все мы знаем, что 1.1 + 2.2 = 3.3, но Python, кажется, так не думает.
Введите в IDLE на своем компьютере такую строку:
>>> (1.1 + 2.2) == 3.3 False
Почему False? Что не так?
Приведем пример. Мы не можем представить дробь ⅓ в виде десятичного числа. ⅓ = 0.33333333… период — бесконечный. Поэтому хранить можно лишь приблизительное значение этого числа.
То есть десятичная дробь 0.1 — это бесконечная двоичная дробь 0.000110011001100110011… и компьютер может хранить в памяти только конечное число цифр после точки. Это лишь приближенное к 0.
>>> 1.1 + 2.2 3.3000000000000003
Для решения этой проблемы мы можем использовать модуль decimal, встроенный в Python. Тип float имеет точность до 15 знаков, а decimal — настраиваемую пользователем.
Разница налицо:
import decimal print(0.1) print(decimal.Decimal(0.1))
Вывод:
0.1
0.1000000000000000055511151231257827021181583404541015625
Этот модуль полезен, когда нам нужно вычислять десятичные дроби так же, как в школе.
Положение точки тоже сохраняется. Мы знаем, что 25.50 кг точнее, чем 25.5 кг, так как у этой дроби два числа после точки.
from decimal import Decimal as D
print(D('1.1') + D('2.2'))
print(D('1.2') * D('2.50'))
Вывод:
3.3
3.000
Обратите внимание на нули в вышеприведенном примере.
Вы можете подумать: почему бы тогда не использовать модуль decimal вместо float постоянно? Справедливый вопрос.
Дело в эффективности. Операции с float происходят гораздо быстрее, чем с decimal.
Когда стоит использовать decimal вместо float?
- При создании приложения для работы с финансами. Здесь нужна точность.
- Когда нужно держать уровень точности на определенном уровне.
- Когда нужно реализовать дробь с определенным числом цифр после точки.
Модуль fractions
В Python есть модуль fractions, он производить операции с дробными числами.
У дробей есть числитель и знаменатель — это целые числа. Также этот модуль позволяет производить операции с рациональными числами.
Создать fraction-объект можно разными способами. Давайте их разберем:
import fractions print(fractions.Fraction(1.5)) print(fractions.Fraction(5)) print(fractions.Fraction(1,3))
Вывод:
3/2
5
1/3
При создании fraction-объекта из float могут возникнуть неожиданные результаты. Происходит это, как говорилось выше, из-за несовершенного двоичного представления чисел с плавающей точкой.
К счастью, fraction позволяет создать экземпляр из строки. Настоятельно рекомендуем использовать именно этот способ, когда аргументом является десятичное число.
import fractions
# Число с плавающей точкой
# Вывод: 2476979795053773/2251799813685248
print(fractions.Fraction(1.1))
# Строка
# Вывод: 11/10
print(fractions.Fraction('1.1'))
Вывод:
2476979795053773/2251799813685248
11/10
Этот тип данных поддерживает все базовые математические операции.
from fractions import Fraction as F # со всеми работает print(F(1, 3) + F(1, 3)) print(1 / F(5, 6)) print(F(-3, 10) > 0) print(F(-3, 10) < 0)
Вывод:
2/3
6/5
False
True
Модуль math и random
Для решения тригонометрических, логарифмических, вероятностных и статистических задач Python располагает встроенными модулями math и random.
import math print(math.pi) print(math.cos(math.pi)) print(math.exp(10)) print(math.log10(1000)) print(math.sinh(1)) print(math.factorial(6))
Вывод:
3.141592653589793
-1.0
22026.465794806718
3.0
1.1752011936438014
720
👉Полный список функций и атрибутов модуля math.
import random print(random.randrange(10, 20)) x = ['а', 'б', 'в', 'г', 'д'] # Получаем случайный набор из х print(random.choice(x)) # Перемешиваем x random.shuffle(x) # Выводим в консоль перемешанный список x print(x) # Выводим в консоль случайный элемент print(random.random())
Примечание. Ваш вывод может отличать, поскольку функции модуля random выбирают элементы случайно.
Вывод:
13
а
['г', 'б', 'д', 'а', 'в']
0.038881285348306704
👉Полный список функция и атрибутов модуля random.
3 особенности чисел в Python, о которых вы, возможно, не знали / Хабр
Если вы писали код на Python, то весьма высока вероятность того, что вы, хотя бы в одной из своих программ, пользовались числами. Например, это могли быть целые числа для указания индекса значения в списке, или числа с плавающей точкой, представляющие суммы в некоей валюте.
Но числа в Python — это гораздо больше, чем, собственно, их числовые значения. Поговорим о трёх особенностях чисел в Python, с которыми вы, возможно, не знакомы.
№1: у чисел есть методы
В Python практически всё — это объект. Один из первых объектов, о котором узнаёт тот, кто начинает изучать Python — это str, используемый для представления строк. Возможно, вы сталкивались с использованием методов строк, вроде , который возвращает новую строку, все символы которой приведены к нижнему регистру:
>>> "HELLO".lower() 'hello'
Числа в Python тоже, как и строки, являются объектами. У них тоже есть методы. Например, целое число можно преобразовать в байтовую строку с помощью метода .to_bytes():
>>> n = 255 >>> n.to_bytes(length=2, byteorder="big") b'\x00\xff'
Параметр length указывает на количество байт, которые нужно использовать при составлении байтовой строки, а параметр byteorder определяет порядок байт. Например, установка параметра byteorder в значение «big» приводит к возврату байтовой строки, в которой старший байт расположен первым, а установка этого параметра в значение «little» приводит к тому, что первым идёт младший байт.
255 — это максимальное значение, которое может принимать 8-битное целое число. Поэтому в нашем случае при вызове метода .to_bytes() можно без проблем воспользоваться параметром length=1:
>>> n.to_bytes(length=1, byteorder="big") b'\xff'
А вот если записать в n число 256 и вызвать для него .
to_bytes() с параметром length=1, будет выдана ошибка OverflowError:
>>> n = 256 >>> n.to_bytes(length=1, byteorder="big") Traceback (most recent call last): File "<stdin>", line 1, in <module> OverflowError: int too big to convert
Преобразовать байтовую строку в целое число можно, воспользовавшись методом .from_bytes() класса int:
>>> int.from_bytes(b'\x06\xc1', byteorder="big") 1729
Методы класса вызывают, используя имя класса, а не его экземпляр. Именно поэтому в предыдущем примере метод .from_bytes() вызывают, обращаясь к int.
Любопытный факт: 1729 — это самое маленькое положительное число, которое можно представить в виде суммы кубов двух положительных чисел двумя способами. Исторический анекдот связывает это число с индийским математиком Сринивасой Рамануджаном, который рассказал о нём своему наставнику Готфри Харолду Харди.
Харди часто навещал Рамануджана, когда тот, умирая, находился в больнице в Патни. Именно в одно из таких посещений произошёл «инцидент» с номером такси. Харди приехал в Патни на такси, воспользовавшись своим излюбленным транспортным средством. Он вошёл в палату, где лежал Рамануджан. Начинать разговор Харди всегда было мучительно трудно, и он произнёс свою первую фразу: «Если не ошибаюсь, то номер такси, на котором я приехал, 1729. Мне кажется, это скучное число». На что Рамануджан тотчас же ответил: «Нет, Харди! О нет! Это очень интересное число. Это самое малое из чисел, представимых в виде суммы двух кубов двумя различными способами».
Один из способов представления числа 1729 в виде суммы двух кубов — это 13 + 123. Можете отыскать второй способ?
У чисел с плавающей точкой тоже есть методы. Возможно, самый полезный из них — это .is_integer(). Его используют для проверки того, есть ли у числа с плавающей точкой дробная часть:
>>> n = 2.0 >>> n.is_integer() True >>> n = 3.14 >>> n.is_integer() False
Вот — интересный метод .as_integer_ratio(). Он, вызванный для числа с плавающей точкой, возвращает кортеж, содержащий числитель и знаменатель дроби, представляющей это число:
>>> n.as_integer_ratio() (1, 2)
Правда, из-за ошибки представления чисел с плавающей точкой, иногда этот метод возвращает неожиданные результаты:
>>> n = 0.1 >>> n.as_integer_ratio() (3602879701896397, 36028797018963968)
Если надо — можно вызывать методы на числовых литералах, заключённых в круглые скобки:
>>> (255).to_bytes(length=1, byteorder="big") b'\xff' >>> (3.14).is_integer() False
Если обойтись без скобок — при попытке вызова метода на целочисленном литерале будет выдана ошибка SyntaxError. А вот при вызове метода числового литерала с плавающей точкой отсутствие скобок, что странно, не приведёт к ошибке:
>>> 255.SyntaxError: invalid syntax >>> 3.14.is_integer() False
Полный список методов числовых Python-типов можно найти в документации.
№2: числа обладают иерархией
В математике числа обладают естественной иерархией. Например, все натуральные числа являются целыми, а все целые числа — рациональными. Все рациональные числа — это вещественные числа, а все вещественные числа — это комплексные числа.
Похожие рассуждения применимы и к представлению чисел в Python. Здесь «числовая башня» выражается через абстрактные типы, содержащиеся в модуле numbers.
Числовая башня
Все числа в Python являются экземплярами класса Number:
>>> from numbers import Number >>> # Целые числа являются наследниками Number >>> isinstance(1729, Number) True >>> # Числа с плавающей точкой являются наследниками Number >>> isinstance(3.14, Number) True >>> # Комплексные числа являются наследниками Number >>> isinstance(1j, Number) True
Если нужно узнать о том, является ли некое Python-значение числовым, но при этом неважно то, каким именно числовым типом оно представлено, воспользуйтесь конструкцией isinstance(value, Number).
В Python имеется четыре дополнительных абстрактных типа, иерархия которых, начиная с наиболее общего числового типа, выглядит так:
Класс
Complexиспользуется для представления комплексных чисел. Тут имеется один встроенный конкретный тип —complex.Класс
Real— это представление вещественных чисел. Его единственный встроенный конкретный тип —float.Класс
Rationalпредставляет рациональные числа. Его единственным встроенным конкретным типом являетсяFraction.Класс
Integralприменяют для представления целых чисел. В нём имеется два встроенных конкретных типа —intиbool.
Так, погодите, а значения типа bool — это разве числа? Да — числа. Можете это проверить, воспользовавшись REPL:
>>> import numbers >>> # Комплексные числа являются наследниками Complex >>> isinstance(1j, numbers.Complex) True >>> # Комплексные числа не являются наследниками Real >>> isinstance(1j, numbers.Real) False >>> # Числа с плавающей точкой являются наследниками Real >>> isinstance(3.14, numbers.Real) True >>> # Числа с плавающей точкой не являются наследниками Rational >>> isinstance(3.14, numbers.Rational) False >>> # Объекты Fractions - это не наследники Rational >>> from fractions import Fraction >>> isinstance(Fraction(1, 2), numbers.Rational) True >>> # Объекты Fractions - это не наследники Integral >>> isinstance(Fraction(1, 2), numbers.Integral) False >>> # Целые числа - это наследники Integral >>> isinstance(1729, numbers.Integral) True >>> # Логические значения - это наследники Integral >>> isinstance(True, numbers.Integral) True >>> True == 1 True >>> False == 0 True
Всё это, на первый взгляд, выглядит вполне нормально.
Правда, порядок несколько нарушает то, что значения типа bool являются числами.
Странность Python: так как тип bool относится к классу Integral (на самом деле он — прямой наследник int), со значениями True и False можно вытворять довольно необычные вещи.
Например, True можно использовать в роли индекса для того чтобы получить второй элемент итерируемого объекта. А если поделить число на False — будет выдана ошибка ZeroDivisionError.
Попробуйте выполнить «False»[True] и 1 / False в REPL!
Но если присмотреться к числовым типам поближе, окажется, что в иерархии Python-чисел имеется пара своеобразных моментов.
Числа типа Decimal не укладываются в иерархию
Как уже было сказано, в «числовой башне» Python есть 4 конкретных числовых типа, соответствующих четырём абстрактным типам: complex, float, Fraction и int.
Но в Python имеется и пятый числовой тип, представленный классом Decimal. Этот тип используется для точного представления десятичных чисел и для преодоления ограничений арифметических операций с плавающей точкой.
Можно предположить, что числа типа Decimal являются наследниками Real, но это, на самом деле, не так:
>>> from decimal import Decimal
>>> import numbers
>>> isinstance(Decimal("3.14159"), numbers.Real)
FalseЕдинственный класс, наследником которого является класс Decimal — это Number:
>>> isinstance(Decimal("3.14159"), numbers.Complex)
False
>>> isinstance(Decimal("3.14159"), numbers.Rational)
False
>>> isinstance(Decimal("3.14159"), numbers.Integral)
False
>>> isinstance(Decimal("3.14159"), numbers.Number)
TrueЛогично то, что класс Decimal не является наследником Integral. В некоторой степени смысл есть и в том, что Decimal не является наследником Rational.
Но почему Decimal не является наследником Real или Complex?
Ответ кроется в исходном коде CPython:
Объекты Decimal обладают всеми методами, определёнными в классе Real, но эти объекты не должны регистрироваться в виде наследников Real, так как Decimal-числа не взаимодействуют с двоичными числами с плавающей точкой (например, результат операции Decimal(‘3.14’) + 2.71828 не определён). Но ожидается, что числа, классы которых являются наследниками абстрактного класса Real, способны взаимодействовать друг с другом (то есть — R1+R2 должно вычисляться в том случае, если числа R1 и R2 представлены типами, являющимися наследниками Real).
Получается, что объяснение странностей сводится к особенностям реализации.
Числа с плавающей точкой — странные создания
А вот числа с плавающей точкой, с другой стороны, реализуют абстрактный базовый класс Real. Они используются для представления вещественных чисел.
Но, из-за того, что компьютерная память не является неограниченным ресурсом, числа с плавающей точкой — это лишь конечные аппроксимации вещественных чисел. Это приводит к возможности написания «ненормальных» образцов кода вроде такого:
>>> 0.1 + 0.1 + 0.1 == 0.3 False
Числа с плавающей точкой хранятся в памяти в виде двоичных дробей. Это приводит к появлению некоторых проблем. Например, у дроби 1/3 нет конечного десятичного представления (после десятичной точки идёт бесконечное множество троек). А у дроби 1/10 нет конечного представления в виде двоичной дроби.
Другими словами, в компьютере нельзя совершенно точно представить число 0,1 — если только этот компьютер не обладает бесконечной памятью.
Со строго математической точки зрения все числа с плавающей точкой — это рациональные числа, за исключением float(«inf») и float(«nan»). Но программисты используют их в роли аппроксимаций вещественных чисел и воспринимают их, по большей части, как вещественные числа.
Странность Python: float(«nan») — это особое значение с плавающей точкой, представляющее собой «не число». Такие значения часто обозначают как NaN. Но, так как float — это числовой тип, isinstance(float(«nan»), Number) возвращает True.
Получается, что «не числа» — это числа.
В общем, числа с плавающей точкой — странные создания.
№3: набор числовых типов Python можно расширять
Абстрактный числовой базовый тип Python позволяет программисту создавать собственные абстрактные и конкретные числовые типы.
В качестве примера рассмотрим класс ExtendedInteger, который реализует числа в форме a+b√p, где a и b — целые числа, а p — простое число (обратите внимание: класс не обеспечивает то, что число p является простым):
import math import numbers class ExtendedInteger(numbers.Real): def init(self, a, b, p = 2) -> None: self.a = a self.b = b self.p = p self._val = a + (b * math.sqrt(p)) def repr(self): return f"{self.class.name}({self.a}, {self.b}, {self.p})" def str(self): return f"{self.a} + {self.b}√{self.p}" def trunc(self): return int(self._val) def float(self): return float(self._val) def hash(self): return hash(float(self._val)) def floor(self): return math.floor(self._val) def ceil(self): return math.ceil(self._val) def round(self, ndigits=None): return round(self._val, ndigits=ndigits) def abs(self): return abs(self._val) def floordiv(self, other): return self._val // other def rfloordiv(self, other): return other // self._val def truediv(self, other): return self._val / other def rtruediv(self, other): return other / self._val def mod(self, other): return self.
_val % other def rmod(self, other): return other % self._val def lt(self, other): return self._val < other def le(self, other): return self._val <= other def eq(self, other): return float(self) == float(other) def neg(self): return ExtendedInteger(-self.a, -self.b, self.p) def pos(self): return ExtendedInteger(+self.a, +self.b, self.p) def add(self, other): if isinstance(other, ExtendedInteger): # Если оба экземпляра имеют одно и то же значение p, # вернуть новый экземпляр ExtendedInteger if self.p == other.p: new_a = self.a + other.a new_b = self.b + other.b return ExtendedInteger(new_a, new_b, self.p) # В противном случае вернуть значение типа float else: return self._val + other._val # Если other - значение класса Integral, прибавить значение other к значению self.
a elif isinstance(other, numbers.Integral): new_a = self.a + other return ExtendedInteger(new_a, self.b, self.p) # Если other - значение класса Real, вернуть значение типа float elif isinstance(other, numbers.Real): return self._val + other._val # Если тип other неизвестен, позволить другим принять решение # о том, что делать в такой ситуации else: return NotImplemented def radd(self, other): # Сложение коммутативно, поэтому прибегнуть к add return self.add(other) def mul(self, other): if isinstance(other, ExtendedInteger): # Если оба экземпляра имеют одно и то же значение p, # вернуть новый экземпляр ExtendedInteger if self.p == other.p: new_a = (self.a * other.a) + (self.b * other.b * self.p) new_b = (self.a * other.b) + (self.b * other.a) return ExtendedInteger(new_a, new_b, self.
p) # в противном случае вернуть значение типа float else: return self._val * other._val # Если other - значение класса Integral, умножить его компоненты a и b на other elif isinstance(other, numbers.Integral): new_a = self.a * other new_b = self.b * other return ExtendedInteger(new_a, new_b, self.p) # Если other - значение класса Real, вернуть значение типа float elif isinstance(other, numbers.Real): return self._val * other # Если тип other неизвестен, позволить другим принять решение # о том, что делать в такой ситуации else: return NotImplemented def rmul(self, other): # Умножение коммутативно, поэтому прибегнуть к mul return self.mul(other) def pow(self, exponent): return self._val ** exponent def rpow(self, base): return base ** self._val
Для того чтобы обеспечить правильность реализации интерфейса Real конкретным типом — нужно создать реализации множества методов, в именах которых есть два символа подчёркивания.
Ещё нужно поразмыслить о том, как методы вроде .add() и .mul() взаимодействуют с другими типами, являющимися наследниками Real.
Обратите внимание: вышеприведённый пример не создавался в расчёте на его полноту или абсолютную правильность. Его цель — продемонстрировать читателю возможности работы с числами.
При наличии реализации ExtendedInteger можно заниматься следующими вычислениями:
>>> a = ExtendedInteger(1, 2) >>> b = ExtendedInteger(2, 3) >>> a ExtendedInteger(1, 2, 2) >>> # Проверяем то, что a - это наследник Number >>> isinstance(a, numbers.Number) True >>> # Проверяем то, что a - это наследник Real >>> isinstance(a, numbers.Real) True >>> print(a) 1 + 2√2 >>> a * b ExtendedInteger(14, 7, 2) >>> print(a * b) 14 + 7√2 >>> float(a) 3.8284271247461903
Иерархия числовых типов в Python — довольно гибкая структура.
Но, конечно, всегда стоит очень внимательно относиться к реализации типов, являющихся наследниками встроенных абстрактных базовых типов Python. Нужно обеспечить их корректную работу друг с другом.
В документации по Python можно найти несколько советов по реализации собственных типов, которые стоит прочесть тому, кто решит заняться созданием собственных числовых типов. Такому человеку ещё полезно будет ознакомиться с реализацией Fraction.
Итоги
Вот — те три особенности Python-чисел, которые мы здесь обсуждали:
У чисел есть методы, как и у практически всех остальных объектов в Python.
Числа обладают иерархией, даже несмотря на то, что их чёткие взаимоотношения несколько портит наличие типов
Decimalиfloat.Программисты могут создавать собственные числовые типы, которые вписываются в иерархию числовых типов Python.
Может быть, вы узнали из этого материала не только об этих особенностях чисел, но и ещё о чём-нибудь, что вам пригодится.
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.
Присоединяйтесь к нашей команде.
чисел — Числовые абстрактные базовые классы — Документация по Python 3.11.3
Исходный код: Lib/numbers.py
Модуль номеров ( PEP 3141 ) определяет иерархию числовых
абстрактные базовые классы, которые постепенно определяют
больше операций. Ни один из типов, определенных в этом модуле, не предназначен для создания экземпляров.
- класс номеров.Номер
Корень числовой иерархии. Если вы просто хотите проверить, является ли аргумент x — это число, неважно, какого рода, используйте
isinstance(x, Number).
Числовая башня
- класс номеров.Комплекс
Подклассы этого типа описывают комплексные числа и включают операции которые работают на встроенном комплексе
типа. Это: преобразования всложныйилогический,реальный,образ,+,-,*,/,**,абс(),сопряженное(),==, и!=. Все, кроме-и!=, являются абстрактными.- настоящий
Реферат. Извлекает действительную составляющую этого числа.
- изображение
Реферат.
Извлекает мнимую составляющую этого числа.
- абстрактный метод сопряженный ()
Реферат. Возвращает комплексное сопряжение. Например,
(1+3j).conjugate() == (1-3j).
- класс номеров.Настоящий
К
Complex,Realдобавляет операции, которые работают с реальными числа.Короче говоря, это: преобразование в
float,math.trunc(),round(),math.floor(),math.ceil(),divmod(),//,%,<,<=,>и>=.Real также предоставляет значения по умолчанию для
complex(),real,imagиconjugate().
- класс номеров.Rational
Подтипы
Действительноеи добавляетчислительизнаменательсвойств.
Он также обеспечивает значение по умолчанию для с плавающей запятой().Числитель
изнаменательзначений должны быть экземплярамиIntegralи должны быть в наименьших условиях сзнаменательположительный.- числитель
Реферат.
- знаменатель
Реферат.
- класс номеров. Интеграл
Subtypes
Rationalи добавляет преобразование в 9,|,~.
Примечания для разработчиков типа
Разработчики должны быть осторожны, чтобы сделать равные числа равными и хешировать
их к одним и тем же значениям. Это может быть тонко, если есть два разных
расширения действительных чисел. Например, дроби . Дробь реализует hash() следующим образом:
по определению __hash__(я):
если self.
знаменатель == 1:
# Получить целые числа правильно.
хэш возврата (self.numerator)
# Дорогая проверка, но точно правильная.
если я == поплавок (я):
вернуть хэш (с плавающей запятой (сам))
еще:
# Используйте хэш кортежа, чтобы избежать высокой частоты коллизий на
# простые дроби.
хеш возврата((self.numerator, self.denominator))
Добавление дополнительных числовых ABC
Есть, конечно, и другие возможные азбуки для чисел, и это было бы
быть плохой иерархией, если она исключает возможность добавления
те. Вы можете добавить MyFoo между Complex и Реальный с:
класс MyFoo (комплекс): ... MyFoo.register(Настоящий)
Реализация арифметических операций
Мы хотим реализовать арифметические операции так, чтобы смешанный режим
операции либо вызывают реализацию, автор которой знал о
типы обоих аргументов или преобразовать оба в ближайший встроенный тип
и сделать операцию там.
Для подтипов Интеграл , это
означает, что __add__() и __radd__() должны быть определены как:
класс MyIntegral(Integral):
def __add__(я, другой):
если isinstance (другое, MyIntegral):
вернуть do_my_adding_stuff(я, другой)
elif isinstance (другое, OtherTypeIKnowAbout):
вернуть do_my_other_adding_stuff(я, другой)
еще:
вернуть нереализованный
def __radd__(я, другой):
если isinstance (другое, MyIntegral):
вернуть do_my_adding_stuff(другое, себя)
elif isinstance (другое, OtherTypeIKnowAbout):
вернуть do_my_other_adding_stuff(другое, себя)
elif isinstance (другой, интеграл):
вернуть int(другое) + int(себя)
elif isinstance (другое, реальное):
вернуть поплавок (другой) + поплавок (сам)
elif isinstance (другой, сложный):
вернуть комплекс (другой) + комплекс (я)
еще:
вернуть нереализованный
Существует 5 различных случаев для операции смешанного типа над подклассами Комплекс .
Я буду ссылаться на весь приведенный выше код, который не
см. MyIntegral и OtherTypeIKnowAbout как
«шаблон». a будет экземпляром A , который является подтипом
Комплекс ( a : A <: Комплекс ) и b : B <:
Комплекс . Я рассмотрю a + b :
Если
Аопределяет__add__()который принимаетb, все хорошо.Если
Aвозвращается к стандартному коду, вернуть значение из__add__(), мы бы упустили возможность чтоBопределяет более интеллектуальный__radd__(), поэтому шаблон должен возвращатьNotImplementedиз__добавить__(). (Илиможет не реализовать__add__()в все.)Затем
B__radd__()получает шанс. Если он принимаети, все хорошо.Если он возвращается к шаблону, больше нет возможных методы, чтобы попробовать, так что это где реализация по умолчанию должен жить.
Если
B <: A, Python пытается использоватьB.__radd__доА.__добавить__. Это нормально, потому что это было реализовано с помощью знаниеA, поэтому он может обрабатывать эти экземпляры до делегированиеКомплекс.
Если A <: Сложные и B <: Действительное без обмена какими-либо другими знаниями,
тогда подходящей общей операцией является операция, включающая встроенный
в комплексе , и оба __radd__() приземляются там, поэтому a+b
== б+а .
Поскольку большинство операций над любым данным типом будут очень похожими,
может быть полезно определить вспомогательную функцию, которая генерирует
прямые и обратные экземпляры любого заданного оператора.
Например, дробей.Дробь использует:
по определению _operator_fallbacks (мономорфный_оператор, резервный_оператор):
защита вперед (а, б):
если isinstance(b, (int, Fraction)):
вернуть monomorphic_operator(a, b)
elif isinstance(b, float):
вернуть fallback_operator (с плавающей запятой (а), б)
elif isinstance (b, комплекс):
вернуть fallback_operator (комплекс (а), б)
еще:
вернуть нереализованный
forward.__name__ = '__' + fallback_operator.__name__ + '__'
вперед.__doc__ = мономорфный_оператор.__doc__
деф реверс(б, а):
если isinstance(a, Rational):
# Включает целые числа.
вернуть monomorphic_operator(a, b)
elif isinstance(a, Real):
return fallback_operator (с плавающей запятой (a), с плавающей запятой (b))
elif isinstance(a, Комплекс):
return fallback_operator (комплекс (а), комплекс (б))
еще:
вернуть нереализованный
reverse.
__name__ = '__r' + резервный_оператор.__name__ + '__'
reverse.__doc__ = monomorphic_operator.__doc__
возврат вперед, назад
определение _add (а, б):
"""а + б"""
return Fraction (a.числитель * b.знаменатель +
б.числитель * а.знаменатель,
а.знаменатель * б.знаменатель)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...
Числа Python, преобразование типов и математика (с примерами)
В этом руководстве вы узнаете о числах Python, преобразовании типов и математике с помощью примеров.
Числовые типы данных используются для хранения числовых значений.
Python поддерживает целые числа, числа с плавающей запятой и комплексные числа. В Python они определены как классы int , float и complex .
-
ряд- содержит целые числа со знаком неограниченной длины. -
float- содержит числа с плавающей запятой и точность до 15 знаков после запятой.
-
комплекс- содержит комплексные числа.
Числовой тип данных Python
Целые числа и числа с плавающей запятой разделяются наличием или отсутствием десятичной точки. Например,
- 5 — это целое число .
- 5.42 — число с плавающей запятой.
Комплексные числа записываются в виде x + yj , где x — действительная часть, а y — мнимая часть.
Мы можем использовать функцию type() , чтобы узнать, к какому классу принадлежит переменная или значение.
Давайте посмотрим пример,
num1 = 5 print(num1, 'имеет тип', type(num1)) число2 = 5,42 печать (число2, 'имеет тип', тип (число2)) число3 = 8+2j print(num3, 'имеет тип', type(num3))
Вывод
5 имеет тип <класс 'int'> 5.42 имеет тип(8+2j) имеет тип
В приведенном выше примере мы создали три переменные с именами num1 , num2 и num3 со значениями 5 , 5,42 , 900 8+2j соответственно.
Мы также использовали функцию type() , чтобы узнать, к какому классу принадлежит определенная переменная. С
- 5 является целым числом,
type()возвращаетintкак класс num1 т.е. - 5.42 - это значение с плавающей запятой,
type()возвращает float как класс num2 , т.е. -
1 + 2j— комплексное число,type()возвращает комплекс как класс num3 , т. е.
Системы счисления
Числа, с которыми мы имеем дело каждый день, имеют десятичную систему счисления (основание 10) .
Но программисты должны работать с двоичной (основание 2) , шестнадцатеричной (основание 16) и восьмеричной (основание 8) системами счисления.
В Python мы можем представить эти числа, поместив соответствующий префикс перед этим числом. В следующей таблице перечислены эти префиксы.
| Система счисления | Префикс |
|---|---|
| Двоичный | 0b или 0B |
| Восьмеричный | 00 или 00 |
| Шестнадцатеричный | 0x или 0X |
Вот несколько примеров
print(0b1101011) # отпечатков 107 print(0xFB + 0b10) # печатает 253 print(0o15) # печатает 13
Преобразование типов в Python
В программировании преобразование типов — это процесс преобразования одного типа числа в другой.
Такие операции, как сложение и вычитание, неявно (автоматически) преобразуют целые числа в числа с плавающей точкой, если один из операндов является числом с плавающей запятой. Например,
print(1 + 2.0) # выводит 3.0
Здесь мы видим выше, что 1 (целое) преобразуется в 1.0 (с плавающей запятой) для сложения, и результат также является числом с плавающей запятой.
Явное преобразование типов
Мы также можем использовать встроенные функции, такие как int() , float() и complex() для явного преобразования между типами. Эти функции могут даже конвертировать из строк.
число1 = целое (2.3)
print(num1) # печатает 2
число2 = целое (-2,8)
print(num2) # печатает -2
число3 = число с плавающей запятой (5)
print(num3) # печатает 5.0
число4 = комплекс('3+5j')
print(num4) # печатает (3 + 5j) Здесь при преобразовании из числа с плавающей запятой в целое число усекается (удаляются десятичные части).
Аналогичным образом при преобразовании из целого числа в число с плавающей запятой .0 добавляется к числу в постфиксе.
Случайный модуль Python
Python предлагает модуль random для генерации случайных чисел или выбора случайного элемента из итератора.
Сначала нам нужно импортировать модуль random . Например,
случайный импорт печать (случайный. случайный диапазон (10, 20)) список1 = ['а', 'б', 'с', 'г', 'е'] # получить случайный элемент из list1 печать (случайный выбор (список1)) # Перемешать список1 случайный. случайный (список1) # Распечатать перетасованный список1 печать (список1) # Напечатать случайный элемент печать(случайный.случайный())
Выход
15 а ['д', 'б', 'в', 'е', 'а'] 0,6716121217631744
Чтобы узнать больше о модуле random , посетите Python Random Module.
Python Mathematics
Python предлагает модуль math для выполнения различных математических операций, таких как тригонометрия, логарифмы, вероятность и статистика и т. д. Например,
import math печать (math.pi) печать (math.cos (math.pi)) печать (математика.выражение (10)) печать (математика. log10 (1000)) печать (математика.

к. 251 + 2) = 253
print(0xFB + 0b10)
# выведет 13
print(0o15)
038881285348306704
lower()
'hello'
0
>>> n.is_integer()
True
>>> n = 3.14
>>> n.is_integer()
False
SyntaxError: invalid syntax
>>> 3.14.is_integer()
False
Complex)
True
>>> # Комплексные числа не являются наследниками Real
>>> isinstance(1j, numbers.Real)
False
>>> # Числа с плавающей точкой являются наследниками Real
>>> isinstance(3.14, numbers.Real)
True
>>> # Числа с плавающей точкой не являются наследниками Rational
>>> isinstance(3.14, numbers.Rational)
False
>>> # Объекты Fractions - это не наследники Rational
>>> from fractions import Fraction
>>> isinstance(Fraction(1, 2), numbers.Rational)
True
>>> # Объекты Fractions - это не наследники Integral
>>> isinstance(Fraction(1, 2), numbers.Integral)
False
>>> # Целые числа - это наследники Integral
>>> isinstance(1729, numbers.Integral)
True
>>> # Логические значения - это наследники Integral
>>> isinstance(True, numbers.Integral)
True
>>> True == 1
True
>>> False == 0
True
a = a
self.b = b
self.p = p
self._val = a + (b * math.sqrt(p))
def repr(self):
return f"{self.class.name}({self.a}, {self.b}, {self.p})"
def str(self):
return f"{self.a} + {self.b}√{self.p}"
def trunc(self):
return int(self._val)
def float(self):
return float(self._val)
def hash(self):
return hash(float(self._val))
def floor(self):
return math.floor(self._val)
def ceil(self):
return math.ceil(self._val)
def round(self, ndigits=None):
return round(self._val, ndigits=ndigits)
def abs(self):
return abs(self._val)
def floordiv(self, other):
return self._val // other
def rfloordiv(self, other):
return other // self._val
def truediv(self, other):
return self._val / other
def rtruediv(self, other):
return other / self._val
def mod(self, other):
return self.
_val % other
def rmod(self, other):
return other % self._val
def lt(self, other):
return self._val < other
def le(self, other):
return self._val <= other
def eq(self, other):
return float(self) == float(other)
def neg(self):
return ExtendedInteger(-self.a, -self.b, self.p)
def pos(self):
return ExtendedInteger(+self.a, +self.b, self.p)
def add(self, other):
if isinstance(other, ExtendedInteger):
# Если оба экземпляра имеют одно и то же значение p,
# вернуть новый экземпляр ExtendedInteger
if self.p == other.p:
new_a = self.a + other.a
new_b = self.b + other.b
return ExtendedInteger(new_a, new_b, self.p)
# В противном случае вернуть значение типа float
else:
return self._val + other._val
# Если other - значение класса Integral, прибавить значение other к значению self.
a
elif isinstance(other, numbers.Integral):
new_a = self.a + other
return ExtendedInteger(new_a, self.b, self.p)
# Если other - значение класса Real, вернуть значение типа float
elif isinstance(other, numbers.Real):
return self._val + other._val
# Если тип other неизвестен, позволить другим принять решение
# о том, что делать в такой ситуации
else:
return NotImplemented
def radd(self, other):
# Сложение коммутативно, поэтому прибегнуть к add
return self.add(other)
def mul(self, other):
if isinstance(other, ExtendedInteger):
# Если оба экземпляра имеют одно и то же значение p,
# вернуть новый экземпляр ExtendedInteger
if self.p == other.p:
new_a = (self.a * other.a) + (self.b * other.b * self.p)
new_b = (self.a * other.b) + (self.b * other.a)
return ExtendedInteger(new_a, new_b, self.
p)
# в противном случае вернуть значение типа float
else:
return self._val * other._val
# Если other - значение класса Integral, умножить его компоненты a и b на other
elif isinstance(other, numbers.Integral):
new_a = self.a * other
new_b = self.b * other
return ExtendedInteger(new_a, new_b, self.p)
# Если other - значение класса Real, вернуть значение типа float
elif isinstance(other, numbers.Real):
return self._val * other
# Если тип other неизвестен, позволить другим принять решение
# о том, что делать в такой ситуации
else:
return NotImplemented
def rmul(self, other):
# Умножение коммутативно, поэтому прибегнуть к mul
return self.mul(other)
def pow(self, exponent):
return self._val ** exponent
def rpow(self, base):
return base ** self._val
Извлекает мнимую составляющую этого числа.
Он также обеспечивает значение по умолчанию для
знаменатель == 1:
# Получить целые числа правильно.
хэш возврата (self.numerator)
# Дорогая проверка, но точно правильная.
если я == поплавок (я):
вернуть хэш (с плавающей запятой (сам))
еще:
# Используйте хэш кортежа, чтобы избежать высокой частоты коллизий на
# простые дроби.
хеш возврата((self.numerator, self.denominator))

__name__ = '__r' + резервный_оператор.__name__ + '__'
reverse.__doc__ = monomorphic_operator.__doc__
возврат вперед, назад
определение _add (а, б):
"""а + б"""
return Fraction (a.числитель * b.знаменатель +
б.числитель * а.знаменатель,
а.знаменатель * б.знаменатель)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...

0) # выводит 3.0 