Herança em programação orientada a objetos

Conteúdo

Visão geral

  • Aprenda sobre herança em programação orientada a objetos e várias formas de herança
  • Entenda a substituição do método e a super função () no mundo da programação orientada a objetos

Introdução

Herança é um dos aspectos mais importantes da programação orientada a objetos (OOP). A chave para entender a herança é que ela fornece a reutilização de código. Em vez de escrever o mesmo código, uma e outra vez, podemos simplesmente herdar as propriedades de uma classe na outra.

Esse, como você pode imaginar, economize muito tempo. E tempo é dinheiro em ciência de dados!

herança em oop-9792497

A Programação Orientada a Objetos trata de objetos do mundo real e herança é uma forma de representar relacionamentos do mundo real. Aqui está um exemplo: carro, ônibus, bicicleta – todos eles pertencem a uma categoria mais ampla chamada Veículo. Isso significa que eles herdaram as propriedades dos veículos de classe, quer dizer, todos são usados ​​para transporte.

Podemos representar essa relação em código com a ajuda de herança.

Outra coisa intrigante sobre herança é que ela é transitiva por natureza.. Mas o que isso significa? Veremos em detalhes posteriormente neste artigo. Python também oferece suporte a vários tipos de herança que abordarei em detalhes neste artigo..

Este é o segundo artigo de uma série de artigos relacionados à programação orientada a objetos. Leia também o primeiro artigo:

Tabela de conteúdo

  1. O que é herança em programação orientada a objetos?
  2. Diferentes formas de herança na programação orientada a objetos
    • Herança única
    • Herança múltipla
    • Herança multinível
    • Herança hierárquica
    • Herança híbrida
  3. Substituição de método
  4. A superfunção ()

O que é herança em programação orientada a objetos?

Herança é o procedimento no qual uma classe herda os atributos e métodos de outra classe. A classe cujas propriedades e métodos são herdados é conhecida como a classe principal. E a classe que herda as propriedades da classe principal é a classe Criança.

O interessante é que, junto com propriedades e métodos herdados, una clase hija puede tener sus propias propiedades y métodos.

Puede usar la siguiente sintaxis: para implementar la herencia en Python:

parent_class de classe:
body of parent class

class child_class( parent_class):
corpo de classe infantil

Veamos la implementación:

carro classe:          #parent class

    def __init__(auto, nome, quilometragem):
        self.name = name 
        self.mileage = mileage 

    def description(auto):                
        retorno f"o {self.name} carro dá a quilometragem de {auto.quilometragem}km/l"

BMW classe(Carro):     #child class
    pass

class Audi(Carro):     #child class
    def audi_desc(auto):
        Retorna "Este é o método de descrição da classe Audi."
obj1 = BMW("BMW série 7",39.53)
imprimir(obj1.descrição())

obj2 = Audi("Audi A8 L",14)
imprimir(obj2.descrição())
imprimir(obj2.audi_desc())

Produção:

a13-4443158

Hemos creado dos clases secundarias, a saber, “Bmw” e “Audi”, que han heredado los métodos y propiedades de la clase principal “Rio Coche”. Não fornecemos funções e métodos adicionais na classe BMW. Considerando que existe um método adicional dentro da classe Audi.

Observe como os objetos em classes filhas podem acessar o método de instância de descrição () da classe principal com a ajuda de obj1.description () y obj2.description (). E o método separado da classe Audi também pode ser acessado por obj2.audi_desc ().

Podemos verificar a classe base ou pai de qualquer classe usando um atributo de classe embutido __bases__

imprimir(BMW .__ bases__, Audi .__ bases__)
screenshot-from-2020-09-28-20-44-53-3987278

Como podemos aqui, a classe base de ambas as subclasses é Rio Coche. Agora, Vamos ver o que acontece quando __base__ é usado com a classe pai Car:

imprimir( Car .__ bases__ )

screenshot-from-2020-09-30-17-59-33-3279774

Sempre que criamos uma nova classe em Python 3.x, herda de uma classe base integrada chamada Objeto. Em outras palavras, class Object é a raiz de todas as classes.

Formas de herança na programação orientada a objetos

