Construtores Python e __init__

107

Por que os construtores são realmente chamados de "Construtores"? Qual é seu propósito e como eles são diferentes dos métodos em uma classe?

Além disso, pode haver mais de um __init__em uma classe? Tentei o seguinte, alguém pode explicar o resultado?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Finalmente, é __init__uma sobrecarga de operador?

Arindam Roychowdhury
fonte
41
Tecnicamente, __init__é um inicializador . O construtor python é __new__. Python usa inicialização automática de duas fases - __new__retorna um objeto válido, mas (normalmente) não preenchido (consulte boolpara um contra-exemplo), que então o __init__chamou automaticamente. Isso evita os problemas que linguagens como C ++ têm com objetos parcialmente construídos - você nunca tem um em Python (embora possa ser parcialmente inicializado). Você quase nunca precisará substituir ambos __new__e __init__em uma classe.
Tim Delaney
2
@TimDelaney: Não tenho certeza do que você quer dizer com objetos parcialmente construídos em C ++.
Sebastian Mach
11
@phresnel Em C ++, o tipo do objeto é a classe base (não a subclasse) enquanto no construtor da classe base. Você não pode chamar um método virtual no construtor da classe base e fazer com que a subclasse forneça a implementação. Em Java, você pode chamar um método de subclasse no construtor da classe base, mas as variáveis ​​de membro da subclasse serão inicializadas automaticamente após o construtor da classe base (e chamada de método). Em linguagens com inicialização de duas fases como o Python, você pode chamar métodos no inicializador da classe base e fazer com que a subclasse forneça (ou substitua) o comportamento.
Tim Delaney
@TimDelaney: Ah, obrigado pelo esclarecimento.
Sebastian Mach
4
@TimDelaney. Acho que seu comentário deve substituir a resposta aceita.
flamenco

Respostas:

114

Não há sobrecarga de função no Python, o que significa que você não pode ter várias funções com o mesmo nome, mas com argumentos diferentes.

Em seu exemplo de código, você não está sobrecarregando __init__() . O que acontece é que a segunda definição liga novamente o nome __init__ao novo método, tornando o primeiro método inacessível.

Quanto à sua pergunta geral sobre construtores, a Wikipedia é um bom ponto de partida. Para coisas específicas do Python, eu recomendo fortemente os documentos do Python .

NPE
fonte
Isso também significa que o arquivo de origem é analisado (interpretado?) Sequencialmente? Posso ter certeza de que qualquer função que defini posteriormente sobrescreve aquela definida com o mesmo nome anteriormente? :( meu Q parece bobo .. deveria saber
0xc0de
4
@ 0xc0de: No Python, as definições de função são, na verdade, instruções executáveis e executadas de cima para baixo, então sim.
NPE
1
@ 0xc0de O que realmente acontece é que o corpo da classe é executado em seu próprio namespace, esse namespace é então passado para a metaclasse (entre com o nome e as bases). As definições de função, então, estão apenas criando uma função com o corpo especificado e atribuindo-a ao seu nome. A última tarefa para __init__será o que termina na aula.
skyking
64

Por que os construtores são realmente chamados de "Construtores"?

O construtor (nomeado __new__) cria e retorna uma nova instância da classe. Portanto, o C.__new__método da classe é o construtor da classe C.

O C.__init__método de instância é chamado em uma instância específica, depois de criado, para inicializá-lo antes de ser passado de volta ao chamador. Portanto, esse método é o inicializador para novas instâncias de C.

Como eles são diferentes dos métodos de uma classe?

Conforme declarado na documentação oficial, __init__ é chamado após a criação da instância . Outros métodos não recebem este tratamento.

Qual é o seu propósito?

O objetivo do construtor C.__new__é definir o comportamento personalizado durante a construção de uma nova Cinstância.

O objetivo do inicializador C.__init__é definir a inicialização personalizada de cada instância ou Capós sua criação.

Por exemplo, Python permite que você faça:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Mas se você quiser que cada instância de Testtenha um atributo xigual a 10, você pode colocar esse código dentro de __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Cada método de instância (um método chamado em uma instância específica de uma classe) recebe a instância como seu primeiro argumento. Esse argumento é convencionalmente nomeado self.

Os métodos de classe, como o construtor __new__, recebem a classe como seu primeiro argumento.

Agora, se você quiser valores personalizados para o xatributo, tudo o que você precisa fazer é passar esse valor como argumento para __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Espero que isso ajude você a tirar algumas dúvidas, e como você já recebeu boas respostas para as outras perguntas, vou parar por aqui :)

Rik Poggi
fonte
9

As classes são simplesmente projetos para criar objetos. O construtor é um código que é executado sempre que você cria um objeto. Portanto, não faz sentido ter dois construtores. O que acontece é que o segundo sobrescreve o primeiro.

Normalmente, você os usa para criar variáveis ​​para esse objeto como este:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Então, o que você poderia fazer é criar um objeto desta classe como este:

>>> testobject = testing(5)

O testobject terá então um objeto chamado some_valueque neste exemplo será 5.

>>> testobject.some_value
5

Mas você não precisa definir um valor para cada objeto, como fiz no meu exemplo. Você também pode fazer assim:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

então, o valor de algum_valor será 5 e você não precisa defini-lo ao criar o objeto.

>>> testobject = testing()
>>> testobject.some_value
5

o >>> e ... na minha amostra não é o que você escreve. É como ficaria no pyshell ...

Niclas Nilsson
fonte
Não tem problema, fico feliz que tenha ajudado :)
Niclas Nilsson
1

os co-construtores são chamados automaticamente quando você cria um novo objeto, assim "construindo" o objeto. A razão pela qual você pode ter mais de um init é porque os nomes são apenas referências em python, e você tem permissão para alterar o que cada variável faz referência quando quiser (daí a tipagem dinâmica)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

na definição de sua classe, ele apenas mantém o último

Ryan Haining
fonte
0

Não há noção de sobrecarga de método em Python. Mas você pode obter um efeito semelhante especificando argumentos opcionais e de palavra-chave

NLPer
fonte