Como retornar um valor de __init__ em Python?

102

Eu tenho uma aula com uma __init__função.

Como posso retornar um valor inteiro desta função quando um objeto é criado?

Eu escrevi um programa, onde __init__analisa a linha de comando e preciso definir algum valor. Tudo bem defini-lo na variável global e usá-lo em outras funções de membro? Se sim, como fazer isso? Até agora, declarei uma variável fora da classe. e defini-la como uma função não reflete em outra função ??

webminal.org
fonte
8
Se você estava pensando em retornar um código de erro, em vez disso, gere uma exceção.
JoeG
1
Por favor, remova seu comentário e atualize sua pergunta. Você possui a pergunta. É a sua pergunta. Por favor, corrija a questão para mostrar corretamente qual é o seu verdadeiro problema. Você está usando mal __init__; podemos ajudá-lo se você descrever o que realmente está tentando realizar.
S.Lott,

Respostas:

117

__init__é necessário retornar Nenhum. Você não pode (ou pelo menos não deveria) devolver outra coisa.

Tente fazer o que quiser para retornar uma variável de instância (ou função).

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None
Can Berk Güder
fonte
24
+1: Você não pode devolver outra coisa. Não faz sentido.
S.Lott,
72
init não retorna o objeto recém-criado - como visto no TypeError, é necessário retornar None, certo? O objeto recém-criado é retornado por new , init apenas define alguns de seus atributos. Mas sim, como você disse, alterar init , ou new , para retornar outra coisa realmente não faz sentido.
weronika
Onde fica newaqui? Está newimplícito em Python? Presumi que a semântica do Python era diferente do Java e das outras linguagens que usam essa palavra.
cs95 de
1
@Shiva AFAIK, por new weronika significava __new __ (self) não a semântica geral do java.
Harsh Daftary
2
Só porque isso não pode ser feito, não significa que não faça sentido. Seria, por exemplo, bom passar dados da super().__init__classe derivada sem ter que retransmiti-los por meio de uma variável de instância.
cz
123

Por que você gostaria de fazer isso?

Se você quiser retornar algum outro objeto quando uma classe for chamada, use o __new__()método:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj
Jacek Konieczny
fonte
9
Sim, novo é a maneira certa de retornar algo diferente de uma instância de classe ao usar uma classe ... Eu só estou me perguntando - há alguma razão para você realmente querer FAZER isso?
weronika
33
@weronika Uma ideia: em qualquer situação em que você normalmente usaria uma fábrica, mas tem algum motivo para querer apresentar uma interface que se pareça com uma instanciação normal de classe. Exemplo: ao adicionar alguns novos parâmetros opcionais em sua classe __init__, você percebe que realmente, para fornecer a flexibilidade que deseja, você precisa de uma fábrica de classes que retorna instâncias de subclasses especializadas. Mas os usuários de sua biblioteca já estão usando sua API existente. Para preservá-lo, você substitui __new__para retornar instâncias de suas subclasses especializadas.
Mark Amery
10
Se você quiser ver um exemplo do que disse Mark Amery, verifique o código-fonte do datetimemódulo na Biblioteca Padrão. Ele usa __new__exatamente dessa maneira.
Zearin de
Além disso, se alguém quiser fazer isso, certifique-se de herdar do objeto, caso contrário, não funcionará.
Mino_e
Eu meio que acho que neste ponto, apenas usar uma função regular faz mais sentido. Pode ser um pouco estranho para as pessoas da dimensão Java (funções não em classes? Heresia!), Mas é pitônico. (Você também pode atribuir propriedades a funções como em funtionName.val = .. que é meio selvagem, mas funciona)
Shayne
37

Da documentação de__init__ :

Como uma restrição especial nos construtores, nenhum valor pode ser retornado; isso fará com que um TypeError seja gerado no tempo de execução.

Como prova, este código:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

Dá este erro:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'
nosklo
fonte
17

A amostra de uso do assunto em questão pode ser assim:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

Não tenho reputação suficiente, então não posso escrever um comentário, é uma loucura! Eu gostaria de poder postá-lo como um comentário para weronika

PMN
fonte
3
Isso gerará um NameError: selfnão está definido em__new__(cls, Item)
Hart Simha
15

O __init__método, como outros métodos e funções, retorna None por padrão na ausência de uma instrução return, portanto, você pode escrevê-lo como um destes:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

Mas, é claro, adicionar o return Nonenão compra nada.

Não tenho certeza do que você está procurando, mas pode estar interessado em um destes:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

estampas:

42
42
Quamrana
fonte
ohh .. Posso acessar a variável de membro da classe? Então isso deve resolver meu problema ... obrigado
webminal.org
@lakshmipathi, Sim, variáveis ​​de instância como essa são públicas.
quamrana
Como um oneliner para obter algo valioso devolvido após o início de uma aula:f = Foo().value
JLT
@JLT Sim, você pode sempre fazer isso, mas ainda não significa que alguma coisa foi devolvida __init__.
quamrana
7

__init__não retorna nada e deve sempre retornar None.

gruszczy
fonte
4

Você pode apenas defini-lo como uma variável de classe e lê-lo no programa principal:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode
PythonPro
fonte
2

Só queria adicionar, você pode devolver aulas em __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

O método acima ajuda a implementar uma ação específica em uma exceção em seu teste


fonte
2
super().__init__está retornando None, então você está retornando None, o que é bom, mas redundante.
cz
2

init () não retorna nenhum valor resolvido perfeitamente

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

saída: minha velocidade é de 21 kmh

vikram singh gurjar
fonte
-2

Bem, se você não se importa mais com a instância do objeto ... você pode simplesmente substituí-la!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'
cosmo
fonte
2
Isso apenas altera o que é atribuído ao nome selfdentro desse construtor.
Ondrej K.