Em geral, existem cinco formas de herança com base na participação de pais e filhos na classe.

1. Herança única

Esta é uma forma de herança onde uma classe herda apenas uma classe principal. Esta é a forma simples de herança e, portanto, também conhecido como herança simples.

classe pai:
  def f1(auto):
    imprimir("Função da classe pai.")

classe criança(Pai):
  def f2(auto):
    imprimir("Função da classe filha.")

object1 = Criança()
object1.f1()
object1.f2()

screenshot-from-2020-09-28-22-11-28-7257539

Aqui, A classe filha herda apenas uma classe pai, portanto, este é um exemplo de herança simples.

2. Herança múltipla

Uma herança se torna múltiplas heranças quando uma classe herda mais de uma classe principal. A classe filha depois de herdar propriedades de várias classes principais tem acesso a todos os seus objetos.

classe Parent_1:
  def f1(auto):
    imprimir("Função da classe parent_1.")

classe Parent_2:
  def f2(auto):
    imprimir("Função da classe parent_2.")

classe Parent_3:
  def f3(auto):
    imprimir("função da classe parent_3.")

classe criança(Pai_1, Pai_2, Parent_3):
  def f4(auto):
    imprimir("Função da classe filha.")

object_1 = Criança()
object_1.f1()
objeto_1.f2()
objeto_1.f3()
objeto_1.f4()

screenshot-from-2020-09-30-18-01-00-6896696

Aqui temos uma classe Filha que herda as propriedades das três classes pais Parent_1, Parent_2 y Parent_3. Todas as classes têm funções diferentes e todas as funções são chamadas usando o objeto de classe Criança.

Mas suponha que uma classe filha herde duas classes que têm a mesma função:

classe Parent_1:
  def f1(auto):
    imprimir("Função da classe parent_1.")

classe Parent_2:
  def f1(auto):
    imprimir("Função da classe parent_2.")

classe criança(Pai_1, Pai_2):
  def f2(auto):
    imprimir("Função da classe filha.")

Aqui, As classes Parent_1 e Parent_2 têm a mesma função f1 (). Agora, quando o objeto da classe Child chama f1 (), uma vez que a classe Filha herda as duas classes pais, O que você acha que deveria acontecer?

obj = criança() 
obj.f1()

screenshot-from-2020-09-30-18-04-07-6132602

Mas, Por que a função f1 não foi herdada () da classe Parent_2?

Em herança múltipla, a classe filha primeiro procura o método em sua própria classe. Se não for encontrado, pesquisar classes pai depth_first e ordenar da esquerda para a direita. Uma vez que este foi um exemplo fácil com apenas duas classes principais, podemos ver claramente que a classe Parent_1 foi herdada primeiro, então a classe filha procurará o método na classe Parent_1 antes de olhar na classe Parent_2.

Mas para complicados problemas de herança, é difícil identificar a ordem. Então, a maneira real de fazer isso é chamado Orden de resolução de método (MRO) e Python. Podemos encontrar o MRO de qualquer classe usando o atributo __mro__

Child.__mro__

captura de tela de 2020-09-30-18-06-17-7768903

Isso indica que a turma do Criança visitou pela primeira vez a classe Parent_1 e depois Parent_2, para que o método f1 será chamado () Parent_1.

Vamos dar um exemplo complicado em Python:

classe Parent_1:
pass

class Parent_2:
pass

class Parent_3:
pass

class Child_1(Parent_1.Parent_2):
pass

class Child_2(Parent_2.Parent_3):
pass

class Child_3(Child_1 Child_2 Parent_3):
passar

Aqui, a classe Child_1 herda duas classes: Parent_1 e Parent_2. a classe Child_2 também herda duas classes: Parent_2 y Parent_3. Outra classe Child_3 herda três classes: Child_1, Child_2 e Parent_3.

Agora, apenas olhando para esta herança, é muito difícil determinar a ordem de resolução do método para a classe Child_3. Então, aqui está o uso real de __mro __-

screenshot-from-2020-09-30-18-07-32-8298006

Podemos ver isso primeiro, o intérprete procura Child_3, então Child_1 seguido por Parent_1, Criança_2, Parent_2 e Parent_3 respectivamente.

