Многочлен — это выражение вида
$x^3 + 2x^2 - 10x + 5$. Будем хранить
многочлены в виде списков коэффициентов:
[1, 2, -10, 5]
. Но лучше перевернем:
[5, -10, 2, 1]
. 5 — это коээфициент при
$x^0$. -10 — это коэффициент при $x^1=x$.
2 — коэффициент при $x^2$, 1 — коэффициент при
$x^3$.
Объекты класса многочлен хранят многочлены, эти объекты можно складывать, красиво распечатывать, искать значение в точке: $p(x) = x^3 + 2x^2 - 10x + 5$, тогда $p(0) = 5$, $p(1) = 1^3 + 2\cdot 1^2 - 10\cdot1 + 5 = 1 + 2 - 10 + 5 = -2$.
Класс Poly
будет иметь одно поле (данные)
со списком коэффициентов, и три указанных
выше метода (распечатать, сложить, посчитать
значение в точке. Давайте четвертый добавим —
степень)
class Poly:
# передаем список коэффициентов мн-на
# игнорируем ситуацию, что старший коэф.
# может быть 0
def __init__(self, coefs):
self.coefs = coefs
# выдает степень многочлена.
def deg(self):
return len(self.coefs) - 1
# Использование класса:
p1 = Poly([5, -10, 2, 1])
p2 = Poly([-1, 0, 1]) # -1 + 0*x + 1*x^2 = x^2-1
print(p1.deg())
print(p2.deg())
3 2
Расширим наш класс, добавим печать, сложение, значение в точке:
class Poly:
def __init__(self, coefs):
self.coefs = coefs
def deg(self):
return len(self.coefs) - 1
# посчитать значение в точке x
def value(self, x):
# n = 0
# sum = 0
# for coef in self.coefs:
# sum += coef * x ** n
# n += 1
sum = 0
for n, coef in enumerate(self.coefs):
#n перебирает индексы 0, 1, 2, 3
#coef перебирает элементы массива
sum += coef * x ** n
return sum
# сделать красивую строку из многочлена
def pretty(self):
#сначала сделаем список одночленов
#если коэффициенты [2, 0, 3, -1], то
#получим [2, 0, 3x^2, -x^3].
#add_coef(1, 'x') -> 'x'
#add_coef(2, 'x') -> '2x'
#add_coef(-3, 'x') -> '-3x'
#add_coef(0, 'x') -> '0'
def add_coef(c, var):
if c == 0:
return '0'
if c == 1:
return var
if c == -1:
return '-' + var
return f'{c}{var}'
#add_polys('2x', '3x^2') -> '2x+3x^2'
#add_polys('2x', '-3x^2') -> '2x-3x^2'
#add_polys('0', '-3x^2') -> '-3x^2'
def add_polys(m1, m2):
if m1 == '0':
return m2
if m2 == '0':
return m1
if m2[0] == '-':
return m1 + m2
return m1 + '+' + m2
# [4, 5, 3, 2] -> 4 + 5x + 3x^2
result = str(self.coefs[0]) # '4'
# перебираем список [5, 3, 2]
for d, coef in enumerate(self.coefs[1:]):
result = add_polys(result, add_coef(coef, f'x^{d+1}'))
return result
# Сэкономим на сложении многочленов. Проверим,
# что есть:
p1 = Poly([5, -10, 2, 1])
p2 = Poly([-1, 0, 1]) # -1 + 0*x + 1*x^2 = x^2-1
print(p1.pretty())
print(p2.pretty())
print(p1.value(0)) # должно быть 5
print(p1.value(1)) # должно быть -2
5-10x^1+2x^2+x^3 -1+x^2 5 -2
# пример кода с пробемами:
a = [5, -10, 2, 1]
p1 = Poly(a)
print(p1.pretty())
a.append(42) # a = [5, -10, 2, 1, 42]
print(p1.pretty())
5-10x^1+2x^2+x^3 5-10x^1+2x^2+x^3+42x^4
Многочлен p1 изменился, потому что он хранит ссылку на список, и если кто-то этот список меняет, многочлену тоже приходится меняться.
Исправляем:
class Poly:
def __init__(self, coefs):
# теперь список копируется
# coefs.copy() - требовал бы, что
# coefs это список.
self.coefs = list(coefs)
...
p1 = Poly( (10, 20, 30) ) # можно передать tuple
p1 = Poly(range(10)) # любое перечисление
p1.coefs = [4, 5, 6]
print(p1.pretty())
4+5x^1+6x^2
Такое ручное изменение содержимого объекта
никогда не приветствуется. (принцип инкапсуляции),
считается, что мы не знаем, как устроены объекты.
Как хранятся коэффициенты, может, они вообще
не в списке хранятся. Любое действие с объектом
принято делать через методы.
Чтобы явно показать, что мы не хотим, чтобы
кто-то писал p1.coefs
, надо поле coefs
назвать
с подчеркивания: _coefs
. Все, что начинается
с подчеркивания, принято вызывать только внутри
класса.
class Poly:
def __init__(self, coefs):
self._coefs = coefs
def deg(self):
return len(self._coefs) - 1
# посчитать значение в точке x
def value(self, x):
# n = 0
# sum = 0
# for coef in self.coefs:
# sum += coef * x ** n
# n += 1
sum = 0
for n, coef in enumerate(self._coefs):
#n перебирает индексы 0, 1, 2, 3
#coef перебирает элементы массива
sum += coef * x ** n
return sum
# сделать красивую строку из многочлена
def pretty(self):
#сначала сделаем список одночленов
#если коэффициенты [2, 0, 3, -1], то
#получим [2, 0, 3x^2, -x^3].
#add_coef(1, 'x') -> 'x'
#add_coef(2, 'x') -> '2x'
#add_coef(-3, 'x') -> '-3x'
#add_coef(0, 'x') -> '0'
def add_coef(c, var):
if c == 0:
return '0'
if c == 1:
return var
if c == -1:
return '-' + var
return f'{c}{var}'
#add_polys('2x', '3x^2') -> '2x+3x^2'
#add_polys('2x', '-3x^2') -> '2x-3x^2'
#add_polys('0', '-3x^2') -> '-3x^2'
def add_polys(m1, m2):
if m1 == '0':
return m2
if m2 == '0':
return m1
if m2[0] == '-':
return m1 + m2
return m1 + '+' + m2
# [4, 5, 3, 2] -> 4 + 5x + 3x^2
result = str(self._coefs[0]) # '4'
# перебираем список [5, 3, 2]
for d, coef in enumerate(self._coefs[1:]):
if d == 0:
var = 'x'
else:
var = f'x^{d + 1}'
result = add_polys(add_coef(coef, var), result)
return result
# Сэкономим на сложении многочленов. Проверим,
# что есть:
p1 = Poly([5, -10, 2, 1])
p2 = Poly([-1, 0, 1]) # -1 + 0*x + 1*x^2 = x^2-1
print(p1.pretty())
print(p2.pretty())
print(p1.value(0)) # должно быть 5
print(p1.value(1)) # должно быть -2
print(p1._coefs) # так не делаем. Имя с _