• python closures and decorators


    Functions as objects and closures

    python中的函数是first-class objects,即它们可以作为参数传递到其他函数中,可以存储到数据结构中,也可以作为函数的返回值

    一个简单例子

    # foo.py
    def callf(func):
        return func()
    
    >>> import foo
    >>> def hello():
    ...     return 'hello'
    ...    
    >>> f = foo.callf(hello) # function as an arg
    >>> f
    'hello'
    

    对上面代码做一点修改:

    # foo.py
    x = 42
    def callf(func):
        return func()
    
    >>> import foo
    >>> x = 37
    >>> def hello():
    ...     return 'hello. x is %d' % x
    ...
    >>> foo.callf(hello)
    'hello. x is 37'
    

    这里我们调用foo.callf(),但是x的值却不是foo.py中定义的变量值,而是调用函数前上文的值。因此我们应该关注一个函数与周边变量的关系,也就有了closure闭包的概念

    closure: 当一个函数的语句和它们所执行的环境一起打包的时候,就成为了所谓的closure 我们可以查看一个函数的__globals__属性,如:

    >>> hello.__globals__
    {'__builtins__': <module '__builtin__' (built-in)>,
    'helloworld': <function helloworld at 0x7bb30>,
    'x': 37, '__name__': '__main__', '__doc__': None
    'foo': <module 'foo' from 'foo.py'>}
    

    可以看到hello里面已经绑定了x=37

    当使用嵌套函数时,闭包会给inner function捕获执行需要的环境,如

    import foo
    def bar():
        x = 13
        def helloworld():
            return "Hello World. x is %d" % x
        foo.callf(helloworld) # returns 'Hello World, x is 13'
    

    这里内部函数helloworld与x=13已经组成一个闭包

    闭包可以怎样使用?我们看一个延时赋值的例子:

    from urllib import urlopen
    def page(url):
        def get():
            return urlopen(url).read()
        return get
    
    >>> python = page("http://www.python.org")
    >>> python
    <function get at 0x95d5f0>
    >>> pydata = python() # fetch http://www.python.org
    >>> pydata.__closure__
    (<cell at 0x67f50: str object at 0x69230>,)
    >>> python._ _closure_ _[0].cell_contents
    'http://www.python.org'
    

    pydata对象在赋值的时候已经绑定了参数url的值,可以留到以后进行调用

    Decorators

    decorator装饰器的作用是在里面封装其他函数或者类,用@号来表示,eg:

    @trace
    def square(x):
        return x*x
    

    等同于

    def square(x):
        return x*x
    square = trace(square)
    

    这个例子中定义了一个square()函数,但马上将它作为参数传递到trace()中,并将返回的对象替代原来的square。装饰器顾名思义就是给原来函数增加一些装饰,比如我们这里trace函数可以做一些额外的事情,最后返回的对象可以是一个包含square的函数,即对我们的square函数做了“装饰”

    再看一个平常使用的例子:

    enable_tracing = True
    if enable_tracing:
        debug_log = open("debug.log","w")
    
    def trace(func):
        if enable_tracing:
            def callf(*args,**kwargs):
                debug_log.write("Calling %s: %s, %s
    " % (func._ _name_ _, args, kwargs))
                r = func(*args,**kwargs)
                debug_log.write("%s returned %s
    " % (func._ _name, r))
                return r
            return callf
        else:
            return func
    

    这个代码就可以追踪上面square函数的调用,如果enable_tracing,则用函数callf将func封装起来,在里面增加记录日志功能,并且callf最后还是返回func函数,也就是说如果允许追踪的时候我们就将原来的函数对象装饰成一个有追踪功能的callf函数对象返回,如果不允许追踪,就简单返回func本身,这是非常精妙的一种设计

  • 相关阅读:
    BizTalk 2010 Adapter for mySAP Business Suite 所支持版本
    BizTalk Adapter Pack for Oracle 实现Oracle 11g的CRUD
    BizTalk 360 功能介绍 CTP版
    以小见大——那些基于 protobuf 的五花八门的 RPC(5 完)
    BizTalk Server 2010 + SQL Server 2008 R2 通过集成创造更大价值 [ 上篇 ]
    double to float
    Office 2003 PIA
    matlab传参数
    Convert.ToInt16
    矩阵转换
  • 原文地址:https://www.cnblogs.com/jolin123/p/4438459.html
Copyright © 2020-2023  润新知