8

I tried to return a value in a class constructor (init):

class A:
  def __init__(self):
    return 1

but there is a run-time error saying init should return None. If this is the case, how to understand:

a=A()

where "a" is assigned as the class instance?

Hailiang Zhang
  • 17,604
  • 23
  • 71
  • 117

4 Answers4

28

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
Community
  • 1
  • 1
K Z
  • 29,661
  • 8
  • 73
  • 78
8

It works like this:

You do:

a = A()

A.__new__() is called, and returns an instance of the class A.

Equivalently:

a = A.__new__(A)

Python then calls

a.__init__()

Which, as the error message says, should not return a value.

Joel Cornett
  • 24,192
  • 9
  • 66
  • 88
  • 2
    I think it calls `object.__new__(A)` or `A.__new__(A)` with `A` as an argument, because `A.__new__()` without arguments raises *TypeError* saying *object.__new__(): not enough arguments* – Bleeding Fingers Oct 24 '12 at 06:27
  • @hus787: Yes you're right. I was simplifying things a bit. Thanks for the clarification. – Joel Cornett Oct 24 '12 at 06:40
4

As you know, everything in Python is an object, and classes are not an exception. Class A is an object with a method __call__(...) which is what allows you to write things like a = A(). Under the hood, A.__call__ will first create an object using a static method __new__ (which has a reasonable default implementation) and then calls the new object's __init__ with the proper constructor args.

bereal
  • 32,519
  • 6
  • 58
  • 104
2

The requirement that __init__ should return None is a concious implementation choice, that lets you rely on the fact that object of type class consistantly returns an object of type instance of class. It's the same in many other languages such as C++.

If implemented differently it would create useless confusion.

root
  • 76,608
  • 25
  • 108
  • 120