zoukankan      html  css  js  c++  java
  • 关于Python的装饰器

    函数装饰器:

    <![if !supportLists]>一.   <![endif]>什么是装饰器:

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

    这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

    <![if !supportLists]>二.   <![endif]>为什么要用装饰器:

    软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的,具体可以参考:

    百度百科: https://baike.baidu.com/item/开放封闭原则/6028662?fr=aladdin

    维基百科: https://zh.wikipedia.org/wiki/开闭原则

    <![if !supportLists]>三.   <![endif]>要知道的三个概念:

    <![if !supportLists]>1.       <![endif]>函数的作用域

    <![if !supportLists]>a.       <![endif]>什么叫作用域:

    在电脑程序设计中,作用域(scope,或译作有效范围)是名字(name)与实体(entity)的绑定(binding)保持有效的那部分计算机程序。不同的编程语言可能有不同的作用域和名字解析。而同一语言内也可能存在多种作用域,随实体的类型变化而不同。作用域类别影响变量的绑定方式,根据语言使用静态作用域还是动态作用域变量的取值可能会有不同的结果。

    出自维基百科: https://zh.wikipedia.org/wiki/作用域

    <![if !supportLists]>b.       <![endif]>Python中怎么产生不同的作用域

    Python中,只有模块module),class)以及函数deflambda)才会引入新的作用域,其它的代码块(如iftryfor等)是不会引入新的作用域的.

    来自: http://www.cnblogs.com/yuanchenqi/articles/5828233.html

    <![if !supportLists]>c.       <![endif]>Python中有几种作用域:

    :L-R-G-B

    local: 局部作用域,即函数中定义的变量

    enclosing: 嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的

    global:全局变量,就是模块级别定义的变量

    builtins: 内置作用域(python内置)

    LEGB含义解释:

    L-Local(function);函数内的名字空间

    E-Enclosing function locals;外部嵌套函数的名字空间(例如closure)

    G-Global(module);函数定义所在模块(文件)的名字空间

    B-Builtin(Python)Python内置模块的名字空间

    LEGB规定了查找一个名称的顺序为:local-->enclosing function locals-->global-->builtin

     

    作者:_Zhao_

    链接:http://www.jianshu.com/p/3b72ba5a209c

    來源:简书

     

    下面内容来自Python的官方文档:

    4.2.2. Resolution of names

    A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name.

    When a name is used in a code block, it is resolved using the nearest enclosing scope. The set of all such scopes visible to a code block is called the block’s environment.

    When a name is not found at all, a NameError exception is raised. If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, an UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError.

    If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

    If the global statement occurs within a block, all uses of the name specified in the statement refer to the binding of that name in the top-level namespace. Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the module builtins. The global namespace is searched first. If the name is not found there, the builtins namespace is searched. The global statement must precede all uses of the name.

    The global statement has the same scope as a name binding operation in the same block. If the nearest enclosing scope for a free variable contains a global statement, the free variable is treated as a global.

    The nonlocal statement causes corresponding names to refer to previously bound variables in the nearest enclosing function scope. SyntaxError is raised at compile time if the given name does not exist in any enclosing function scope.

    The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called __main__.

    Class definition blocks and arguments to exec() and eval() are special in the context of name resolution. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace. The namespace of the class definition becomes the attribute dictionary of the class. The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods – this includes comprehensions and generator expressions since they are implemented using a function scope. This means that the following will fail:

    class A:

        a = 42

        b = list(a + i for i in range(10))

     

    <![if !supportLists]>2.       <![endif]>一切皆对象,即一个函数可以作为一个参数传入到另外一个函数中

     

    <![if !supportLists]>3.       <![endif]>闭包:

     

    <![if !supportLists]>a.       <![endif]>闭包的定义:

    在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

    出自维基百科: https://zh.wikipedia.org/wiki/闭包_(计算机科学)

    <![if !supportLists]>b.       <![endif]>简单的理解方式:

    闭包=函数块+定义函数时的环境

    <![if !supportLists]>c.       <![endif]>举个栗子:

    In [15]: def outer():

        ...:     name ="Tom"

        ...:     def inner():

        ...:         return name

        ...:     return inner

        ...:

     

    In [16]: ret  = outer()

     

    In [17]: ret

    Out[17]: <function __main__.outer.<locals>.inner>

     

    In [18]: ret()

    Out[18]: 'Tom'

    <![if !vml]>

    [endif]>

                       如图:out()内部空间的name在外部被使用了.,这就是个闭包:

                       还有疑问可以移步到: http://www.cnblogs.com/yuanchenqi/articles/5830025.html

    <![if !supportLists]>四.   <![endif]>函数装饰器

    一开始介绍了什么是装饰器,以及为什么要用装饰器,那么怎么去实现一个装饰器,以及装饰器是怎么工作的:

    例如.现在有一个函数,现在需要在这个函数上新加一些功能:

    <![if !supportMisalignedColumns]><![endif]>

    import time

    def foo():

        print("hello world")

        time.sleep(2)

    # 现在要输出foo()实际的执行时间可以这样

    def show_time():

        start=time.time()

        foo()

        end=time.time()

        print(end-start)

     

    # 执行变成了 show_time()

    # show_time()

    def show_time1(f):

        """将函数作为参数传入"""

        start = time.time()

        f()

        end = time.time()

        print(end - start)

    show_time1(foo)

    def show_time(f):

        def inner():

            start = time.time()

            f()

            end=time.time()

            print(end-start)

        return inner

    foo = show_time(foo)

    foo()

    <![if !vml]>

    <![endif]>

    # python提供了一种方法

    @show_time    #相当于执行了foo = show_time(foo)

    def foo():

        print("hello world")

        time.sleep(2)

     

    foo()

    <![if !vml]>

    <![endif]>

    执行foo()实际上相当于执行的是inner()

     

    这时inner()就是一个闭包

    foo存在参数的时候如何处理:注意看上图,图中foo实际上即使inner

    def show_time(f):

        def inner(*args,**kwargs):

            start = time.time()

            f(*args,**kwargs)

            end=time.time()

            print(end-start)

        return inner

     

    @show_time   

    def foo(a,b):

        """foo有参数的情况"""

        print(a*b)

        time.sleep(2)

     

    foo("hello",5)

    <![if !vml]>

    <![endif]>

     

    突然有个想法,装饰器上还可不可以再加装饰器:

    答案是可以滴:

    import time

     

    def show_time(f):

        def inner(*args,**kwargs):

            start = time.time()

            f(*args,**kwargs)

            end=time.time()

            print(end-start)

        return inner

     

    def test(f):

        def inner():

            print("test")

            f()

        return inner

    @test

    @show_time    #相当于执行了foo = show_time(foo)

    def foo():

        """foo有参数的情况"""

        print("foo")

        time.sleep(2)

    foo()

    Now 给装饰器加一个参数.

     

     

     

    import time

    def outer(flag):

        def show_time(f):

            def inner(*args,**kwargs):

                start = time.time()

                f(*args,**kwargs)

                end=time.time()

                print(end - start)

                if flag:

                    print("flag为真")

                else:

                    print("flag为假")

            return inner

        return show_time

     

     

    @outer(" ")   

    def foo():

        """foo有参数的情况"""

        print("foo")

        time.sleep(2)

    foo()

    <![if !vml]>

    <![endif]>

     

         

     

    <![if !supportLists]>五.   <![endif]> 

  • 相关阅读:
    过采样算法之SMOTE
    4.4 spring-自定义标签的解析
    4.3 spring-嵌入式beans标签的解析
    4.2 spring-import 标签的解析;
    4.1 spring-alias 标签的解析;
    4.0 spring-注册解析的Bean
    3.9 spring-自定义标签解析
    3.8 spring
    3.8 spring-qualifier 子元素的使用与解析
    3.7 spring-property 子元素的使用与解析
  • 原文地址:https://www.cnblogs.com/twotigers/p/7716374.html
Copyright © 2011-2022 走看看