O que __init__ e self fazem no Python?

793

Estou aprendendo a linguagem de programação Python e me deparei com algo que não entendo completamente.

Em um método como:

def method(self, blah):
    def __init__(?):
        ....
    ....

O que selffaz? O que deveria ser? Isso é obrigatório?

O que o __init__método faz? Por que isso é necessário? (etc.)

Eu acho que eles podem ser construções OOP, mas eu não sei muito.

ivanleoncz
fonte

Respostas:

585

Neste código:

class A(object):
    def __init__(self):
        self.x = 'Hello'

    def method_a(self, foo):
        print self.x + ' ' + foo

... a selfvariável representa a instância do próprio objeto. A maioria das linguagens orientadas a objetos passa isso como um parâmetro oculto para os métodos definidos em um objeto; Python não. Você tem que declarar explicitamente. Quando você cria uma instância da Aclasse e chama seus métodos, ela é passada automaticamente, como em ...

a = A()               # We do not pass any argument to the __init__ method
a.method_a('Sailor!') # We only pass a single argument

O __init__método é aproximadamente o que representa um construtor em Python. Quando você chama A()Python, cria um objeto para você e o passa como o primeiro parâmetro para o __init__método Quaisquer parâmetros adicionais (por exemplo, A(24, 'Hello')) também serão passados ​​como argumentos - nesse caso, causando uma exceção a ser levantada, pois o construtor não os espera.

Chris B.
fonte
8
e se você colocar x = 'Hello'fora do init, mas dentro da classe? é como java onde é o mesmo ou se torna uma variável estática que é inicializada apenas uma vez?
Jayen
15
É como uma variável estática. É inicializado apenas uma vez e está disponível através de A.xou a.x. Note-se que substituindo-lo em uma classe específica não afetará a base, então A.x = 'foo'; a.x = 'bar'; print a.x; print A.xirá imprimir barentãofoo
Chris B.
156
Vale ressaltar que o primeiro argumento não precisa ser necessariamente chamado self, é apenas por convenção.
Henry Gomersall
13
Qual é o sentido da objectdeclaração de classe? Eu notei que algumas classes têm isso e outras não
Chris
9
@ Chris É para compatibilidade com Python 2. No Python 3, não há necessidade de herdar explicitamente, objectporque isso acontece por padrão.
Gabriel
241

Sim, você está certo, essas são construções oop.

__init__é o construtor de uma classe. O selfparâmetro refere-se à instância do objeto (como thisem C ++).

class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

O __init__método é chamado quando a memória do objeto é alocada:

x = Point(1,2)

É importante usar o selfparâmetro dentro do método de um objeto se você quiser persistir o valor com o objeto. Se, por exemplo, você implementar o __init__método como este:

class Point:
    def __init__(self, x, y):
        _x = x
        _y = y

Seus parâmetros xe yseriam armazenados em variáveis ​​na pilha e descartados quando o método init fica fora do escopo. Definir essas variáveis ​​como self._xe self._ydefine essas variáveis ​​como membros do Pointobjeto (acessível para a vida útil do objeto).

RedBlueThing
fonte
1
Então, existe alguma razão pela qual você não gostaria selfde estar no construtor? Por que você precisa especificar, não seria melhor se estivesse implícito?
68568 Aaron Franke
Até onde eu sei, __ init __ não é um construtor, é o primeiro método que será executado quando qualquer objeto for criado, __ init __ é usado para configurar o objeto. __ new __ é o construtor em python.
Deepanshu
206

Um breve exemplo ilustrativo

Na esperança de que possa ajudar um pouco, aqui está um exemplo simples que eu usei para entender a diferença entre uma variável declarada dentro de uma classe e uma variável declarada dentro de uma __init__função:

class MyClass(object):
    i = 123
    def __init__(self):
        self.i = 345

a = MyClass()
print(a.i)
print(MyClass.i)

Resultado:

