class Circle:
    def __init__(self, radius):
        self.radius = radius #all attributes must be preceded by "self."

"""
Explanation: Objects
Python is an object oriented language. As such it allows the definition of classes.
For instance lists are also classes, that's why there are methods associated with them (i.e. append()). Here we will see how to create classes and assign them attributes and methods.
Definition and initialization
A class gathers functions (called methods) and variables (called attributes).
The main of goal of having this kind of structure is that the methods can share a common
set of inputs to operate and get the desired outcome by the programmer.
In Python classes are defined with the word class and are always initialized
with the method __init__, which is a function that always must have as input argument the
word self. The arguments that come after self are used to initialize the class attributes.
In the following example we create a class called Circle.
End of explanation
"""


A = Circle(5.0)

"""
Explanation: To create an instance of this class we do it as follows
End of explanation
"""


print(A.radius)

"""
Explanation: We can check that the initialization worked out fine by printing its attributes
End of explanation
"""


class Circle:
    def __init__(self, radius):
        self.radius = radius #all attributes must be preceded by "self."
    def area(self):
        import math
        return math.pi * self.radius * self.radius

A = Circle(1.0)

print(A.radius)
print(A.area())

"""
Explanation: We now redefine the class to add new method called area that computes the area of the circle
End of explanation
"""


class Circle:
    def __init__(self, radius):
        self.radius = radius #all attributes must be preceded by "self."
    def area(self):
        import math
        return math.pi * self.radius * self.radius
    def enlarge(self):
        return Circle(2.0*self.radius)

A = Circle(5.0) # Create a first circle
B = A.enlarge() # Use the method to create a new Circle
print(B.radius) # Check that the radius is twice as the original one.

"""
Explanation: Exercise 3.1
Redefine the class Circle to include a new method called perimeter that returns the value of the circle's perimeter.
We now want to define a method that returns a new Circle with twice the radius of the input Circle.
End of explanation
"""


class Circle:
    def __init__(self, radius):
        self.radius = radius #all attributes must be preceded by "self."
    def area(self):
        import math
        return math.pi * self.radius * self.radius
    def enlarge(self):
        return Circle(2.0*self.radius)
    def add_area(self, c):
        return self.area() + c.area()

A = Circle(1.0)
B = Circle(2.0)
print(A.add_area(B))
print(B.add_area(A))

"""
Explanation: We now add a new method that takes as an input another element of the class Circle
and returns the total area of the two circles
End of explanation
"""


