• 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本身,这是非常精妙的一种设计

  • 相关阅读:
    数据库 concat 与 ||
    mysql时间戳详解及运用
    mysql数据库事务的操作与理解
    数据分析实战——03丨Python基础语法:开始你的Python之旅
    数据分析实战——02丨学习数据挖掘的最佳路径是什么?
    数据分析实战——01丨数据分析全景图及修炼指南
    数据分析实战——开篇词 | 你为什么需要数据分析能力?
    从0开始学大数据学习笔记——37.如何对数据进行分类和预测?
    坚毅(GRIT)阅读笔记
    Make over monday – 每周动手实践的Tableau社区网站
  • 原文地址:https://www.cnblogs.com/jolin123/p/4438459.html
Copyright © 2020-2023  润新知