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

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:

主站蜘蛛池模板: 饶平县| 奉节县| 抚松县| 健康| 六枝特区| 淮南市| 万荣县| 类乌齐县| 大悟县| 山阳县| 宜宾市| 井陉县| 墨竹工卡县| 林口县| 永城市| 吉木萨尔县| 炎陵县| 贵州省| 泰安市| 老河口市| 仁化县| 铅山县| 丹棱县| 太康县| 通榆县| 哈巴河县| 龙南县| 旺苍县| 永善县| 榆社县| 蓝田县| 铁力市| 新源县| 上思县| 龙口市| 湟源县| 连平县| 盘锦市| 永清县| 廉江市| 浪卡子县|