Как вернуть значение из __init__ в Python?

103

У меня есть класс с __init__функцией.

Как я могу вернуть целочисленное значение из этой функции при создании объекта?

Я написал программу, в которой __init__выполняется синтаксический анализ командной строки, и мне нужно установить какое-то значение. Можно ли установить его в глобальной переменной и использовать в других функциях-членах? Если да, то как это сделать? Пока что я объявил переменную вне класса. и установка одной функции не отражается на другой функции ??

webminal.org
источник
8
Если вы рассматривали возможность возврата кода ошибки, вместо этого вызовите исключение.
JoeG
1
Пожалуйста, удалите свой комментарий и обновите свой вопрос. Вопрос принадлежит вам. Это твой вопрос. Пожалуйста, исправьте вопрос, чтобы правильно показать, в чем ваша настоящая проблема. Вы неправильно используете __init__; мы можем помочь вам, если вы опишете, чего вы действительно пытаетесь достичь.
S.Lott

Ответы:

119

__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, верно? Вновь созданный объект возвращается командой new , init просто устанавливает некоторые из его атрибутов. Но да, как вы сказали, изменение init или new , чтобы вернуть что-то еще, действительно не имеет смысла.
weronika
Где newздесь? Является ли newзаложенная в Python? Я предположил, что семантика Python отличается от Java и других языков, в которых используется это слово.
cs95
1
@Shiva AFAIK, под новой вероникой подразумевается __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
Да, new - это правильный способ вернуть что-то кроме экземпляра класса при использовании класса ... Мне просто интересно - есть ли какая-то причина, по которой вы действительно могли бы захотеть это сделать?
weronika
33
@weronika Одна идея: в любой ситуации, когда вы обычно используете фабрику, но у вас есть какая-то причина, чтобы представить интерфейс, который выглядит как создание обычного класса. Пример: добавляя новые необязательные параметры в свой класс __init__, вы понимаете, что на самом деле для обеспечения желаемой гибкости вам нужна фабрика классов, которая возвращает экземпляры специализированных подклассов. Но пользователи вашей библиотеки уже используют ваш существующий API. Чтобы сохранить его, вы переопределяете, __new__чтобы возвращать экземпляры ваших специализированных подклассов.
Марк Эмери
10
Если вы хотите увидеть пример того, что сказал Марк Эмери, просмотрите исходный код datetimeмодуля из стандартной библиотеки. Он использует __new__именно так.
Zearin
Также, если кто-то хочет это сделать, убедитесь, что он наследовал от объекта, иначе это не сработает.
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)

У меня недостаточно репутации, поэтому я не могу написать комментарий, это безумие! Хотел бы я опубликовать это как комментарий к Веронике

PMN
источник
3
Это вызовет ошибку NameError: selfне определено в__new__(cls, Item)
Hart Simha
15

Этот __init__метод, как и другие методы и функции, по умолчанию возвращает None в отсутствие оператора return, поэтому вы можете написать его, как любой из этих:

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
Quamrana
источник
ох .. Могу ли я получить доступ к переменной-члену вне класса? Тогда это должно решить мою проблему .... спасибо
webminal.org
@lakshmipathi, Да, такие переменные экземпляра общедоступны.
quamrana
Чтобы получить что-то ценное, возвращенное после начала класса:f = Foo().value
JLT
@JLT Да, вы всегда так делаете, но это еще не означает, что что-то возвращается __init__.
quamrana
7

__init__ничего не возвращает и должен всегда возвращаться None.

Gruszczy
источник
4

Вы можете просто установить его в переменную класса и прочитать его из основной программы:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode
PythonPro
источник
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внутри этого конструктора.
Ондрей К.