Polimorfismo — un principio fondamentale della programmazione orientata agli oggetti, che consente agli oggetti con strutture diverse di implementare lo stesso interfaccia, permettendo così di lavorare in modo intercambiabile. In Python, grazie alla tipizzazione dinamica, il polimorfismo è molto flessibile.
Nei linguaggi con tipizzazione statica rigorosa (Java, C++) il supporto per il polimorfismo richiede la dichiarazione di interfacce o classi astratte. In Python, grazie al duck typing, il polimorfismo non è legato alla gerarchia di ereditarietà e nemmeno all'interfaccia. È sufficiente che l'oggetto supporti i metodi/attributi richiesti.
Da un lato, questo rende il linguaggio flessibile e conveniente. Dall'altro, aumenta la probabilità di errori a runtime a causa di errori di battitura o della mancanza del metodo necessario, che si manifesteranno solo durante l'esecuzione del codice.
In Python, si distinguono:
class Animal: def speak(self): raise NotImplementedError class Dog(Animal): def speak(self): return 'Woof!' class Cat(Animal): def speak(self): return 'Meow!' def animal_voice(animal): print(animal.speak()) animal_voice(Dog()) # Woof! animal_voice(Cat()) # Meow!
class Duck: def quack(self): return 'Quack!' def make_quack(animal): print(animal.quack()) make_quack(Duck()) # Quack!
Caratteristiche chiave:
L'ereditarietà è l'unico modo per garantire il polimorfismo in Python?
No. Grazie al duck typing, qualsiasi funzione può accettare un oggetto con i metodi necessari indipendentemente dalla sua classe o gerarchia.
Si può considerare il polimorfismo la corrispondenza della firma solo per nome del metodo, e non per la sua sostanza?
No. Se un oggetto supporta il metodo necessario, ma la sua semantica differisce da quella attesa, possono verificarsi bug. Il polimorfismo è efficace solo quando coincidono non solo l'interfaccia, ma anche il significato.
Il classe astratta fornisce protezione contro errori di implementazione errata dell'interfaccia nelle classi figlie?
Solo parzialmente. Se l'erede non implementa il metodo astratto, si verificherà un TypeError quando si tenta di creare un'istanza. Ma se implementa violando la logica, possono verificarsi errori.
In una libreria di logging viene introdotta una classe esterna, che ha un metodo log(), ma restituisce un oggetto dati anziché registrare nel log. Gli errori si manifestano solo durante l'esecuzione.
Vantaggi:
Svantaggi:
Le classi sono dotate di test, l'interfaccia è formalizzata attraverso una classe base astratta e @abstractmethod, e nella documentazione è descritta la semantica dei metodi.
Vantaggi:
Svantaggi: