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