345
123
Dave Everitt
fonte
7
Observação interessante, mas acho que você está no caminho errado. Com a impressão MyClass.i, parece mais que você está chamando uma variável 'estática' i. Onde, com ai, você está chamando uma variável de membro, i. Parece-me que o init é apenas um construtor que é executado pela primeira vez quando você cria um objeto da classe.
captainspi
34
Isso é o que eu estava tentando 'explicar a mim mesmo' com este exemplo - que a variável definida por __init__é o que é passado para instâncias da classe, não a variável 'estática' da própria classe que tem o mesmo nome ...
Dave Everitt
44

Em resumo:

  1. selfcomo sugere, refere-se a si mesmo - o objeto que chamou o método. Ou seja, se você tiver N objetos chamando o método, self.ase referirá a uma instância separada da variável para cada um dos N objetos. Imagine N cópias da variável apara cada objeto
  2. __init__é o que é chamado como construtor em outras linguagens OOP, como C ++ / Java. A idéia básica é que seja um método especial chamado automaticamente quando um objeto dessa classe é criado
Acumenus
fonte
29

__init__age como um construtor. Você precisará passar "self" para qualquer função de classe como o primeiro argumento, se desejar que eles se comportem como métodos não estáticos. "self" são variáveis ​​de instância para sua classe.

ewalk
fonte
1
'self' define se um método é estático ou não! Uau, isso é um abridor de olhos para esse cara de java.
Liwevire
25

Experimente este código. Espero que ajude muitos programadores em C como eu a aprender Py.

#! /usr/bin/python2

class Person:

    '''Doc - Inside Class '''

    def __init__(self, name):
        '''Doc - __init__ Constructor'''
        self.n_name = name        

    def show(self, n1, n2):
        '''Doc - Inside Show'''
        print self.n_name
        print 'Sum = ', (n1 + n2)

    def __del__(self):
        print 'Destructor Deleting object - ', self.n_name

p=Person('Jay')
p.show(2, 3)
print p.__doc__
print p.__init__.__doc__
print p.show.__doc__

Resultado:

Jay

Sum = 5

Doc - Inside Class

Doc - __init__ Constructor

Doc - Inside Show

Destructor Deleting object - Jay

Jayzcode
fonte
Não sei se sou apenas eu, mas ler este código foi um pouco confuso. Talvez seja porque eu ainda sou um programador iniciante em Python, idk.
Linny
Eu não sou claro sobre o assunto do documento .. ele puxa a documentação? e se eu fizer: '' 'test - my doc' '', posso usar: print.p .__ test__? ou doc ​​é uma palavra-chave específica?
Thomas
@Thomas doc é a palavra-chave para detalhes documentados. As aspas triplas são usadas para anotar documentos e o documento é uma entidade opcional.
Jayzcode
25

Objetos de classe suportam dois tipos de operações: referências de atributo e instanciação

As referências de atributo usam a sintaxe padrão usada para todas as referências de atributo em Python: obj.name. Nomes de atributos válidos são todos os nomes que estavam no espaço de nomes da classe quando o objeto da classe foi criado. Portanto, se a definição de classe fosse assim:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

em seguida, MyClass.ie MyClass.fsão referências a atributos válidos, retornando um número inteiro e um objeto de função, respectivamente. Os atributos de classe também podem ser atribuídos, para que você possa alterar o valor MyClass.ipor atribuição. __doc__também é um atributo válido, retornando a docstring pertencente à classe: "A simple example class".

A instanciação de classe usa notação de função. Apenas finja que o objeto de classe é uma função sem parâmetros que retorna uma nova instância da classe. Por exemplo:

x = MyClass()

A operação de instanciação ("chamando" um objeto de classe) cria um objeto vazio. Muitas classes gostam de criar objetos com instâncias personalizadas para um estado inicial específico. Portanto, uma classe pode definir um método especial chamado __init__(), assim:

def __init__(self):
    self.data = []

Quando uma classe define um __init__()método, a instanciação de classe invoca automaticamente a instância de classe __init__()recém-criada. Portanto, neste exemplo, uma nova instância inicializada pode ser obtida por:

x = MyClass()

Obviamente, o __init__()método pode ter argumentos para maior flexibilidade. Nesse caso, os argumentos fornecidos ao operador de instanciação de classe são transmitidos para __init__(). Por exemplo,

class Complex:
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart

