Ejemplos de programas en Python Orientado a Objetos

Class Circle (circle.py)

In [2]:
"""
circle.py: The circle module, which defines a Circle class.
"""
from math import pi

class Circle:  
    """A Circle instance models a circle with a radius"""
    
    def __init__(self, radius=1.0):
        """Constructor with default radius of 1.0"""
        self.radius = radius  # Create an instance variable radius
        
    def __str__(self):
        """Return a descriptive string for this instance, invoked by print() and str()"""
        return 'This is a circle with radius of %.2f' % self.radius

    def __repr__(self):
        """Return a command string that can be used to re-create this instance, invoked by repr()"""
        return 'Circle(radius=%f)' % self.radius
    
    def get_area(self):
        """Return the area of this Circle instance"""
        return self.radius * self.radius * pi
 
# For Testing under Python interpreter
# If this module is run under Python interpreter, __name__ is '__main__'.
# If this module is imported into another module, __name__ is 'circle' (the module name).
if __name__ == '__main__':
    c1 = Circle(2.1)      # Construct an instance
    print(c1)             # Invoke __str__()
    print(c1.get_area())
 
    c2 = Circle()         # Default radius
    print(c2)
    print(c2.get_area())  # Invoke member method
 
    c2.color = 'red'  # Create a new attribute for this instance via assignment
    print(c2.color)
    #print(c1.color)  # Error - c1 has no attribute color

    # Test doc-strings
    print(__doc__)                  # This module
    print(Circle.__doc__)           # Circle class
    print(Circle.get_area.__doc__)  # get_area() method
    
    print(isinstance(c1, Circle)) # True
    print(isinstance(c2, Circle)) # True
    print(isinstance(c1, str))    # False

Class Point with operators overloading(point.py)

In [5]:
class Point:    
    """A Point instance models a 2D point with x and y coordinates"""

    def __init__(self, x=0, y=0):
        """Constructor, which creates the instance variables x and y with default of (0,0)"""
        self.x = x
        self.y = y

    def __str__(self):
        """Return a descriptive string for this instance"""
        return '(%.2f, %.2f)' % (self.x, self.y)
        
    def __repr__(self):
        """Return a command string to re-create this instance"""
        return 'Point(x=%f, y=%f)' % (self.x, self.y)
        
    def __add__(self, right):
        """Override the '+' operator: create and return a new instance"""
        p = Point(self.x + right.x, self.y + right.y)
        return p

    def __mul__(self, factor):
        """Override the '*' operator: modify and return this instance"""
        self.x *= factor
        self.y *= factor
        return self

# Test
if __name__ == '__main__':
    p1 = Point()
    print(p1)      # (0.00, 0.00)
    p1.x = 5
    p1.y = 6
    print(p1)      # (5.00, 6.00)
    p2 = Point(3, 4)
    print(p2)      # (3.00, 4.00)
    print(p1 + p2) # (8.00, 10.00) Same as p1.__add__(p2)
    print(p1)      # (5.00, 6.00) No change
    print(p2 * 3)  # (9.00, 12.00) Same as p1.__mul__(p2)
    print(p2)      # (9.00, 12.00) Changed

Class Circle with get set methods (get_set.py)

In [5]:
from math import pi

class Circle:
    """A Circle instance models a circle with a radius"""

    def __init__(self, _radius=1.0):
        """Constructor with default radius of 1.0"""
        self.set_radius(_radius)   # Call setter

    def set_radius(self, _radius):
        """Setter for instance variable radius with input validation"""
        if _radius < 0:
            raise ValueError("Radius shall be non-negative")
        self._radius = _radius

    def get_radius(self):
        """Getter for instance variable radius"""
        return self._radius

    def get_area(self):
        """Return the area of this Circle instance"""
        return self.get_radius() * self.get_radius() * pi  # Call getter

    def __repr__(self):
        """Return a command string to recreate this instance"""
        # Used by str() too as __str__() is not defined
        return 'Circle(radius=%f)' % self.get_radius()  # Call getter
        
if __name__ == '__main__':
    c1 = Circle(1.2)        # Constructor
    print(c1)               # Invoke __repr__(). Output: Circle(radius=1.200000)
    print(vars(c1))         # Output: {'_radius': 1.2}
    print(c1.get_area())    # Output: 4.52389342117
    print(c1.get_radius())  # Run Getter. Output: 1.2
    c1.set_radius(3.4)      # Test Setter
    print(c1)               # Output: Circle(radius=3.400000)
    c1._radius = 5.6        # Access instance variable directly (not recommended but permitted)
    print(c1)               # Output: Circle(radius=5.600000)
 
    c2 = Circle()      # Default radius
    print(c2)          # Output: Circle(radius=1.000000)
 
    c3 = Circle(-5.6)  # ValueError: Radius shall be non-negative

Circle with operator overloading (operator_overload.py)

