题主举的这种例子平时很少用到,个人觉得真心不如a if a > b else b的写法
说个可能很多人不知道的吧
可能大多数人都知道,python中的def本质上是一个赋值语句,比如:
def f(a = b):
print a
这里的流程是,f的代码块在编译时被编译为一个code object放在字节码中,然后执行到这里的时候,根据这个code object构建一个function object,然后,将这个function object赋值给f这个变量,没错,是变量
为啥要封装而不是直接将code object赋值呢,因为function object还含有一些动态的信息,比如函数参数默认值(上面的b),或是否闭包的信息(若f是一个闭包函数)等
而今天要说的是class,这个本质上也是一个赋值语句,不过稍微复杂一点,运行到class这句的时候,会先将class下面的代码块“假装”当成一个函数来执行,但语法上和正常函数有一些区别:
1 无输入参数
2 不能显式return
3 代码块中def定义的函数并不作为这个“假”函数的闭包
可能还有一些其他区别
而执行上的区别在于,执行完成后,不销毁局部环境,而是将剩余的局部变量转换为class的属性,最后构建class object,赋值给class名字,没错,class名字也是变量
这样搞可以在class“定义”(实际上说“构造”更合适)的时候更灵活,比如:
class A:
i = raw_input()
if i == "a":
def f(self):
print "user select a"
else:
def f(self):
print "user select b"
del i
a = A()
a.f()
构造A的时候,执行下面这段代码,根据用户输入的是不是a,来决定定义(实际也是“构造”)方法f,注意这段代码有两个“局部变量”:i和f,最后del掉i,这样i就不会成为A的一个属性了(俗称“类静态变量”)
利用这个特性有时候可以偷懒省事,比如批量生成方法:
class Pkg:
for _fmt in "BHIQ":
exec ('unpack_%s= lambda self : '
'struct.unpack("!%s", self.bytes)[0]' %
(_fmt, _fmt))
del _fmt
__str__ = __repr__ = lambda self : `self.bytes`
(py的lambda和def等价,只是写法不同)
补充:
class块在最后并不是简单的将“残余”局部变量表转化为class的属性,而是对于函数等做一个method的转换,在执行代码块的def的时候,定义的是普通的函数,在最后会被转成class的unbounded method:
class A:
def f(self):
print "f"
print f
f(None)
print A.f
A().f()
可以看到,在f定义之后,本来是一个function,只是最后构造class的时候转成了一个method,而对于在中间用修饰器指定是staticmethod或classmethod的,则不会做转化或者做其它类型的转换,因此解释器的“构造class”过程是需要识别这俩修饰器所修饰过的函数的