x = Complex(3.0, -4.5)
x.r, x.i

Retirado da documentação oficial que mais me ajudou no final.


Aqui está o meu exemplo

class Bill():
    def __init__(self,apples,figs,dates):
        self.apples = apples
        self.figs = figs
        self.dates = dates
        self.bill = apples + figs + dates
        print ("Buy",self.apples,"apples", self.figs,"figs 
                and",self.dates,"dates. 
                Total fruitty bill is",self.bill," pieces of fruit :)")

Quando você cria uma instância da classe Bill:

purchase = Bill(5,6,7)

Você obtém:

> Buy 5 apples 6 figs and 7 dates. Total fruitty bill is 18  pieces of
> fruit :)
Harvey
fonte
22

Eu tive problemas para entender isso sozinho. Mesmo depois de ler as respostas aqui.

Para entender corretamente o __init__método, você precisa entender a si mesmo.

O auto Parâmetro

Os argumentos aceitos pelo __init__método são:

def __init__(self, arg1, arg2):

Mas nós apenas passamos dois argumentos:

instance = OurClass('arg1', 'arg2')

De onde vem o argumento extra?

Quando acessamos os atributos de um objeto, fazemos por nome (ou por referência). Aqui, a instância é uma referência ao nosso novo objeto. Acessamos o método printargs do objeto de instância usando instance.printargs.

Para acessar os atributos do objeto de dentro do __init__método, precisamos de uma referência ao objeto.

Sempre que um método é chamado, uma referência ao objeto principal é passada como o primeiro argumento. Por convenção, você sempre chama esse primeiro argumento aos seus métodos.

Isso significa que no __init__método que podemos fazer:

self.arg1 = arg1
self.arg2 = arg2

Aqui estamos definindo atributos no objeto. Você pode verificar isso fazendo o seguinte:

instance = OurClass('arg1', 'arg2')
print instance.arg1
arg1

valores como esse são conhecidos como atributos do objeto. Aqui, o __init__método define os atributos arg1 e arg2 da instância.

fonte: http://www.voidspace.org.uk/python/articles/OOP.shtml#the-init-method

eee
fonte
17

observe que, selfna verdade, pode ser qualquer identificador python válido. Por exemplo, poderíamos escrever com a mesma facilidade, a partir do exemplo de Chris B:

class A(object):
    def __init__(foo):
        foo.x = 'Hello'

    def method_a(bar, foo):
        print bar.x + ' ' + foo

e funcionaria exatamente da mesma maneira. No entanto, é recomendável usar self, porque outros pythoners o reconhecerão mais facilmente.

SingleNegationElimination
fonte
Concordo que a auto seria recomendado no lugar de foo, ajuda a outros programadores com olhar para o código
Linny
15

Basicamente, você precisa usar a palavra-chave 'self' ao usar uma variável em várias funções na mesma classe. Quanto ao init , é usado para configurar valores padrão, caso nenhuma outra função dessa classe seja chamada.

user1675111
fonte
6
Não há palavra-chave 'self' no Python. Chamar o primeiro parâmetro de 'self' é simplesmente uma convenção.
David Anderson
self é usado basicamente como espaço reservado. Não é necessário que você use auto, você poderia usar "eeee" ou "foo" ou qualquer outra coisa, é apenas recomendado para outros programadores durante a leitura de seu código
Linny
15
  1. __init__é basicamente uma função que "inicializa" / "ativa" as propriedades da classe para um objeto específico, uma vez criada e correspondida à classe correspondente.
  2. self representa o objeto que herdará essas propriedades.
Atlas
fonte
1
a palavra-chave "self" não precisa ser usada, é apenas um espaço reservado. Você pode usar qualquer palavra, mas é recomendável que você usa auto para ajudar a legibilidade do programa
Linny
13

O 'self' é uma referência à instância da classe

class foo:
    def bar(self):
            print "hi"

Agora podemos criar uma instância de foo e chamar o método, o parâmetro self é adicionado pelo Python neste caso:

f = foo()
f.bar()

Mas também pode ser passado se a chamada do método não estiver no contexto de uma instância da classe, o código abaixo faz a mesma coisa

