官术网_书友最值得收藏!

How objects are created

Objects other than built-in types or compiled module classes are created at runtime. Objects can be classes, instances, functions, and so on. We call an object's type to give us a new instance; or put in another way, we call a type class to give us an instance of that type.

Creation of function objects

Key 5: Create function on runtime.

Let's first take a look at how function objects can be created. This will broaden our view. This process is done by interpreter behind the scenes when it sees a def keyword. It compiles the code, which is shown as follows, and passes the code name arguments to the function class that returns an object:

>>> function_class = (lambda x:x).__class__
>>> function_class
<class 'function'>
>>> def foo():
...     print("hello world")
... 
>>> 
>>> def myprint(*args,**kwargs):
...     print("this is my print")
...     print(*args,**kwargs)
... 
>>> newfunc1 = function_class(foo.__code__, {'print':myprint})
>>> newfunc1()
this is my print
hello world
>>> newfunc2 = function_class(compile("print('asdf')","filename","single"),{'print':print})
>>> newfunc2()
asdf

Creation of instances

Key 6: Process flow for instance creation.

We call class to get a new instance. We saw from the making calls to objects section that when we call class, it calls its metaclass __call__ method to get a new instance. It is the responsibility of __call__ to return a new object that is properly initialized. It is able to call class's __new__, and __init__ because class is passed as first argument, and instance is created by this function itself:

>>> class Meta(type):
...     def __call__(*args):
...         print("meta call ",args)
...         return None
... 
>>> 
>>> class C(metaclass=Meta):
...     def __init__(*args):
...         print("C init not called",args)
... 
>>> c = C() #init will not get called 
meta call  (<class '__main__.C'>,)
>>> print(c)
None
>>>

To enable developer access to both functionalities, creating new object, and initializing new object, in class itself; __call__ calls the __new__ class to return a new object and __init__ to initialize it. The full flow can be visualized as shown in the following code:

>>> class Meta(type):
...     def __call__(*args):
...         print("meta call ,class object :",args)
...         class_object = args[0]
...         if '__new__' in class_object.__dict__:
...             new_method = getattr(class_object,'__new__',None)
...             instance = new_method(class_object)
...         else:
...             instance = object.__new__(class_object)
...         if '__init__' in class_object.__dict__:
...             init_method =  getattr(class_object,'__init__',None)
...             init_method(instance,*args[1:])
...         return instance
...
>>> class C(metaclass=Meta):
...     def __init__(instance_object, *args):
...         print("class init",args)
...     def __new__(*args):
...         print("class new",args)
...         return object.__new__(*args)
...
>>> class D(metaclass=Meta):
...     pass
...
>>> c=C(1,2)
meta call ,class object : (<class '__main__.C'>, 1, 2)
class new (<class '__main__.C'>,)
class init (1, 2)
>>> d = D(1,2)
meta call ,class object : (<class '__main__.D'>, 1, 2)
>>>

Take a look at the following diagram:

Creation of class objects

Key 7: Process flow for class creation.

There are three ways in which we can create classes. One is to simply define the class. The second one is to use the built-in __build_class__ function, and the third is to use the new_class method of type module. Method one uses two, method two uses method three internally. When interpreter sees a class keyword, it collects the name, bases, and metaclass that is defined for the class. It will call the __build_class__ built-in function with function (with the code object of the class), name of the class, base classes, metaclass that is defined, and so on:

__build_class__(func, name, *bases, metaclass=None, **kwds) -> class

This function returns the class. This will call the __prepare__ class method of metaclass to get a mapping data structure to use as a namespace. The class body will be evaluated, and local variables will be stored in this mapping data structure. Metaclass's type will be called with this namespace dictionary, bases, and class name. It will in turn call the __new__ and __init__ methods of metaclass. Metaclass can change attributes passed to its method:

>>> function_class = (lambda x:x).__class__
>>> M = __build_class__(function_class(
...                         compile("def __init__(self,):\n    print('adf')",
...                                 '<stdin>',
...                                 'exec'),
...                         {'print':print}
...                         ),
...                     'MyCls')
>>> m = M()
adf
>>> print(M,m)
<class '__main__.MyCls'> <__main__.MyCls object at 0x0088B430>
>>>

Take a look at the following diagram:

主站蜘蛛池模板: 衡南县| 囊谦县| 沙洋县| 丹寨县| 通城县| 陆丰市| 濉溪县| 房产| 轮台县| 乐业县| 郎溪县| 诏安县| 平利县| 通海县| 遂川县| 集安市| 河北区| 吉隆县| 鄄城县| 辽源市| 揭阳市| 郴州市| 辽中县| 胶南市| 塔城市| 大厂| 淮阳县| 黄龙县| 三河市| 永新县| 石台县| 许昌市| 江油市| 康保县| 出国| 汾阳市| 塔河县| 五河县| 北京市| 和平区| 徐水县|