3 votes

Programmation abstraite en Python

import math
class Point:

    def __init__(self,x,y):
        self.x = x
        self.y = y

    def move(self,x,y):
        self.x += x
        self.y += y

    def __str__(self):
        return "<"+ str(self.x) + "," + str(self.y) + ">"

class Shape:        
    def __init__(self, centrePoint, colour, width, height):
        self.centrePoint = centrePoint
        self.colour = colour
        self.width = width
        self.height = height
        self.type = "Square"

    def __init__(self, centrePoint, radius, colour):
        self.type = "Circle"
        self.radius = radius
        self.colour = colour
        self.centrePoint = centrePoint

    def move(self,x,y):
        self.centrePoint.move(x,y)

    def getArea(self):
        if (self.type == "Square"):
            return self.width * self.height
        elif (self.type == "Circle"):
            return math.pi*(self.radius**2)

    def __str__(self):
        return "Center Point: " + str(self.centrePoint) + "\nColour: "+ self.Colour + "\nType: " + self.type + "\nArea: " + self.getArea()

class Rectangle (Shape):

    def scale(self, factor):
        self.scaleVertically(factor)
        self.scaleHorizontally(factor)

    def scaleVertically(self, factor):
        self.height *= factor

    def scaleHorizontally(self, factor):
        self.width *= factor

class Circle (Shape):

    def scale(self, factor):
        self.radius * factor

C'est le code que j'ai jusqu'à présent, Shape est censé représenter une classe abstraite et les deux autres classes sont censées en hériter, pour moi cela semble encore trop codé pour être une solution abstraite, comment pourrais-je l'améliorer ?

4voto

tbraun89 Points 1530

Je modifierais cette partie dans la classe abstraite :

def getArea(self):
    if (self.type == "Square"):
        return self.width * self.height
    elif (self.type == "Circle"):
        return math.pi*(self.radius**2)

Vous pouvez spécifier une valeur par défaut dans la classe abstraite et remplacer la méthode dans la classe Rectangle ou en Circle .

Mais vous obtiendrez peut-être une meilleure réponse sur https://codereview.stackexchange.com/ .

UPDATE (exemple) :

from abc import ABCMeta, abstractmethod

class Shape: 
  __metaclass__ = ABCMeta

  @abstractmethod
  def getArea(self):
    pass

class Rectangle (Shape):
  def getArea(self):
    return self.width * self.height

class Circle (Shape):
  def getArea(self):
    return math.pi*(self.radius**2)

MISE À JOUR 2 (surcharge des fonctions)

Comme Ohad a écrit, la surcharge ne fonctionne pas en python voici un exemple sans surcharger la fonction init :

def Shape:
  def __init__(self, centrePoint, colour, **kwargs):
    self.centrePoint = centrePoint
    self.colour      = colour
    self.width       = kwargs.get('width')
    self.height      = kwargs.get('height')
    self.radius      = kwargs.get('radius')

Vous pouvez maintenant créer des objets avec

rect = Rectangle(0, "red", width=100, height=20)
circ = Circle(0, "blue", radius=5)

Un bon article sur kwargs est ici : Quelle est la façon la plus propre et la plus pythonique d'avoir des constructeurs multiples en Python ?

La variable type est également inutile car elle permet d'identifier le type :

>>> rect = Rectangle(...)
>>> print isinstance(rect, Rectangle)
True
>>> print isinstance(rect, Circle)
False

2voto

Ohad Points 909

Tout d'abord, notez qu'il n'y a pas de surcharge de fonction en python, donc ceci :

class Shape:        
    def __init__(self, centrePoint, colour, width, height):
        ...

    def __init__(self, centrePoint, radius, colour):
        ...

votre première fonction sera "écrasée" par la seconde.

En règle générale, l'idée principale derrière le concept d'une classe commune de base/abstraite est de découpler l'implémentation à partir de l'interface (notez les conventions python, lower_case_with_underscores pour les noms de fonctions, et non camleCase) :

class Shape: 
  __metaclass__ = ABCMeta

  @abstractmethod
  def get_area(self):
    pass

  move, scale, scale_vertically, scale_horizontally, print...

Maintenant que j'ai ma classe de base abstraite mais opérationnelle (comme dans "Chaque forme peut être mise à l'échelle, déplacée "), qui ne sait absolument pas comment un cercle est construit, déplacé ou mis à l'échelle. Je peux alors commencer à implémenter les sous-classes : Rectangle , Circle et ainsi de suite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X