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?
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:
A()
is a shorthand for A.__call__
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).__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!'}
Roughly speaking, there are two main ways to create new objects in Python:
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.
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__
.
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:
type.__call__()
is excutedtype.__new__()
allocates memory and then returns new a class (a metaclass instace), and then calls type.__init__()
.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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With