Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 2, 2021 12:48 am GMT

Orientao a objetos de outra forma: ABC

Na discusso sobre herana e mixins foram criadas vrias classes, como Autenticavel e AutenticavelComRegistro que adicionam funcionalidades a outras classes e implementavam tudo o que precisavam para seu funcionamento. Entretanto podem existir casos em que no seja possvel implementar todas as funes na prpria classe, deixando com que as classes que a estende implemente essas funes. Uma forma de fazer isso travs das ABC (abstract base classes, ou classes base abstratas).

Sem uso de classes base abstratas

Um exemplo de classe que no possvel implementar todas as funcionalidades foi dada no texto Encapsulamento da lgica do algoritmo, que discutia a leitura de valores do teclado at que um valor vlido fosse lido (ou que repete a leitura caso um valor invlido tivesse sido informado). Nesse caso a classe ValidaInput implementava a lgica base de funcionamento, porm eram suas classes filhas (ValidaNomeInput e ValidaNotaInput) que implementavam as funes para tratar o que foi lido do teclado e verificar se um valor vlido ou no.

class ValidaInput:    mensagem_valor_invalido = 'Valor invlido!'    def ler_entrada(self, prompt):        return input(prompt)    def transformar_entrada(self, entrada):        raise NotImplementedError    def validar_valor(self, valor):        raise NotImplementedError    def __call__(self, prompt):        while True:            try:                valor = self.transformar_entrada(self.ler_entrada(prompt))                if self.validar_valor(valor):                    break            except ValueError:                ...            print(self.mensagem_valor_invalido)        return valorclass ValidaNomeInput(ValidaInput):    mensagem_valor_invalido = 'Nome invlido!'    def transformar_entrada(self, entrada):        return entrada.strip().title()    def validar_valor(self, valor):        return valor != ''class ValidaNotaInput(ValidaInput):    mensagem_valor_invalido = 'Nota invlida!'    def transformar_entrada(self, entrada):        return float(entrada)    def validar_valor(self, valor):        return 0 <= valor <= 10

Entretanto, esse cdigo permite a criao de objetos da classe ValidaInput mesmo sem ter uma implementao das funes transformar_entrada e validar_valor. E a nica mensagem de erro ocorreria ao tentar executar essas funes, o que poderia estar longe do problema real, que a criao de um objeto a partir de uma classe que no prove todas as implementaes das suas funes, o que seria semelhante a uma classe abstrata em outras linguagens.

obj = ValidaInput()# Diversas linhas de cdigoobj('Entrada: ')  # Exceo NotImplementedError lanada

Com uso de classes base abstratas

Seguindo a documentao da ABC, para utiliz-las necessrio informar a metaclasse ABCMeta na criao da classe, ou simplesmente estender a classe ABC, e decorar com abstractmethod as funes que as classes que a estenderem devero implementar. Exemplo:

from abc import ABC, abstractmethodclass ValidaInput(ABC):    mensagem_valor_invalido = 'Valor invlido!'    def ler_entrada(self, prompt):        return input(prompt)    @abstractmethod    def transformar_entrada(self, entrada):        ...    @abstractmethod    def validar_valor(self, valor):        ...    def __call__(self, prompt):        while True:            try:                valor = self.transformar_entrada(self.ler_entrada(prompt))                if self.validar_valor(valor):                    break            except ValueError:                ...            print(self.mensagem_valor_invalido)        return valor

Desta forma, ocorrer um erro j ao tentar criar um objeto do tipo ValidaInput, dizendo quais so as funes que precisam ser implementadas. Porm funcionar normalmente ao criar objetos a partir das classes ValidaNomeInput e ValidaNotaInput visto que elas implementam essas funes.

obj = ValidaInput()  # Exceo TypeError lanadanome_input = ValidaNomeInput()  # Objeto criadonota_input = ValidaNotaInput()  # Objeto criado

Como essas funes no utilizam a referncia ao objeto (self), ainda possvel decorar as funes com staticmethod, como:

from abc import ABC, abstractmethodclass ValidaInput(ABC):    mensagem_valor_invalido = 'Valor invlido!'    @staticmethod    def ler_entrada(prompt):        return input(prompt)    @staticmethod    @abstractmethod    def transformar_entrada(entrada):        ...    @staticmethod    @abstractmethod    def validar_valor(valor):        ...    def __call__(self, prompt):        while True:            try:                valor = self.transformar_entrada(self.ler_entrada(prompt))                if self.validar_valor(valor):                    break            except ValueError:                ...            print(self.mensagem_valor_invalido)        return valorclass ValidaNomeInput(ValidaInput):    mensagem_valor_invalido = 'Nome invlido!'    @staticmethod    def transformar_entrada(entrada):        return entrada.strip().title()    @staticmethod    def validar_valor(valor):        return valor != ''class ValidaNotaInput(ValidaInput):    mensagem_valor_invalido = 'Nota invlida!'    @staticmethod    def transformar_entrada(entrada):        return float(entrada)    @staticmethod    def validar_valor(valor):        return 0 <= valor <= 10

Isso tambm seria vlido para funes decoradas com classmethod, que receberiam a referncia a classe (cls).

Consideraes

No necessrio utilizar ABC para fazer o exemplo discutido, porm ao utilizar essa biblioteca ficou mais explcito quais as funes que precisavam ser implementados nas classes filhas, ainda mais que sem utilizar ABC a classe base poderia nem ter as funes, com:

class ValidaInput:    mensagem_valor_invalido = 'Valor invlido!'    def ler_entrada(self, prompt):        return input(prompt)    def __call__(self, prompt):        while True:            try:                valor = self.transformar_entrada(self.ler_entrada(prompt))                if self.validar_valor(valor):                    break            except ValueError:                ...            print(self.mensagem_valor_invalido)        return valor

Como Python possui duck-typing, no necessrio uma grande preocupao com os tipos, como definir e utilizar interfaces presentes em outras implementaes de orientao a objetos, porm devido herana mltipla, ABC pode ser utilizada como interface que no existe em Python, fazendo com que as classes implementem determinadas funes. Para mais a respeito desse assunto, recomendo as duas lives do dunossauro sobre ABC (1 e 2), e a apresentao do Luciano Ramalho sobre type hints.

Uma classe filha tambm no obrigada a implementar todas as funes decoradas com abstractmethod, mas assim como a classe pai, no ser possvel criar objetos a partir dessa classe, apenas de uma classe filha dela que implemente as demais funes. Como se ao aplicar um abstractmethod tornasse a classe abstrata, e qualquer classe filha s deixasse de ser abstrata quando a ltima funo decorada com abstractmethod for sobrescrita. Exemplo:

from abc import ABC, abstractmethodclass A(ABC):    @abstractmethod    def func1(self):        ...    @abstractmethod    def func2(self):        ...class B(A):    def func1(self):        print('1')class C(B):    def func2(self):        print('2')a = A()  # Erro por no implementar func1 e func2b = B()  # Erro por no implementar func2c = C()  # Objeto criado

Original Link: https://dev.to/acaverna/orientacao-a-objetos-de-outra-forma-abc-89b

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To