Onde fica o construtor da classe em Python? – python orientação-a-objetos classes

Pergunta:


Definição da Wikipédia.

O construtor é um método
que geralmente é responsável pela alocação de recursos necessários ao
funcionamento do objeto além da definição inicial das variáveis de
estado (atributos).

Em Python normalmente é usado o método __init__ para definir os valores dos atributos, isto é o que eu compreendo a respeito deste método, ou seja, em meu ponto de vista ele é um construtor. Veja o exemplo para a ilustração:

class Carro(object):
    def __init__(self, modelo, ano): #Construtor da classe.
        self.modelo = modelo
        self.ano = ano

meuCarro = Carro("Jeep 4x4", 2015)

print("Modelo: %s" % meuCarro.modelo)
print("Ano: %d" % meuCarro.ano)

Contudo, na pesquisa que fiz, eu descobri que o método __init__ não é o construtor da classe, e sim o método chamado quando um objeto é requerido. Agora fiquei confuso a respeito de onde é o local de um construtor de uma classe em Python. Onde seria o local do construtor?

Autor da pergunta gato

Resposta Comunidade:

O que é um construtor

Isto é uma tecnicalidade. Podemos considerá-lo como o construtor. De fato ele é um inicializador, conforme já havia escrito em pergunta anterior. Mas o inicializador será chamado todas as vezes que for criado um objeto novo, logo após chamar o __new__ que será o alocador de memória do objeto. Este alocador é provido pela linguagem se você não definir um, o que raramente é necessário, normalmente em objetos imutáveis pode ser interessante.

E é isso. Se fizer uma pesquisa mais profunda verá que todos, no dia a dia, chamarão o __init__ de construtor. Se não chamar ele de construtor, então todas linguagens que eu conheço estão usando o nome errado, porque o que elas chamam de construtor também é um inicializador. Elas também costumam chamar o alocador implicitamente e normalmente não é necessário defini-lo em todas as classes. Claro que se for ser detalhista, o terminologia não é bem essa mesmo.

__del__ é o destrutor, certo? Ou é só um “desinicializador”, ou só um desalocador? Para todos os efeitos, ele destrói o objeto. Ele é o oposto do __new__ ou o oposto do __init__? A documentação diz que ele é um destrutor. Então um dos dois é o construtor :).

A construção do objeto em Python ocorre em dois passos, o que também é verdade em várias linguagens. Nem sempre é aparente porque a alocação costuma ser pouco explorada. Em C++, por exemplo é possível sobrepor o operador new para criar uma alocação personalizada. Em C# ou Java, não é possível. Mas note que nessas linguagens o construtor é só um inicializador, e por acaso sempre será chamado o alocador, que é fixo, antes de inicializar os membros, mas a construção é a inicialização. Então podemos dizer que o inicializador é o construtor. E claro que ele nunca poderá ser chamado antes de chamar o alocador.

Constructor expression

O que você pode fazer é criar uma expressão de construtor, que é uma forma de dar ao consumidor daquela classe um jeito de explicitamente fazer toda construção do objeto e, obviamente deverá fazer a alocação e a inicialização de alguma forma, mesmo que chamando os método que já sabem fazer isto. O que não faria sentido se for para fazer exatamente a mesma coisa. E é claro que precisa saber o que está fazendo para não cometer erros. Ele é uma forma de dar mais flexibilidade para a construção.

Para criar uma forma da classe fazer outras atividades além da alocação e inicialização, precisa dar capacidade dela ser chamada como uma função. Isto se dá criando um método __call__. Então:

class A(object):
    def __init__(self):
        print("init")
    def __call__(self):
        print("call ")

a = A() #imprime init
A() #imprime call

Se ambos tiverem a mesma assinatura, o __init__ será chamado, a não ser que chame o __call explicitamente, simplificadamente: A()(). O __init__ sempre será chamado antes.

Exemplos de uso do __call__.

Eu não chamaria isso de construtor.

Factory method

Ainda é possível criar um método estático (sem o self) que pode ser chamado para invocar a construção do objeto, mas não vejo isto com bons olhos. Não me parece idiomático.

Veja funcionando no ideone.

Leitura adicional

