Jak zwrócić wartość z __init__ w Pythonie?


103

Mam klasę z __init__funkcją.

Jak mogę zwrócić wartość całkowitą z tej funkcji podczas tworzenia obiektu?

Napisałem program, w którym __init__analizuje się wiersz poleceń i potrzebuję ustawić jakąś wartość. Czy można ustawić to w zmiennej globalnej i używać w innych funkcjach składowych? Jeśli tak, jak to zrobić? Do tej pory zadeklarowałem zmienną poza klasą. a ustawienie jednej funkcji nie odzwierciedla się w innej funkcji?


8
Jeśli rozważasz zwrócenie kodu błędu, zgłoś wyjątek.
JoeG

1
Usuń komentarz i zaktualizuj swoje pytanie. Masz pytanie. To twoje pytanie. Rozwiąż pytanie, aby poprawnie pokazać, jaki jest twój prawdziwy problem. Nadużywasz __init__; możemy Ci pomóc, jeśli opiszesz, co naprawdę próbujesz osiągnąć.
S.Lott

Odpowiedzi:


119

__init__jest wymagany do zwrócenia Brak. Nie możesz (a przynajmniej nie powinieneś) zwrócić czegoś innego.

Spróbuj zrobić wszystko, co chcesz, aby zwrócić zmienną instancji (lub funkcję).

>>> 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

24
+1: Nie możesz zwrócić czegoś innego. To nie ma sensu.
S.Lott,

72
init nie zwraca nowo utworzonego obiektu - jak widać w TypeError, wymagane jest zwrócenie None, prawda? Nowo utworzony obiekt jest zwracany przez new , init po prostu ustawia niektóre jego atrybuty. Ale tak, jak powiedziałeś, zmiana init lub nowego , aby zwrócić coś innego, naprawdę nie ma sensu.
weronika

Gdzie newtu jest ? Czy jest newukryty w Pythonie? Założyłem, że semantyka Pythona różni się od języka Java i innych języków, które używają tego słowa.
cs95

1
@Shiva AFAIK, przez new weronika oznaczało __new __ (self), a nie ogólną semantyczną java.
Harsh Daftary

2
To, że nie można tego zrobić, nie oznacza, że ​​nie ma to sensu. Byłoby na przykład dobrze przekazać dane z super().__init__klasy pochodnej bez konieczności przekazywania ich przez zmienną instancji.
cz

123

Dlaczego chcesz to zrobić?

Jeśli chcesz zwrócić jakiś inny obiekt po wywołaniu klasy, użyj __new__()metody:

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

obj = MyClass()
print obj

9
Tak, nowy to właściwy sposób zwracania czegoś innego niż instancja klasy podczas korzystania z klasy ... Zastanawiam się tylko - czy jest jakiś powód, dla którego mógłbyś chcieć to ZROBIĆ?
weronika

33
@weronika Jeden pomysł: w każdej sytuacji, w której normalnie korzystasz z fabryki, ale masz powód, aby zaprezentować interfejs, który wygląda jak zwykła instancja klasy. Przykład: dodając kilka nowych parametrów opcjonalnych do swojej klasy __init__, zdajesz sobie sprawę, że naprawdę, aby zapewnić pożądaną elastyczność, potrzebujesz fabryki klas, która zwraca wystąpienia wyspecjalizowanych podklas. Jednak użytkownicy Twojej biblioteki już używają istniejącego interfejsu API. Aby to zachować, nadpisujesz __new__zwracanie wystąpień wyspecjalizowanych podklas.
Mark Amery,

10
Jeśli chcesz zobaczyć przykład tego, co powiedział Mark Amery, sprawdź kod źródłowy datetimemodułu z Biblioteki standardowej. Używa __new__dokładnie w ten sposób.
Zearin

Również jeśli ktoś chce to zrobić, pamiętaj, aby dziedziczyć po obiekcie, w przeciwnym razie to nie zadziała.
Mino_e,

Wydaje mi się, że w tym przypadku samo użycie zwykłej funkcji ma więcej sensu. Może być trochę obcy dla ludzi z wymiaru Java (funkcje nie w klasach - herezja!), Ale z jego Pythona. (Możesz także przypisać właściwości do funkcji jak w funtionName.val = .. co jest trochę dzikie, ale działa)
Shayne

37

Z dokumentacji__init__ :

Jako specjalne ograniczenie konstruktorów nie można zwracać żadnej wartości; spowoduje to wywołanie TypeError w czasie wykonywania.

Na dowód ten kod:

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

f = Foo()

Daje ten błąd:

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

17

Przykładowe wykorzystanie przedmiotowej sprawy może wyglądać następująco:

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)

Nie mam wystarczającej reputacji, więc nie mogę napisać komentarza, to szaleństwo! Chciałbym móc to opublikować jako komentarz do weroniki


3
Spowoduje to zgłoszenie błędu NameError: selfnie jest zdefiniowane w__new__(cls, Item)
Hart Simha

15

__init__Sposób, jak inne metody i funkcje zwróci None domyślnie w przypadku braku instrukcji return, więc można napisać, że jak jeden z nich:

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

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

Ale oczywiście dodanie return Nonenic nie kupuje.

Nie jestem pewien, czego szukasz, ale może Cię zainteresować jeden z nich:

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

f=Foo()
print f.value
print f

wydruki:

42
42

ohh ... czy mogę uzyskać dostęp do zmiennej składowej poza klasą? To powinno rozwiązać mój problem… dzięki
webminal.org

@lakshmipathi, Tak, zmienne instancji takie jak ta są publiczne.
quamrana

Jako oneliner, aby otrzymać coś wartościowego zwróconego po rozpoczęciu zajęć:f = Foo().value
JLT

@JLT Tak, zawsze to robisz, ale nadal nie oznacza to, że coś jest zwracane __init__.
quamrana


4

Możesz po prostu ustawić ją na zmienną klasy i odczytać ją z głównego programu:

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

2

Chciałem tylko dodać, możesz zwrócić klasy w __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

Powyższa metoda pomaga zaimplementować w teście określoną akcję na wyjątku


2
super().__init__powraca None, więc wracasz None, co jest w porządku, ale zbędne.
cz

2

init () nie zwraca żadnej wartości rozwiązanej idealnie

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)

wyjście: moja prędkość to 21 kmh


-2

Cóż, jeśli nie dbasz już o instancję obiektu ... możesz ją po prostu zastąpić!

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

print MuaHaHa('foo')=='foo'

2
To tylko zmienia to, co jest przypisane do nazwy selfw tym konstruktorze.
Ondrej K.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.