在 Python 中,import 语句会执行一个文件中的顶层代码,然后将各种函数定义体预先编译成字节码(Python 中字节码可以通过 dis 反编译模块看到)缓存起来,以后重新导入相同的模块就使用缓存,只做名称绑定。对于函数来说,Python 解释器会将 def 定义的函数体编译成字节码,并且将函数对象绑定到对应的全局名称上,但是这时候显然不会执行定义体,解释器只会在运行时调用函数的时候才会执行定义体。
但是对于类来说,导入的时候,解释器会执行 类的定义体,类中嵌套 的类定义体也会被执行。
下面通过代码来理解导入时和运行时的差别,建议先不要执行代码,先通过纸笔模拟一遍执行过程:
假设 evaltime.py 通过两种方式调用:
通过在 Python 交互式解释器导入运行:
通过命令行调用解释器解释脚本:
输出的结果分别是什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from evalsupport import deco_alphaprint ('<[1]> evaltime module start' )class ClassOne (): print ('<[2]> ClassOne body' ) def __init__ (self ): print ('<[3]> ClassOne.__init__' ) def __del__ (self ): print ('<[4]> ClassOne.__del__' ) def method_x (self ): print ('<[5]> ClassOne.method_x' ) class ClassTwo (object ): print ('<[6]> ClassTwo body' ) @deco_alpha class ClassThree (): print ('<[7]> ClassThree body' ) def method_y (self ): print ('<[8]> ClassThree.method_y' ) class ClassFour (ClassThree ): print ('<[9]> ClassFour body' ) def method_y (self ): print ('<[10]> ClassFour.method_y' ) if __name__ == '__main__' : print ('<[11]> ClassOne tests' , 30 * '.' ) one = ClassOne() one.method_x() print ('<[12]> ClassThree tests' , 30 * '.' ) three = ClassThree() three.method_y() print ('<[13]> ClassFour tests' , 30 * '.' ) four = ClassFour() four.method_y() print ('<[14]> evaltime module end' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 print ('<[100]> evalsupport module start' )def deco_alpha (cls ): print ('<[200]> deco_alpha' ) def inner_1 (self ): print ('<[300]> deco_alpha:inner_1' ) cls.method_y = inner_1 return cls class MetaAleph (type ): print ('<[400]> MetaAleph body' ) def __init__ (cls, name, bases, dic ): print ('<[500]> MetaAleph.__init__' ) def inner_2 (self ): print ('<[600]> MetaAleph.__init__:inner_2' ) cls.method_z = inner_2 print ('<[700]> evalsupport module end' )
在第一种情况下,输出的结果是:
1 2 3 4 5 6 7 8 9 10 <[100]> evalsupport module start <[400]> MetaAleph body <[700]> evalsupport module end <[1]> evaltime module start <[2]> ClassOne body <[6]> ClassTwo body <[7]> ClassThree body <[200]> deco_alpha <[9]> ClassFour body <[14]> evaltime module end
可以看到,解释器会先处理模块的依赖,并且执行每个类以及嵌套类的定义体,而装饰器函数在定义的时候没有被执行,当需要装饰类的时候,类的定义体首先被执行(这很合理,有了类才能被装饰),然后执行了装饰器函数。
由于是通过 import 导入,所以 if __name__ == '__main__' 块不会被执行。
对于第二种情况,输出的结果是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <[100]> evalsupport module start <[400]> MetaAleph body <[700]> evalsupport module end <[1]> evaltime module start <[2]> ClassOne body <[6]> ClassTwo body <[7]> ClassThree body <[200]> deco_alpha <[9]> ClassFour body <[11]> ClassOne tests .............................. <[3]> ClassOne.__init__ <[5]> ClassOne.method_x <[12]> ClassThree tests .............................. <[300]> deco_alpha:inner_1 <[13]> ClassFour tests .............................. <[10]> ClassFour.method_y <[14]> evaltime module end <[4]> ClassOne.__del__
前面几行和第一种情况是一致的,在 __main__ 块里,可以看到各个类的方法被执行了,而 ClassThree 的类方法被装饰器替换了,最后程序结束的时候,绑定在全局变量上的 ClassOne 实例被 GC 释放。