3. Herança multinível

Por exemplo, uma classe_1 é herdada por uma classe_2 ​​e esta classe_2 ​​também é herdada por classe_3 e este processo continua. Isso é conhecido como herança multinível.. Vamos entender com um exemplo:

classe pai:
  def f1(auto):
    imprimir("Função da classe pai.")

classe Child_1(Pai):
  def f2(auto):
    imprimir("Função da classe child_1.")

classe Child_2(Child_1):
  def f3(auto):
    imprimir("Função da classe child_2.")

obj_1 = Criança_1()
obj_2 = Criança_2()

obj_1.f1()
obj_1.f2()

imprimir("n")
obj_2.f1()
obj_2.f2()
obj_2.f3()

screenshot-from-2020-09-30-18-09-52-9849898

Aqui, a classe Child_1 herda a classe Parent e a classe Child_2 herda a classe Child_1. Neste Child_1 você tem acesso às funções f1 () y f2 () enquanto Child_2 tem acesso às funções f1 (), f2 () e f3 (). Se tentarmos acessar a função f3 () usando o objeto de classe Class_1, um erro ocorrerá informando:

O objeto 'Child_1’ não tem atributo ‘f3’

obj_1.f3()

screenshot-from-2020-09-30-18-11-09-7482388

4- Herança hierárquica

Nisto, várias classes filho herdam uma única classe pai. O exemplo dado na introdução da herança é um exemplo de herança hierárquica, já que as classes BMW e Audi herdam a classe Car.

Para simplificar, vamos ver outro exemplo:

classe pai:
deff1(auto):
imprimir("Função da classe pai.")

classe Child_1(Pai):
deff2(auto):
imprimir("Função da classe child_1.")

classe Child_2(Pai):
deff3(auto):
imprimir("Função da classe child_2.")

obj_1 = Criança_1()
obj_2 = Criança_2()

obj_1.f1()
obj_1.f2()

imprimir('n')
obj_2.f1()
obj_2.f3()

screenshot-from-2020-09-30-18-13-09-8467252

Aqui, duas classes filhas herdam a mesma classe pai. A classe Child_1 tem acesso às funções f1 () da classe pai e para a função f2 () Dela mesma. Enquanto a classe Child_2 tem acesso às funções f1 () da classe pai e da função f3 () Dela mesma.

5- Herança híbrida

Quando há uma combinação de mais de uma forma de herança, conhecido como herança híbrida. Será mais claro após este exemplo:

classe pai:
  def f1(auto):
    imprimir("Função da classe pai.")

classe Child_1(Pai):
  def f2(auto):
    imprimir("Função da classe child_1.")

classe Child_2(Pai):
  def f3(auto):
    imprimir("Função da classe child_2.")

classe Child_3(Child_1, Criança_2):
  def f4(auto):
    imprimir("Função da classe child_3.")

obj = Child_3()
obj.f1()
obj.f2()
obj.f3()
obj.f4()

screenshot-from-2020-09-30-18-14-15-1161987

Neste exemplo, duas classes ‘Criança_1 ′ e’ Child_2 'são derivados da classe base’ Pai 'usando herança hierárquica. Outra classe ‘Child_3’ é derivado das classes ‘Child_1’ y ‘Criança_2’ usando várias heranças. A classe ‘Child_3’ agora derivado por herança híbrida.

Substituição de método

O conceito de anulação é muito importante na herança. Concede a habilidade especial para a criança / subclasses para fornecer uma implementação específica para um método que já está presente em suas classes pai.

classe pai:
  def f1(auto):
    imprimir("Função da classe pai.")

classe criança(Pai):
  def f1(auto):
    imprimir("Função da classe Criança.")

obj = criança()
obj.f1()

screenshot-from-2020-09-30-18-15-01-1521849

Aqui, função f1 () da classe Child substituiu a função f1 () da classe pai. Sempre que o objeto da classe Criança invoca f1 (), a função da classe Criança é executada. Porém, o objeto da classe principal pode invocar a função f1 () da classe principal.

obj_2 = pai()
obj_2.f1()

screenshot-from-2020-09-30-18-15-39-2868996

