这是Python解释器简介的第二部分。第一部分请点击这里 。
完成编译之前的三个步骤都是在检查一个简单的函数对象。我们现在来谈谈更深层次的对象——函数的代码对象。
12345678 | >>> def foo(a):... x = 3... return x + a...>>> foo<function foo at 0x107ef7aa0>>>> foo.func_code<code object foo at 0x107eeccb0, file \” |
从上面的代码,你能发现所谓的代码对象就是函数对象的一个属性。(这个函数对象还有许多其它的属性,但它们大多都很无聊,因为 foo 函数实在是太简单了。)
代码对象是在Python编译器中生成的,并且在解释器中完成解释工作。它向解释器传递“开工了”的信息。我们再来看看代码对象的属性。
1234567 | >>> dir(foo.func_code)[\’__class__\’, \’__cmp__\’, \’__delattr__\’, \’__doc__\’, \’__eq__\’, \’__format__\’, \’__ge__\’,\’__getattribute__\’, \’__gt__\’, \’__hash__\’, \’__init__\’, \’__le__\’, \’__lt__\’, \’__ne__\’, \’__new__\’,\’__reduce__\’, \’__reduce_ex__\’, \’__repr__\’, \’__setattr__\’, \’__sizeof__\’, \’__str__\’,\’__subclasshook__\’, \’co_argcount\’, \’co_cellvars\’, \’co_code\’, \’co_consts\’, \’co_filename\’,\’co_firstlineno\’, \’co_flags\’, \’co_freevars\’, \’co_lnotab\’, \’co_name\’, \’co_names\’, \’co_nlocals\’,\’co_stacksize\’, \’co_varnames\’] |
这个属性列表虽然很长,但是其中大多数属性我们今天并不会涉及。我们只关注3个有趣的 foo 函数代码对象的属性。
123456 | >>> foo.func_code.co_varnames(\’a\’, \’x\’)>>> foo.func_code.co_consts(None, 3)>>> foo.func_code.co_argcount1 |
通过调用它们,我们能依次得到:变量名、函数中已知的常量和函数参数的数量。但是目前为止,我们还是不知道生成代码对象的指令到底是什么。事实上,这个指令叫做字节码。字节码也是代码对象的一个属性:
12 | >>> foo.func_code.co_code\’d\\x01\\x00}\\x01\\x00|\\x01\\x00|\\x00\\x00\\x17S\’ |
我们得到了许多待分解的信息。这里到底发生了什么?在下一部分,我们将深入研究字节码。