A documentação sobre objetos do Python é uma boa leitura para entender tudo isto. Um artigo que fala bastante sobre estes métodos mágicos.

o Método __init__ é o inicializador da classe, tanto que o momento que ele é executado você já possui a instância criada (self), em python o método construtor de classe é o __new__:

class Foo:
    def __new__(cls):
        return cls()

Repare que diferente do __init__ o método __new__ precisa retornar um valor, no caso a instancia da classe que está sendo criada. Veja a documentação oficial para mais detalhes.

Um exemplo de uso do método __new__ é na criação de objetos singletons:

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

Porem, em 99% dos casos, você não precisa (e talvez não deva) alterar o método construtor da sua classe.

Fonte

Related Posts:

Qual a diferença entre AppCompatActivity e Activity? – android android-activity
Pergunta: Qual a diferença da AppCompatActivity para Activity ? A partir de qual versão a AppCompatActivity foi adicionada ao Android? Autor da pergunta Luhhh A diferença reside ...
Como abreviar palavras em PHP? – php string
Pergunta: Possuo informações comuns como nome de pessoas e endereços, e preciso que elas contenham no máximo 30 caracteres sem cortar palavras. Exemplo: 'Avenida Natalino João Brescansin' ...
Qual é a finalidade de um parêntese vazio numa declaração Lambda? – c# expressões-lambda característica-linguagem
Pergunta: Criei um exemplo de uma declaração Lambda sem argumentos, entretanto, estou com duvidas referente a omissão do parêntese vazio () na declaração. Veja o exemplo: class ...
Boas práticas para URI em API RESTful – api rest restful
Pergunta: Estou com dúvida em relação às URIs de alguns recursos da api que estou desenvolvendo. Tenho os recursos projetos e atividades com relação 1-N, ...
Dúvidas sobre a integração do MySQL com Java – java mysql netbeans
Pergunta: Estou criando um sistema no NetBeans, utilizando a linguagem Java e o banco de dados MySQL. Escrevi o seguinte código para realizar a conexão ...
Qual é a finalidade da pasta Model do framework Inphinit? – php inphinit
Pergunta: No Inphinit micro-framework existe a pasta Model que fica dentro da pasta application, e nela é onde ficam as classes, mas eu estou muito ...
Uso do ‘@’ em variáveis – javascript typescript coffeescript
Pergunta: Vejo em algumas linguagens que compilam para javascript, como TypeScript e CoffeeScript, o uso do @ em variáveis, como também, casos em que o ...
Qual tamanho máximo um arquivo JSON pode ter? – json arquivo
Pergunta: Vou dar um exemplo para conseguir explicar minha duvida: Preciso recuperar informação de imagens vindas de uma API, esse banco de imagens me retorna JSON's ...
O que é Teste de Regressão? – terminologia engenharia-de-software testes
Pergunta: Na matéria de Teste de Software o professor abordou um termo chamado Teste de Regressão, isto dentro da disciplina de teste de software. Sendo ...
O que é um construtor da linguagem? – php característica-linguagem
Pergunta: Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos ...
Função intrínseca para converter numérico para string – cobol
Pergunta: Estou a tentar saber se existe alguma função intrínseca do COBOL para converter um data numérico para string sem precisar usar a cláusula REDEFINES: ( ...
Porque usar implements? – java android
Pergunta: Qual a diferença entre usar btn.setOnClickListener(new OnClickListener() { e public class MainActivity extends Activity implements OnClickListener{ Estive fazendo um curso de Android e meu professor falou que ...
O que é XHTML e quando deve ser usado? – html xml xhtml
Pergunta: O que eu sei é que o XHTML precisa ser XML válido. Isso implica, por exemplo, que todas as tags precisam ser fechadas. Por ...
Uma placa aceleradora de vídeo pode melhorar o desempenho não-gráfico? [fechada] – desempenho
Pergunta: Para desenvolver em Ruby on Rails, eu utilizo aqui uma máquina virtual do VirtualBox com Ubuntu Server 14.04 sem interface gráfica instalada. Recentemente descobri uma ...
Concat() VS Union() – c# .net
Pergunta: Qual a diferença entre Concat() e Union() ? Quando usar Concat() e quando usar Union() ? Somente pode ser usado em list ? ...

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *