Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Fazer referência de uma classe Mãe dentro de uma classe Filha

Dentro classe Filme, eu posso me referir à um atributo feito dentro da classe mãe, neste código abaixo eu trato o atributo "_nome" como se fosse da própria classe filme, e obtenho sucesso.

class Filme(Programa):
    def __init__(self, nome, ano, duracao):
        super().__init__(nome, ano)
        self.duracao = duracao

    def mostrar_nome(self):
        return self._nome

Porém, quando faço:

class Filme(Programa):
    def __init__(self, nome, ano, duracao):
        super().__init__(nome, ano)
        self.duracao = duracao

    def oi(self):
        return super()._nome

Aparece o seguinte erro:

AttributeError: 'super' object has no attribute '_nome'

Mas por quê? O erro indica que "super" está sendo tratado como um Objeto, não como uma classe, como posso me referir à classe Programa dentro da classe Filme?

1 resposta
solução!

Eu pesquisei sobre isso há um tempo, mas sempre encontrei respostas como "você tem que usar a referencia de self para acessar os atributos de instância da classe". Estou assumindo que o seu código é parecido com o que está abaixo, quando inclui a classe Programa:

class Programa(object):
    def __init__(self, nome, ano):
        self._nome = nome
        self._ano = ano

class Filme(Programa):
    def __init__(self, nome, ano, duracao):
        super().__init__(nome, ano)
        self.duracao = duracao

    def oi(self):
        return self._nome


if __name__ == '__main__':
    f = Filme('Escola de Rock', 2008, 2)
    print(f.oi())

Como a resposta que encontrei funcionava, mas não entendia exatamente pq super()._nome, olhei na documentação e encontrei 2 coisas: 1) Variáveis de classe e variáveis de instancias. No primeiro caso a variável é compartilhada com todas as instâncias da classe. No segundo caso, a variável é única para cada instância. (https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables). Então eu assumi que a variável (como em nosso exemplo) nome, pertence à instância que está sendo criada.

2) ainda assim, parece confuso, mas olha o que fala a documentação de super(): "Retorna um objeto proxy (um objeto intermediário) que delega as chamadas de METODO para a classe pai" (https://docs.python.org/3.3/library/functions.html#super). Assim, assumi que super() vai nos ligar com os métodos da classe pai, e para acessar os atributos, precisamos acessar via self, pq esses atributos estão ligados à instância criada (da classe filha).

Testando a hipótese de que o objeto proxy, gerado por super() consegue acessar o atributo _nome. Vamos criar um método que retorna o nome na classe Programa:

class Programa(object):
    def __init__(self, nome, ano):
        self._nome = nome
        self._ano = ano

    def nome_encapsulado_na_classe_base(self):
        return self._nome


class Filme(Programa):
    def __init__(self, nome, ano, duracao):
        super().__init__(nome, ano)
        self.duracao = duracao

    def oi(self):
        return super().nome_encapsulado_na_classe_base()


if __name__ == '__main__':
    f = Filme('Escola de Rock', 2008, 2)
    print(f.oi())

Extra: sim é possível termos uma sintaxe como super()._nome (no exemplo abaixo super()._ano). Mas mantenha esse exemplo somente como curiosidade, pois não é um design legal. E quando vc chegar na parte de propriedades (encapsulamento), vai entender, que o mecanismo é o mesmo que o do exemplo anterior [proxy object que delega chamadas de métodos], porém com um syntax sugar:

class Programa(object):
    def __init__(self, nome, ano):
        self._nome = nome
        self.__ano = ano

    def nome_encapsulado_na_classe_base(self):
        return self._nome

    @property  # além de encapsular a variável ano, vai nos dar a sintaze `meu_obj._ano`, sem a necessidade de usar os parenteses
    def _ano(self):
        return self.__ano

class Filme(Programa):
    def __init__(self, nome, ano, duracao):
        super().__init__(nome, ano)
        self.duracao = duracao

    def oi(self):
        return super().nome_encapsulado_na_classe_base()

    def ano_filme(self):
        return super()._ano


if __name__ == '__main__':
    f = Filme('Escola de Rock', 2008, 2)
    print(f.oi())
    print(f.ano_filme())