In [2]:
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def __eq__(self, right):
        """Override operator '==' to compare the two radius"""
        if self.__class__.__name__ == right.__class__.__name__:
            return self.radius == right.radius
        raise TypeError("not a 'Circle' object")

if __name__ == '__main__':
    print(Circle(8) == Circle(8))   # True
    print(Circle(8) == Circle(88))  # False
    print(Circle(8) == 'abc')       # TypeError

Inheritance (cylinder.py)

In [2]:
from circle import Circle  # Using the Circle class in the circle module

class Cylinder(Circle):
    """The Cylinder class is a subclass of Circle"""

    def __init__(self, radius = 1.0, height = 1.0):
        """Constructor"""
        super().__init__(radius)  # Invoke superclass' constructor (Python 3)
            # OR
            # super(Cylinder, self).__init__(radius)   (Python 2)
            # Circle.__init__(self, radius)            Explicit superclass class
        self.height = height

    def __str__(self):
        """Self Description for print()"""
        # If __str__ is missing in the subclass, print() will invoke the superclass version!
        return 'Cylinder(radius=%.2f,height=%.2f)' % (self.radius, self.height)

    def get_volume(self):
        """Return the volume of the cylinder"""
        return self.get_area() * self.height  # Inherited get_area()
 
# For testing
if __name__ == '__main__':
    cy1 = Cylinder(1.1, 2.2)  # Output: Cylinder(radius=1.10,height=2.20)
    print(cy1)
    print(cy1.get_area())     # Use inherited superclass' method
    print(cy1.get_volume())   # Invoke its method
 
    cy2 = Cylinder()          # Default radius and height
    print(cy2)                # Output: Cylinder(radius=1.00,height=1.00)
    print(cy2.get_area())
    print(cy2.get_volume())

    print(dir(cy1))
        # ['get_area', 'get_volume', 'height', 'radius', ...]
    print(Cylinder.get_area)
        # 
        # Inherited from the superclass
    print(Circle.get_area)
        # 

    c1 = Circle(3.3)
    print(c1)    # Output: This is a circle with radius of 3.30
        
    print(issubclass(Cylinder, Circle))  # True
    print(issubclass(Circle, Cylinder))  # False
    print(isinstance(cy1, Cylinder))     # True
    print(isinstance(cy1, Circle))       # True (A subclass object is also a superclass object)
    print(isinstance(c1, Circle))        # True
    print(isinstance(c1, Cylinder))      # False (A superclass object is NOT a subclass object)
    print(Cylinder.__base__)             # Show superclass: 
    print(Circle.__subclasses__())       # Show a list of subclasses: []

Inheritance (shape.py)

In [2]:
from math import pi

class Shape:    
    """The superclass Shape with a color"""
    def __init__(self, color = 'red'):  # Constructor
        self.color = color
    def __str__(self):  # For print() and str()
        return 'Shape(color=%s)' % self.color

class Circle(Shape):
    """The Circle class: a subclass of Shape with a radius"""
    def __init__(self, radius = 1.0, color = 'red'):  # Constructor
        super().__init__(color)
        self.radius = radius
    def __str__(self):  # For print() and str()
        return 'Circle(%s, radius=%.2f)' % (super().__str__(), self.radius)
    def get_area(self):
        return self.radius * self.radius * pi

class Rectangle(Shape):
    """The Rectangle class: a subclass of Shape wit a length and width"""
    def __init__(self, length = 1.0, width = 1.0, color = 'red'):  # Constructor
        super().__init__(color)
        self.length = length
        self.width = width
    def __str__(self):  # For print() and str()
        return 'Rectangle(%s, length=%.2f, width=%.2f)' % (super().__str__(), self.length, self.width)
    def get_area(self):
        return self.length * self.width

class Square(Rectangle):
    """The Square class: a subclass of Rectangle having the same length and width"""
    def __init__(self, side = 1.0, color = 'red'):  # Constructor
        super().__init__(side, side, color)
    def __str__(self):  # For print() and str()
        return 'Square(%s)' % super().__str__()

# For Testing
if __name__ == '__main__':
    s1 = Shape('orange')
    print(s1)                # Shape(color=orange)
    print(s1.color)
 
    c1 = Circle(1.2, 'orange')
    print(c1)                # Circle(Shape(color=orange), radius=1.20)
    print(c1.get_area())
 
    r1 = Rectangle(1.2, 3.4, 'orange')
    print(r1)                # Rectangle(Shape(color=orange), length=1.20, width=3.40)
    print(r1.get_area())
 
    sq1 = Square(5.6, 'orange')
    print(sq1)               # Square(Rectangle(Shape(color=orange), length=5.60, width=5.60))
    print(sq1.get_area())

Multiple inheritance (minh.py)

In [2]:
class A:
    def m(self):
        print('in Class A')

class B(A):
    def m(self):
        A.m(self)
        print('in Class B')
    
class C(A):
    def m(self):
        A.m(self)
        print('in Class C')

