Polynomials - constructors

https://docs.python.org/3/tutorial/classes.html

https://www.python-course.eu/polynomial_class_in_python.php

INTRODUCTION

Creating a new class creates a new 'type' of object, allowing new 'instances' of that type to be made. A class in Python is defined by a 'class' statement (a compound statement). Class names should be in a StudlyCups style.

When a class definition is entered, a new namespace is created, and used as the local scope.


# Syntax.

class ClassName:   # a 'class object' will be created
    docstring   # optional
    statements

class DerivedClassName(BaseClassName):   # inheritance
    docstring   # optional
    statements

class DerivedClassName(Base1, Base2, Base3):   # multiple inheritance
    docstring   # optional
    statements

# Now ClassName has a reference to the class object.
instance = ClassName()   # 'calling' a class object
ClassName.__doc__   # access to the docstring
instance.__class__   # access to the class object

POLYNOMIALS


class Poly:
    """The class for polynomials of a single variable."""

    def __init__(self, c=0, n=0):   # a special method (constructor)
        self.data = (n+1) * [0]
        self.data[-1] = c

    def degree(self):   # a method
        return len(self.data) -1

    def is_zero(self):   # a method, data can be [0], [0, 0], ...
        return all(c == 0 for c in self.data)

# Testing the constructor.
poly1 = Poly(3, 5)
# Class 'instantiation', poly1 is a new 'instance'.
# __init__() is automatically invoked.

assert len(poly1.data) == 6
assert poly1.data == [0, 0, 0, 0, 0, 3]   # data is an instance attribute

assert poly1.degree() == 5   # calling a method
assert Poly.degree(poly1) == 5

assert not poly1.is_zero()
assert Poly(0, 3).is_zero()   # data is [0, 0, 0, 0]

poly1.value = 124   # a new instance attribute

CLASS ATTRIBUTES

Class variables (attributes) are shared by all instances of the class.


class Poly:
    counter = 0   # counting created polynomials, a class attribute

    def __init__(self, c=0, n=0):   # a special method
        self.data = (n+1) * [0]
        self.data[-1] = c
        Poly.counter += 1   # using a class attribute
        #Poly.counter = Poly.counter + 1   # the same
        # C/C++: 'a (op)= b' is equal to 'a = a (op) b', (op) can be +,-,*,/

    def __del__(self):
        # It is called when the reference counter drops to zero.
        # Not exactly a destructor from C++.
        Poly.counter -= 1
        #Poly.counter = Poly.counter - 1   # the same

assert Poly.counter == 0
poly1 = Poly(3, 5)
assert Poly.counter == 1
assert poly1.counter == 1   # access from the instance (read-only)
del poly1
assert Poly.counter == 0

STRING REPRESENTATIONS


class Poly:

    def __str__(self):   # the informal string representation, str(instance)
        return str(self.data)
        # it can be also "p_0 + p_1 x + p_2 x^2 + ..."

    def __repr__(self):   # the formal (canonical) string representation, repr(instance)
        if self.is_zero():   # calling a method inside the class, Poly.is_zero(self)
            return "Poly()"
        else:
            L = list()
            for (i, c) in enumerate(self.data):
                if c != 0:
                    L.append("Poly({}, {})".format(repr(c), i))
            return " + ".join(L)

poly1 = Poly(3, 5)
poly1.data[0] = -2   # addition is not implemented yet ...
print(str(poly1))   # [-2, 0, 0, 0, 0, 3]
print(repr(poly1))   # Poly(-2, 0) + Poly(3, 5)