A superfunção ()

A superfunção () em Python, ele retorna um objeto proxy que se refere à classe pai usando o Super palavra chave. Esta super palavra-chave () é basicamente útil para acessar os métodos sobrescritos da classe principal.

  1. Em uma hierarquia de classes com herança única, Super ajuda a referenciar classes principais sem nomeá-las explicitamente, o que torna o código mais fácil de manter.

    Por exemplo-

    classe pai:
      def f1(auto):
        imprimir("Função da classe pai.")
    
    classe criança(Pai):
      def f1(auto):
        super().f1()
        imprimir("Função da classe Criança.")
    
    obj = criança()
    obj.f1()

    screenshot-from-2020-09-30-18-16-53-9118408

    Aqui, com a ajuda de super (). F1 (), método f1 foi chamado () superclasse da classe Criança, quer dizer, a classe pai sem nomeá-la explicitamente.

    Uma coisa a se notar aqui é que a super classe () puede aceptar dos parametros: o primeiro é o nome da subclasse e o segundo é um objeto que é uma instância dessa subclasse. Vamos ver como

    classe pai:
      def f1(auto):
        imprimir("Função da classe pai.")
    
    classe criança(Pai):
      def f1(auto):
        super( Filho, auto ).f1()
        imprimir("Função da classe Criança.")
    
    obj = criança()
    obj.f1()

    screenshot-from-2020-09-30-18-16-53-9118408

    O primeiro parâmetro se refere à subclasse Menino, enquanto o segundo parâmetro se refere ao objeto filho que, neste caso, isto é um mesmo. Você pode ver o resultado depois de usar super () e super (Filho, auto) é o mesmo porque, e Python 3, super (Filho, auto) é equivalente a si mesmo ().

    Agora vamos ver mais um exemplo usando a função __init__.

    classe pai(objeto):
      def__init__(auto, Nome dos pais):
        imprimir(Nome dos pais, 'é derivado de outra classe.')
    
    classe criança(Pai):
      def__init__(auto, Nome da criança):
        imprimir(nome,'é uma subclasse.')
        super().__iniciar__(Nome da criança)
    
    obj = criança('Filho')
    screenshot-from-2020-09-30-18-18-16-3947931

    O que fizemos aqui é chamar a função __init__ da classe pai (dentro da classe infantil) usando super () .__ iniciar __ (Nome da criança). E uma vez que o método __init__ da classe Parent requer um argumento, aconteceu como “Nome da criança”. Então, depois de criar o objeto da classe Child, primeiro a função __init__ da classe Criança foi executada, e então a função __init__ da classe pai.

  2. O segundo caso de uso é oferecer suporte a várias heranças cooperativas em um ambiente de tempo de execução dinâmico.
    classe primeiro():
      def __init__(auto):
        imprimir("primeiro")
        super().__iniciar__()
    
    segunda classe():
      def __init__(auto):
        imprimir("segundo")
        super().__iniciar__()
    
    terceira classe(Segundo, Primeiro):
      def __init__(auto):
        imprimir("terceiro")
        super().__iniciar__()
    
    obj = Terceiro()

    screenshot-from-2020-09-30-18-19-20-4144770
    A super chamada () encontre o seguinte método no MRO em cada etapa, então o primeiro e o segundo também devem ter, pelo contrário, execução para no final de primeiro () .__ iniciar__.

    Observe que a primeira e a segunda superclasse são Objeto.

    Vamos encontrar o MRO da Third () também-

    Terceiro .__ mro__

    screenshot-from-2020-09-30-18-19-53-1265153

    O pedido é terceiro> Segundo> A primeira e a mesma é a ordem de nossa partida.

Notas finais

Para concluir, Neste artigo, desenvolvi o conceito de herança em programação orientada a objetos em Python. Abordei várias formas de herança e alguns dos conceitos comuns de herança, como substituição de método e super função ().

Espero que você tenha entendido os conceitos explicados neste artigo. Deixe-me saber nos comentários abaixo se você tiver alguma dúvida..

Assine a nossa newsletter

Nós não enviaremos SPAM para você. Nós odiamos isso tanto quanto você.