How to Return a Value from _Init_ in Python

How to return a value from __init__ in Python?

__init__ is required to return None. You cannot (or at least shouldn't) return something else.

Try making whatever you want to return an instance variable (or function).

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

What does __init__ method return in python

__init__() returns None. It is __new__() that returns the new instance.

Why is that __init__ function of python doesn't have a return statement even though its a function

__init__() is not a normal function. It is a special method Python uses to customize an instance of a class. It is part of Python's data model:

Called after the instance has been created (by __new__()), but before it is returned to the caller[...].

As you can see from above, when you create a new instance of a class, Python first calls __new_() - which is also a special method - to create a new instance of the class. Then __init__() is called to customize the new instance.

It wouldn't make sense to return anything from __init__(), since the class instance is already created. In fact, Python goes as far as raising an error to prevent this:

>>> class A:
... def __init__(self):
... return 'foo'
...
>>> A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>>

If you want to know what exactly is going on behind the scenes, @eryksun provides a nice explanation:

To completely explain this story, you have to step back to the metaclass __call__ method. In particular the default type.__call__ in CPython calls __new__ and __init__ via their C slot functions, and it's slot_tp_init (defined in Objects/typeobject.c) that enforces the return value to be None. If you use a custom metaclass that overrides type.__call__, it can manually call the __new__ and __init__ methods of the class with no restriction on what __init__ can return -- as silly as that would be.

How can I change what __init__ returns?

The __init__ method doesn't actually return the new instance; when you construct an object by writing Foo() you are not calling __init__ directly, you are calling __new__, and the __new__ method initialises the instance by calling __init__. So you can change what Foo() returns by overriding __new__:

class Foo:
def __new__(cls):
obj = super().__new__(cls)
obj.__init__()
return obj.some_method()
def __init__(self):
self.x = 5
def some_method(self):
return self.x * 2

print(Foo()) # 10

Alternatively you can use a class decorator to replace Foo with a function which creates the instance, calls the method and returns the result:

from functools import wraps

def autocall(cls):
@wraps(cls)
def wrapped():
obj = cls()
return obj.some_method()
return wrapped

@autocall
class Foo:
def __init__(self):
self.x = 5
def some_method(self):
return self.x * 2

print(Foo()) # 10

That said, it's almost always better to just write a helper function, so that the class Foo can still be used in the normal way for other purposes (e.g. testing):

class Foo:
def __init__(self):
self.x = 5
def some_method(self):
return self.x * 2

def foo_helper():
obj = Foo()
return obj.some_method()

print(foo_helper()) # 10

Bad form to return None in __init__ in python

For any function, not only __init__, using plain return is equivalent to returning None, and if you don't use return in a function, None is implicitly returned anyway.

Therefor, it is perfectly fine to use return inside __init__.

(The exception to the rule above is generator functions, inside which you may only use return and not return None, so these are not equivalent inside generator functions).

Returning in the middle of __init__ will simply cut off object's initialization. It will not prevent the object from being created, nor interrupt program's flow in any way.

Will python class __init__ method implicitly return None?

Strictly speaking, it's not A.__new__() that's creating the the instance a.

When you define class A(object): (or class A: as well if you are using Python3, class A: is the old-style class that has been deprecated), it is __new__ from the inheritedobject.__new__() that is being called to create the instance a.

When a = A() is executed, what happens is:

  1. A() is a shorthand for A.__call__
  2. object.__new__(cls, *args, **kwargs) where cls=A, is what actually happens under hood to create instance a. It allocates the memory for the new object, and should then return a new object (the instance).
  3. if and only if the newly created object is returned does __init__(self) then get called with the newly created object passed to it to "initilize" the object.

Consider the following demo:

  • when we override __new__ and no longer returns an object, __init__ will
    not get called:

    class A(object):

    def __new__(cls, *args, **kwargs):
    print cls, args, kwargs

    def __init__(self):
    self.x = 'init!'
    print self.x

    In : a = A()
    <class '__main__.A'> () {}

    # note that "init!" has not appeared here because __new__ didn't return an
    # new instance
  • now, return a new instance by using object.__new__, and you will see that
    after __new__, __init__ would be called as well:

    class A(object):

    def __new__(cls, *args, **kwargs):
    print cls, args, kwargs
    return object.__new__(cls, args, kwargs)

    def __init__(self):
    self.x = 'init!'
    print self.x

    In : a = A()
    <class '__main__.A'> () {}
    init!

Here is another demo to display the difference, note that instance a can be created without calling __init__():

class A(object):
def __init__(self):
self.x = "init!"
print self.x

In : a = object.__new__(A)

In : a
Out: <__main__.A at 0x103466450>

In : a.__dict__
Out: {}

In : aa = A()
init!

In : aa
Out: <__main__.A at 0x1033ddf50>

In : aa.__dict__
Out: {'x': 'init!'}

Now for the inquisitive (and also to refresh my own memory =]):

Roughly speaking, there are two main ways to create new objects in Python:

Create new object (type / class) by subclassing:

class statements tells Python to create a new type / class object(by
subclassing an existing type/class such as object):

class Hello(object):
pass
>>> Hello.__class__
<type 'type'>

In fact all class/type object have type type. The type of type
(type(type)) is still type.

You can subclass a type / class object.

Create new object (instance) by instantiating:

You can also create a new object by instatiating an existing type object.
This is done via the using the __call__ operator (shorthand by ()):

>>> h = hello()
>>> type(h)
<class '__main__.Hello'>
>>> type(int('1'))
<type 'int'>

You cannot subclass an instance object.

(note that you can also create a new instance object by some other means such
as using the list operator [1,2,3], in this case it creates an list instance)

You can check an object's type by type(my_obj) or my_object.__class__.


Now you know how an instance object is created, but what really creates the type / class object (that allows to create instance objects)?

In fact, these objects are created by instantiation as well, albeit it is a
slightly different kind of instantiation from what was mentioned earlier.

Aside from class statement, you can also use
type(cls_name, parent_class_tuple, attr_dict) to create a new class.
For eg:

type('Hello', (object,), {})

will create the Hello class same as the one shown earlier.

What is type? Enter metaclass.

type is a metaclass, which is the class of class, i.e., classes are
instances of metaclasses. The __class__ of type is still type.

So here is a graph that shows the relationships between metaclass, class,
instance:

            instantiate             instantiate
metaclass --------------> class ----------------> instance
type.__new__() object.__new__()

When metaclass type is called to create a new class, the similar flow goes:

  1. type.__call__() is excuted
  2. type.__new__() allocates memory and then returns new a class (a metaclass instace), and then calls type.__init__().
  3. type.__init__() initalizes the newly created class that was passed from step 2.

You can even create a new metaclass by subclassing type:

class MyMeta(type):
def __new__(meta, name, bases, dct):
# do something
return super(MyMeta, meta).__new__(meta, name, bases, dct)
def __init__(cls, name, bases, dct):
# do something
super(MyMeta, cls).__init__(name, bases, dct)

then you can create a new class from this MyMeta metaclass just like you do
with type:

MyClass = MyMeta('MyClass', (object, ), {'x': 1})

Or, use __metaclass__ when defining your class, which has exactly the
same effect as what was shown above:

class MyClass(object):
__metaclass__ = MyMeta
x = 1


Related Topics



Leave a reply



Submit