python 02 闭包

作者: 小鱼儿喜欢花无缺 | 来源:发表于2018-01-30 10:00 被阅读9次

    我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:
    def calc_sum(*args):
    ax = 0
    for n in args:
    ax = ax + n
    return ax
    但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!

    def lazy_sum(*args):
    def sum():
    ax = 0
    for n in args:
    ax = ax + n
    return ax
    return sum
    当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:
    在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

    def now():
    ... print '2013-12-25'
    ...
    f = now
    f()
    2013-12-25

    函数对象有一个name属性,可以拿到函数的名字:

    now.name
    'now'
    f.name
    ‘now'
    现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
    本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:
    def log(func):
    def wrapper(*args, *kw):
    print 'call %s():' % func.name
    return func(
    args, **kw)
    return wrapper

    偏函数

    阅读: 114841
    Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
    在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下:
    int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
    但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

    int('12345', base=8)
    5349
    int('12345', 16)
    74565

    在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。
    正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;
    类似xxx这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的authorname就是特殊变量,hello模块定义的文档注释也可以用特殊变量doc访问,我们自己的变量一般不要用这种变量名;
    类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;
    之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。
    private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:
    Python的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动。有些改动是不兼容旧版本的,也就是在当前版本运行正常的代码,到下一个版本运行就可能不正常了。
    从Python 2.7到Python 3.x就有不兼容的一些改动,比如2.x里的字符串用'xxx'表示str,Unicode字符串用u'xxx'表示unicode,而在3.x中,所有字符串都被视为unicode,因此,写u'xxx'和'xxx'是完全一致的,而在2.x中以'xxx'表示的str就必须写成b'xxx',以此表示“二进制字符串”。
    要直接把代码升级到3.x是比较冒进的,因为有大量的改动需要测试。相反,可以在2.7版本中先在一部分代码中测试一些3.x的特性,如果没有问题,再移植到3.x不迟。
    Python提供了future模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性。举例说明如下:

    为了适应Python 3.x的新的字符串的表示方法,在2.7版本的代码中,可以通过unicode_literals来使用Python 3.x的新的语法:
    似的情况还有除法运算。在Python 2.x中,对于除法有两种情况,如果是整数相除,结果仍是整数,余数会被扔掉,这种除法叫“地板除”:要做精确除法,必须把其中一个数变成浮点数:

    10.0 / 3
    3.3333333333333335
    而在Python 3.x中,所有的除法都是精确除法,地板除用//表示:

    相关文章

      网友评论

        本文标题:python 02 闭包

        本文链接:https://www.haomeiwen.com/subject/xdmqzxtx.html