f = foo()
foo.bar(f)

Curiosamente, o nome da variável 'self' é apenas uma convenção. A definição abaixo funcionará exatamente da mesma maneira. Dito isto, é uma convenção muito forte que deve ser seguida sempre , mas diz algo sobre a natureza flexível da linguagem

class foo:
    def bar(s):
            print "hi"
Tarn
fonte
Por que isso diz algo sobre a natureza flexível da linguagem? Diz apenas que você pode dar às variáveis ​​o nome legal que você escolher. Como isso é diferente de qualquer outra linguagem de programação?
Daniel
Como escrevi na minha resposta, "bar" é apenas uma função em que uma instância de classe é fornecida como o primeiro parâmetro. Portanto, enquanto "bar" é definido como um método vinculado a "foo", também pode ser chamado com uma instância de alguma outra classe. Não é assim que métodos e "isso" funcionam em Java, por exemplo, embora eu imagine que você veja que esses são o mesmo conceito, funções e algum contexto de instância (o contexto de instância sendo o primeiro parâmetro em Python e "isso" em Java ") Talvez agora você consiga ver a flexibilidade do idioma ao qual eu estava me referindo?
tarn
Sim, isso mostra a flexibilidade do idioma. Do jeito que você formulou sua resposta, parecia que você estava dizendo que o fato de poder chamar a variável "self" de outra coisa (como s) estava mostrando a flexibilidade do python.
Daniel
12

Apenas uma demonstração para a pergunta.

class MyClass:

    def __init__(self):
        print('__init__ is the constructor for a class')

    def __del__(self):
        print('__del__ is the destructor for a class')

    def __enter__(self):
        print('__enter__ is for context manager')
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print('__exit__ is for context manager')

    def greeting(self):
        print('hello python')


if __name__ == '__main__':
    with MyClass() as mycls:
        mycls.greeting()

$ python3 class.objects_instantiation.py
__init__ is the constructor for a class
__enter__ is for context manager
hello python
__exit__ is for context manager
__del__ is the destructor for a class
depurar
fonte
11

Neste código:

class Cat:
    def __init__(self, name):
        self.name = name
    def info(self):
        print 'I am a cat and I am called', self.name

Aqui __init__atua como um construtor para a classe e quando um objeto é instanciado, essa função é chamada. selfrepresenta o objeto instanciador.

c = Cat('Kitty')
c.info()

O resultado das instruções acima será o seguinte:

I am a cat and I am called Kitty
Anagha
fonte
11

O que o eu faz? O que deveria ser? Isso é obrigatório ?

O primeiro argumento de todo método de classe, incluindo init, é sempre uma referência à instância atual da classe . Por convenção, esse argumento sempre é nomeado self. No método init, selfrefere-se ao objeto recém-criado; em outros métodos de classe, refere-se à instância cujo método foi chamado.

O Python não força você a usar o " self ". Você pode dar o nome que quiser. Mas lembre-se de que o primeiro argumento em uma definição de método é uma referência ao objeto . Python adiciona o selfargumento à lista para você; você não precisa incluí-lo quando chama os métodos. se você não forneceu o método init no init, receberá um erro

TypeError: __init___() takes no arguments (1 given)

O que o método init faz? Por que isso é necessário? (etc.)

inité curto para inicialização. É um construtor que é chamado quando você cria uma instância da classe e não é necessário . Mas geralmente é nossa prática escrever o método init para definir o estado padrão do objeto. Se você não estiver disposto a definir nenhum estado do objeto inicialmente, não precisará escrever esse método.

Muhammad Faizan Khan
fonte
8
# Source: Class and Instance Variables
# https://docs.python.org/2/tutorial/classes.html#class-and-instance-variables

class MyClass(object):
    # class variable
    my_CLS_var = 10

    # sets "init'ial" state to objects/instances, use self argument
    def __init__(self):
        # self usage => instance variable (per object)
        self.my_OBJ_var = 15

        # also possible, class name is used => init class variable
        MyClass.my_CLS_var = 20


def run_example_func():
    # PRINTS    10    (class variable)
    print MyClass.my_CLS_var

    # executes __init__ for obj1 instance
    # NOTE: __init__ changes class variable above
    obj1 = MyClass()

    # PRINTS    15    (instance variable)
    print obj1.my_OBJ_var

    # PRINTS    20    (class variable, changed value)
    print MyClass.my_CLS_var


run_example_func()
Manohar Reddy Poreddy
fonte
5

Python __init__e selfo que eles fazem?

O que selffaz? O que deveria ser? Isso é obrigatório?

O que o __init__método faz? Por que isso é necessário? (etc.)

O exemplo dado não está correto, então deixe-me criar um exemplo correto com base nele:

class SomeObject(object):

    def __init__(self, blah):
        self.blah = blah

    def method(self):
        return self.blah 

Quando criamos uma instância do objeto, o __init__é chamado para personalizar o objeto depois que ele foi criado. Isto é, quando chamamos SomeObjectcom 'blah'abaixo (que poderia ser qualquer coisa), ele é passado para a __init__função como argumento, blah:

an_object = SomeObject('blah')

O selfargumento é a instância do SomeObjectqual será atribuído an_object.

Mais tarde, convém chamar um método neste objeto:

an_object.method()

Fazer a pesquisa pontilhada, ou seja, an_object.methodvincula a instância a uma instância da função, e o método (como chamado acima) agora é um método "vinculado" - o que significa que não precisamos passar explicitamente a instância para a chamada do método .

A chamada de método obtém a instância porque estava vinculada à pesquisa pontilhada e, quando chamada, executa o código que foi programado para executar.

O selfargumento implicitamente passado é chamado selfpor convenção. Poderíamos usar qualquer outro nome legal do Python, mas você provavelmente será prejudicado por outros programadores do Python se o mudar para outra coisa.

__init__é um método especial, documentado na documentação do modelo de dados Python . É chamado imediatamente após a criação da instância (geralmente via __new__- embora __new__não seja necessária, a menos que você esteja subclassificando um tipo de dados imutável).

Aaron Hall
fonte
3

Aqui, o cara escreveu muito bem e simples: https://www.jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/

Leia o link acima como uma referência para isso:

self? Então, o que há com esse parâmetro automático para todos os métodos do cliente? O que é isso? Por que, é o caso, é claro! Dito de outra forma, um método como sacar define as instruções para sacar dinheiro da conta de algum cliente abstrato. Chamar jeff.withdraw (100.0) coloca essas instruções para usar na instância jeff.

Então, quando dizemos def retirada (auto, quantidade) :, estamos dizendo: "aqui está como você retira dinheiro de um objeto Customer (que chamaremos de self) e de uma figura em dólar (que chamamos de quantidade). é a instância do Cliente em que a retirada está sendo solicitada.Eu também não estou fazendo analogias. jeff.withdraw (100.0) é apenas uma abreviação de Customer.withdraw (jeff, 100.0), que é perfeitamente válido (se não for visto com frequência) código.

O init self pode fazer sentido para outros métodos, mas e o init ? Quando chamamos init , estamos no processo de criar um objeto, então como já pode haver um eu? O Python nos permite estender o padrão próprio para quando os objetos também são construídos, mesmo que não se encaixe exatamente. Imagine que jeff = Customer ('Jeff Knupp', 1000.0) é o mesmo que chamar jeff = Customer (jeff, 'Jeff Knupp', 1000.0); o jeff passado é também o resultado.

É por isso que quando chamamos init , inicializamos objetos dizendo coisas como self.name = name. Lembre-se, já que self é a instância, isso é equivalente a dizer jeff.name = name, que é o mesmo que jeff.name = 'Jeff Knupp. Da mesma forma, self.balance = balance é o mesmo que jeff.balance = 1000.0. Após essas duas linhas, consideramos o objeto Customer "inicializado" e pronto para uso.

Cuidado com o que você __init__

Após a conclusão do init , o chamador pode assumir, com razão, que o objeto está pronto para uso. Ou seja, depois de jeff = Customer ('Jeff Knupp', 1000.0), podemos começar a fazer depósitos e retirar chamadas em jeff; jeff é um objeto totalmente inicializado.

Laxmikant
fonte