Abstract Python class, how to choose implementation

Asked

Viewed 3,574 times

4

I’m learning python and trying to make a program where I have an abstract class and two subclasses that implement such. I need to make another class that will choose which implinking to use depending on the user, but I’m not able to do that. If someone can point me some study material for this part of POO would help me a lot! I couldn’t find anything that would help me in this understated class.

Follow the code part. The Baser I don’t know how to do.

class Dificultador(object):
#classe abstrata que vai ser super classe de DificultadorNivel e DificultadorTipo
from abc import ABCMeta, abstractmethod
__metaclass__ = ABCMeta
@abstractmethod
def Sort(self, expressoes):
    pass

class DificultadorNivel(Dificultador):#Faz um sort da lista de expressoes em niveis
def Sort(self, expressoes):
    expressoes = FonteDeExpressoes().lista()
    expnivel = sorted(expressoes, key=lambda x: x.nivel)
    return expnivel

class DificultadorTipo(Dificultador):#Faz um sort da lista de expressoes em tipo
def Sort(self, expressoes):
    expressoes = FonteDeExpressoes().lista()
    exptipo = sorted(expressoes, key=lambda x: x.tipo)
    return exptipo

class BaseDificultador(Dificultador):
#Funciona como um switch de seleção para escolha do sort

2 answers

4


The simplest way to choose which unstable object depending on some condition of the program is to use a function for it.

The name "complicated" is "Factory Function" or "Factory method". In some other OOP languages, you have to use a Factory Function implies some complication since the function itself has to stay in another class (sometimes constructed artificially just for this), but in Python it is something quite direct:

def obtem_dificultador(parametros):
    if (condicao):
          return DificultadorNivel(parametros)
    else:
        return DificultadorTipo(parametros)  

Or, since classes are simply objects that are called to be instantiated, your class selection can simply return the class - which will be instantiated with the parameters desired only by the caller. Furthermore, if there are several classes, you can reference their classes in a data structure, such as a dictionary, which can allow you to obtain the desired class more cleanly than a long sequence of if/Elif/Else.

Of course Python is dynamic enough for you can change the class, or appearance, of a subclass within the mechanics of instantiating the class itself (usually in the method __new__) - but then, as it is in the @Gypsy response, it is not considered a good practice. Factory functions are good.

In Python it is also possible, for classes defined in Python code, to directly exchange the attribute __class__ of an already instantiated object - effectively changing the class of an existing object. (Of course such a practice would hardly be defensible, without being for demonstration purposes. The object attributes and initialization were all of the old class)

If it is a large project, and you need sophisticated mechanisms to choose the class, it may be the case that it is more advantageous to use Zope Component Architecture - a componentization framework (which only has the name "Zope" - not the entire Zope) http://muthukadan.net/docs/zca.html

(The correct implementation of the abstract class is as it is in the Gypsy response - but in Python it is not something so necessary - unless you really will have a large structure and run the risk of getting confused with what each class needs to implement or not (abstract class sub-classes with missing methods will error at the moment their declaration is processed) )

3

Abstract classes in Python are implemented using the module abc. The correct would be something like this (considering Python 3.4 and above):

from abc import ABC, abstractmethod

class Dificultador(ABC):
    '''classe abstrata que vai ser super classe de DificultadorNivel e DificultadorTipo'''
    @abstractmethod
    def Sort(self, expressoes):
        pass

The other classes are like this:

class DificultadorNivel(Dificultador):
    '''Faz um sort da lista de expressoes em niveis'''
    def Sort(self, expressoes):
        expressoes = FonteDeExpressoes().lista()
        expnivel = sorted(expressoes, key=lambda x: x.nivel)
        return expnivel

class DificultadorTipo(Dificultador):
    '''Faz um sort da lista de expressoes em tipo'''
    def Sort(self, expressoes):
        expressoes = FonteDeExpressoes().lista()
        exptipo = sorted(expressoes, key=lambda x: x.tipo)
        return exptipo

No need to implement BaseDificultador. This goes against the SOLID.

  • Thanks for the answer! I didn’t know SOLID. But how can I select which one will overwrite? I tried to do functions instead of class but found the following error: Typeerror: Can’t instantiate Abstract class Complicator with Abstract methods Sort

  • Power may be, but it will become terribly complex. It goes against the Python culture.

  • You can’t instantiate it Dificultador just because it is an abstract class. It needs an explanation of what an abstract class is?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.