Як повернути значення з __init__ в Python?


102

У мене є клас із __init__функцією.

Як я можу повернути ціле значення з цієї функції, коли створюється об’єкт?

Я написав програму, де __init__проводиться синтаксичний аналіз командного рядка, і мені потрібно встановити якесь значення. Чи нормально встановити його в глобальній змінній та використовувати в інших функціях-членах? Якщо так, то як це зробити? Поки що я оголосив змінну за межами класу. і встановлення однієї функції не відображається в іншій функції ??


8
Якщо ви планували повернути код помилки, замість цього створіть виняток.
JoeG

1
Видаліть свій коментар та оновіть своє запитання. Вам належить питання. Це ваше питання. Будь ласка, виправте питання, щоб правильно показати, в чому ваша справжня проблема. Ви зловживаєте __init__; ми можемо допомогти вам, якщо ви опишете, чого ви насправді намагаєтесь досягти.
S.Lott

Відповіді:


117

__init__потрібно повернути None. Ви не можете (або, принаймні, не повинні) повернути щось інше.

Спробуйте зробити все, що хочете, щоб повернути змінну (або функцію) екземпляра.

>>> 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: Ви не можете повернути щось інше. Це не має ніякого сенсу.
S.Lott

72
init не повертає новостворений об'єкт - як видно з TypeError, потрібно повернути None, правда? Новостворений об'єкт повертається новим , init просто встановлює деякі його атрибути. Але так, як ви вже сказали, змінювати init або нове , щоб повернути щось інше, насправді не має сенсу.
weronika

Де newтут? Це newнеявно в Python? Я припустив, що семантика Python відрізняється від Java та інших мов, які використовують це слово.
cs95,

1
@Shiva AFAIK, під новою weronika мається на увазі __new __ (self), а не загальна семантична Java.
Harsh Daftary

2
Те, що цього неможливо зробити, не означає, що це не має сенсу. Наприклад, було б непогано передати дані з super().__init__похідного класу без необхідності передавати їх через змінну екземпляра.
cz

123

Чому ви хочете це зробити?

Якщо ви хочете повернути якийсь інший об'єкт при виклику класу, використовуйте __new__()метод:

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

obj = MyClass()
print obj

9
Так, нове - це правильний спосіб повернення чогось іншого, крім екземпляра класу, при використанні класу ... Мені просто цікаво - чи є якась причина, через яку ви могли б це зробити?
weronika

33
@weronika Одна ідея: у будь-якій ситуації, коли ви зазвичай використовуєте фабрику, але у вас є причина, щоб хотіти представити інтерфейс, який виглядає як звичайний екземпляр класу. Приклад: додаючи деякі нові необов’язкові параметри до класу __init__, ви розумієте, що насправді, щоб забезпечити потрібну вам гнучкість, вам потрібна фабрика класів, яка повертає екземпляри спеціалізованих підкласів. Але користувачі вашої бібліотеки вже використовують ваш існуючий API. Щоб зберегти його, ви перевизначаєте __new__повернення екземплярів ваших спеціалізованих підкласів.
Mark Amery

10
Якщо ви хочете побачити приклад того, що сказав Марк Амери, перевірте вихідний код datetimeмодуля зі стандартної бібліотеки. Він використовує __new__саме такий спосіб.
Зерін

Крім того, якщо хтось хоче зробити це, переконайтеся, що успадковує об'єкт, інакше це не буде працювати.
Mino_e

Я якось думаю про це, просто використовувати звичайну функцію має більше сенсу. Може бути трохи чужим для людей з виміру Java (функції не в класах? Єресь!), А його пітонічний. (Також ви можете призначати властивості функціям, як у funtionName.val = .., що є диким, але це працює)
Шейн,

37

З документації__init__ :

Як особливе обмеження для конструкторів, не можна повертати значення; це призведе до виникнення помилки TypeError під час виконання.

Як доказ, цей код:

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

f = Foo()

Видає цю помилку:

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

17

Зразок використання даного питання може бути таким:

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)

У мене недостатньо репутації, тому я не можу написати коментар, це божевілля! Я хотів би, щоб я міг опублікувати це як коментар до weronika


3
Це призведе до помилки NameError: selfне визначено в__new__(cls, Item)
Харт Сімха

15

__init__Метод, як і інші методи і функції повертає None за замовчуванням під час відсутності оператора повернення, так що ви можете написати це подобається або з них:

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

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

Але, звичайно, додавання значень return Noneнічого не купує.

Я не впевнений, що ви шукаєте, але вас може зацікавити одне з таких:

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

f=Foo()
print f.value
print f

відбитки:

42
42

ой..Чи можу я отримати доступ до змінної члена з класу? Тоді це має вирішити моє питання .... спасибі
webminal.org

@lakshmipathi, Так, такі змінні екземпляра є загальнодоступними.
quamrana

Як однопрофільний лайнер, щоб повернути щось цінне після початку заняття:f = Foo().value
JLT

@JLT Так, ви завжди це робите, але це все ще не означає, що з чогось повертається __init__.
quamrana


4

Ви можете просто встановити для нього змінну класу і прочитати з головної програми:

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

2

Просто хотів додати, ви можете повернути класи в __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

Наведений вище метод допомагає вам реалізувати певну дію щодо винятку у вашому тесті


2
super().__init__повертається None, отже, ви повертаєтесь None, що добре, але зайве.
cz

2

init () повернути жодне значення не вирішено ідеально

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)

вихід: моя швидкість 21 км / год


-2

Ну, якщо ви більше не дбаєте про екземпляр об’єкта ... ви можете просто замінити його!

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

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

2
Це просто змінює те, що присвоєно імені selfвсередині цього конструктора.
Ondrej K.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.