class D(B,C):
    def m(self):
        B.m(self)
        C.m(self)
        print('in Class D')


if __name__ == '__main__':
    x = D()
    x.m()

Multiple inheritance (minh1.py)

In [2]:
class A:
    def m(self):
        print('in Class A')

class B(A):
    def m(self):
        super().m()
        print('in Class B')
    
class C(A):
    def m(self):
        super().m()
        print('in Class C')

class D(B,C):
    def m(self):
        super().m()
        print('in Class D')

if __name__ == '__main__':
    x = D()
    x.m()

Multiple inheritance (minh2.py)

In [2]:
class A:
    def __init__(self):
        print('init A')
    
class B(A):
    def __init__(self):
        super().__init__()
        print('init B')
    
class C(A):
    def __init__(self):
        super().__init__()
        print('init C')

class D(B,C):
    def __init__(self):
        super().__init__()
        print('init D')

if __name__ == '__main__':
    d = D()
    # init A
    # init C
    # init B
    # init D
    
    c = C()
    # init A
    # init C
    
    b = B()
    # init A
    # init B

Charge (charge.py, chargeclient.py)

In [2]:
import sys
import math

class Charge:
    def __init__(self, x0, y0, q0):
        self._rx = x0  # x value of the query point
        self._ry = y0  # y value of the query point
        self._q = q0   # Charge

    def potentialAt(self, x, y):
        COULOMB = 8.99e09
        dx = x - self._rx
        dy = y - self._ry
        r = math.sqrt(dx*dx + dy*dy)
        if r == 0.0: # Avoid division by 0
            if self._q >= 0.0:
                return float('inf')
            else:
                return float('-inf')
        return COULOMB * self._q / r

    def __str__(self):
        result = str(self._q) + ' at (' + str(self._rx) + ', ' + str(self._ry) + ')'
        return result

In [2]:
#-----------------
# chargeclient.py
#-----------------
import sys
from charge import Charge
# Acepta floats x e y como argumentos en la línea de comandos. Crea dos objetos 
# Charge con posición y carga. Imprime el potencial en (x, y) en la salida estandard
x = float(sys.argv[1])
y = float(sys.argv[2])
c1 = Charge(.51, .63, 21.3)
c2 = Charge(.13, .94, 81.9)
v1 = c1.potentialAt(x, y)
v2 = c2.potentialAt(x, y)
print('potential at (%.2f, %.2f) due to\n', x, y)
print('  ' + str(c1) + ' and')
print('  ' + str(c2))
print('is %.2e\n', v1+v2)
#-----------------------------------------------------------------------
# python chargeclient.py .2 .5
# potential at (0.20, 0.50) due to
#   21.3 at (0.51, 0.63) and
#   81.9 at (0.13, 0.94)
# is 2.22e+12

Class Complex (complex.py)

In [2]:
#-----------------------------------------------------------------------
# complex.py
#-----------------------------------------------------------------------

import math

# A Complex object is a complex number.

# A Complex object is immutable.  So once you create and initialize
# a Complex object, you cannot change it.

class Complex:

    # Construct self with real part real and imaginary
    # part imag. real defaults to 0.0. imag also defaults to 0.0.
    def __init__(self, re=0.0, im=0.0):
        self._re = re
        self._im = im

    # Return the real part of self.
    def re(self):
        return self._re

    # Return the imaginary part of self.
    def im(self):
        return self._im

    # Return the conjugate of self.
    def conjugate(self):
        return Complex(self._re, -self._im)

    # Return a new Complex object which is the sum of self and 
    # Complex object other.
    def __add__(self, other):
        re = self._re + other._re
        im = self._im + other._im
        return Complex(re, im)

    # Return a new Complex object which is the product of self and
    # Complex object other.
    def __mul__(self, other):
        re = self._re * other._re - self._im * other._im
        im = self._re * other._im + self._im * other._re
        return Complex(re, im)

    # Return True if self and Complex object other are equal, and
    # False otherwise.
    def __eq__(self, other):
        return (self._re == other._re) and (self._im == other._im)

    # Return True if self and Complex object other are unequal, and
    # False otherwise.
    def __ne__(self, other):
        return not self.__eq__(other)

    # Return the absolute value of self.
    def __abs__(self):
        return math.sqrt(self._re*self._re + self._im*self._im)
        # Alternative: return math.hypot(self._re, self._im)
        # Alternative: return self.__mul__(self.conjugate())

    # Return a string representation of self.
    def __str__(self):
        return str(self._re) + ' + ' + str(self._im) + 'i'

#-----------------------------------------------------------------------

# For testing.
# Create and use some Complex objects.

def main():

    z0 = Complex(1.0, 1.0)
    z = z0
    z = z * z + z0
    z = z * z + z0
    print(z)

if __name__ == '__main__':
    main()

#-----------------------------------------------------------------------

# python complex.py 
# -7.0 + 7.0i