Ricerca…


Polimorfismo di base

Il polimorfismo è la capacità di eseguire un'azione su un oggetto indipendentemente dal suo tipo. Questo è generalmente implementato creando una classe base e avendo due o più sottoclassi che implementano tutti i metodi con la stessa firma. Qualsiasi altra funzione o metodo che manipoli questi oggetti può chiamare gli stessi metodi indipendentemente dal tipo di oggetto su cui sta operando, senza dover prima eseguire un controllo del tipo. Nella terminologia orientata agli oggetti quando la classe X estende la classe Y, allora Y è chiamato super classe o classe base e X è chiamato sottoclasse o classe derivata.

class Shape:
    """
    This is a parent class that is intended to be inherited by other classes
    """

    def calculate_area(self):
        """
        This method is intended to be overridden in subclasses.
        If a subclass doesn't implement it but it is called, NotImplemented will be raised.

        """
        raise NotImplemented

class Square(Shape):
    """
    This is a subclass of the Shape class, and represents a square
    """
    side_length = 2     # in this example, the sides are 2 units long

    def calculate_area(self):
        """
        This method overrides Shape.calculate_area(). When an object of type
        Square has its calculate_area() method called, this is the method that
        will be called, rather than the parent class' version.

        It performs the calculation necessary for this shape, a square, and
        returns the result.
        """
        return self.side_length * 2

class Triangle(Shape):
    """
    This is also a subclass of the Shape class, and it represents a triangle
    """
    base_length = 4
    height = 3

    def calculate_area(self):
        """
        This method also overrides Shape.calculate_area() and performs the area
        calculation for a triangle, returning the result.
        """

        return 0.5 * self.base_length * self.height

def get_area(input_obj):
    """
    This function accepts an input object, and will call that object's
    calculate_area() method. Note that the object type is not specified. It
    could be a Square, Triangle, or Shape object.
    """

    print(input_obj.calculate_area())

# Create one object of each class
shape_obj = Shape()
square_obj = Square()
triangle_obj = Triangle()

# Now pass each object, one at a time, to the get_area() function and see the
# result.
get_area(shape_obj)
get_area(square_obj)
get_area(triangle_obj)

Dovremmo vedere questo risultato:

Nessuna
4
6.0

Cosa succede senza polimorfismo?
Senza il polimorfismo, potrebbe essere necessario un controllo del tipo prima di eseguire un'azione su un oggetto per determinare il metodo corretto da chiamare. Il seguente esempio di contatore esegue lo stesso compito del codice precedente, ma senza l'uso del polimorfismo, la funzione get_area() deve svolgere più lavoro.

class Square:

    side_length = 2

    def calculate_square_area(self):
        return self.side_length ** 2

class Triangle:

    base_length = 4
    height = 3

    def calculate_triangle_area(self):
        return (0.5 * self.base_length) * self.height

def get_area(input_obj):

    # Notice the type checks that are now necessary here. These type checks
    # could get very complicated for a more complex example, resulting in
    # duplicate and difficult to maintain code.

    if type(input_obj).__name__ == "Square":
        area = input_obj.calculate_square_area()

    elif type(input_obj).__name__ == "Triangle":
        area = input_obj.calculate_triangle_area()

    print(area)

# Create one object of each class
square_obj = Square()
triangle_obj = Triangle()

# Now pass each object, one at a time, to the get_area() function and see the
# result.
get_area(square_obj)
get_area(triangle_obj)

Dovremmo vedere questo risultato:

4
6.0

Nota importante
Si noti che le classi utilizzate nell'esempio del contatore sono classi "new style" e ereditano implicitamente dalla classe dell'oggetto se si utilizza Python 3. Il polimorfismo funzionerà sia in Python 2.x che in 3.x, ma il codice del polimorfo del controesempio solleverà un'eccezione se eseguito in un interprete Python 2.x perché type (input_obj). il nome restituirà "istanza" al posto del nome della classe se non eredita esplicitamente dall'oggetto, risultando in un'area che non viene mai assegnata.

Duck Typing

Polymorphism senza ereditarietà sotto forma di anatra digitata come disponibile in Python grazie al suo sistema di battitura dinamico. Questo significa che finché le classi contengono gli stessi metodi l'interprete Python non fa distinzioni tra loro, poiché l'unico controllo delle chiamate avviene in fase di esecuzione.

class Duck:
    def quack(self):
        print("Quaaaaaack!")
    def feathers(self):
        print("The duck has white and gray feathers.")

class Person:
    def quack(self):
        print("The person imitates a duck.")
    def feathers(self):
        print("The person takes a feather from the ground and shows it.")
    def name(self):
        print("John Smith")

def in_the_forest(obj):
    obj.quack()
    obj.feathers()

donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john)

L'output è:

Quaaaaaack!
L'anatra ha piume bianche e grigie.
La persona imita un'anatra.
La persona prende una piuma da terra e la mostra.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow