zoukankan      html  css  js  c++  java
  • 装饰器(傻逼看的懂版)

    装饰器的作用——

    在不改变函数原代码、调用方式的条件下,对函数增添额外的功能。

    装饰器的组成:

    高阶函数

    函数嵌套

    高阶函数:

    什么是函数?

    函数是对代码段的封装,函数是可执行的,执行函数就是

    运行函数中封装的代码段。

    通过内置方法,可以看到函数是可调用的!

    >>> def foo():

    ...     print('hello,world')

    ...

    >>> callable(foo)

    True

    函数到底是什么?

    ‘function’???

    >>> print(foo)

    <function foo at 0x0051C660>

    很明确,其实函数就是一个内存地址,函数名就是类似于内存地址的指针,对调用函数就是运行对应的内存地址!

    什么是变量:

    >>> name = 'alben'

    >>> mingzi = 'alben

     

     

    如图所示,变量命名就是把一个内存地址赋值到变量名(内存调用)

     

    Python的内存回收:

    当一个内存地址的所有调用都被del的时候,该内存被释放,否则将随着程序的运行永远占用。

     

    那么变量与内存有没有区别呢?

    答案是没有——

    >>> def foo():

    ...     print('Hello,World')

    ...

    >>> abc = foo

    >>> print(abc)

    <function foo at 0x0047C660>

    >>> print(foo)

    <function foo at 0x0047C660>

    >>> 

     

    高阶函数:

    把一个A函数的函数名作为实参传递给B函数,B函数就是高阶函数

     

    举例:

    import time

     

    def foo():

        time.sleep(3)

        l1 = [i * 2 for i in range(1000)]

        print(len(l1))

     

     

    def calc_time(func):

        start_time = time.time()

        func()

        end_time = time.time()

        print('The Func %s run time is %d' %(func,(end_time-start_time)))

     

    calc_time(foo)

     

    通过calc_time函数,可以计算函数foo的运行耗时。

     

    but:

    虽然函数我们实现了不改变函数foo的原代码情况下,增加了一个计算运行时间的功能,这是不可取的!

     

    函数嵌套:

    在一个函数的内部定义另一个函数,这个行为就是函数嵌套

    def foo():

        def inner():

            print("This is inner func")

    这个就是函数嵌套!

     

    通过函数嵌套+高阶函数实现对现有函数功能的增加!

    伪代码:

    import time

     

    def foo():

        time.sleep(3)

        l1 = [i * 2 for i in range(1000)]

        print(len(l1))

     

     

    def calc_time(func):

        def inner():

            start_time = time.time()

            func()

            end_time = time.time()

            print('the Func %s run time is %d ' %(func,(end_time-start_time)))

        return inner

    1、定义了一个函数calc_time,该函数是高阶函数,要求传入另一个函数的函数名

    2、函数calc_time内进行了函数套嵌,内嵌了另一个函数inner,

    3、函数calc_time的return值就是内嵌函数inner

    分析函数inner!

    1、记录和执行时间(start_time)

    2、执行了那个被当做实参传递进calc_time的函数

    3、记录了执行完成时间(end_time)

    4、计算了被传入函数的执行时间!

     

    内嵌函数inner是不能直接在解释器中运行的!会出现如下报错!

    Traceback (most recent call last):

      File "D:/实现自动化运维/高阶函数.py", line 21, in <module>

        inner()

    NameError: name 'inner' is not defined

     

    但是,函数calc_time的return就是内嵌函数的函数名!,所以我们只需要把calc_time的返回值赋值到一个变量,对这个变量执行以下就是执行内嵌函数inner了。

    def foo():

        time.sleep(3)

        l1 = [i * 2 for i in range(1000)]

        print(len(l1))

     

     

    def calc_time(func):

        def inner():

            start_time = time.time()

            func()

            end_time = time.time()

            print('the Func %s run time is %d ' %(func,(end_time-start_time)))

        return inner

     

     

    abc = calc_time(foo)

     

    abc()

     

    结果:

    1000

    the Func <function foo at 0x0049B660> run time is 3

     

    我们已经实现了不改变函数foo源代码的条件下增加了新的功能(计算时间),

    but!调用方式改变了!!

    有一个折中的方案:

    foo = calc_time(foo)

     

    foo()

    这样!简直prefect!

     

    装饰器的雏形就出来了,python解释器给我们提供了一个语法糖!“@”来实现这个功能!

    代码:

    #!/usr/bin/env python3

    #-*- coding:utf-8 -*-

     

    1. import time
    2. def calc_time(func):
    3.     def inner():
    4.         start_time = time.time()
    5.         func()
    6.         end_time = time.time()
    7.         print('the Func %s run time is %d ' %(func,(end_time-start_time)))
    8.     return inner
    9. @calc_time
    10. def foo():
    11.     time.sleep(3)
    12.     l1 = [i * 2 for i in range(1000)]
    13.     print(len(l1))
    14. foo()

     

    在pycharm的Debug中,可以清晰的看到代码的执行顺序如下:

    2-9-3-8-14-4-5-11-12-13-6-7

     

    这就是最简单的装饰器!

     

    下面,思考一个问题!就是如果被装饰的函数带有参数,那怎么办!

     

    有一个推算斐波那契数列的函数:

    def foo(a,b,x):

        if type(a) and type(b) == int:

            l1 = [a,b]

            while True:

                c = l1[-1] + l1[-2]

                l1.append(c)

                if c >x :break

        else:

            print("please give two int")

        print (l1)

     

    现在想要通过上面的装饰器calc_time来对这个函数进行装饰,试一下:

    @calc_time

    def foo(a,b,x):

        if type(a) and type(b) == int:

            l1 = [a,b]

            time.sleep(1)

            while True:

                c = l1[-1] + l1[-2]

                l1.append(c)

                if c > x : break

        else:

            print("please give two int")

        print(l1)

     

    foo(1,2,1000)

     

    运行结果:

    "C:UsersIE-LAB DadeAppDataLocalProgramsPythonPython36-32python.exe" D:/实现自动化运维/高阶函数.py

    Traceback (most recent call last):

      File "D:/实现自动化运维/高阶函数.py", line 26, in <module>

        foo(1,2,1000)

    TypeError: inner() takes 0 positional arguments but 3 were given

     

    Process finished with exit code 1

     

    不用我提示了把,只需要把装饰器内部套嵌的函数加上可变参数就可以了!

    def calc_time(func):

        def inner(*args,**kwargs):

            start_time = time.time()

            func(*args,**kwargs)

            end_time = time.time()

            print('the Func %s run time is %d ' % (func, (end_time - start_time)))

        return inner

     

    好了,我相信白痴看了这个都能理解装饰器了吧!

  • 相关阅读:
    ld: library not found for -lstdc++.6
    WebViewJavascriptBridge 进行js 与native通信。
    invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    OC 与 js 界面JSBridge交互
    react-native init的时候出现问题:npm WARN React-native@0.35.0 requires a peer of react@~15.3.1 but none was
    react-无状态组件
    2018年末--积极拥抱h5.转载 大前端时代来临,我们何去何从?
    /Users/macbook/Library/Developer/Xcode/DerivedData/MapViewDemo: No such file or direc
    EXCEL中如何获得工作表(sheet)的名称
    DELPHI中Showmodal与Show的区别
  • 原文地址:https://www.cnblogs.com/alben-cisco/p/7197891.html
Copyright © 2011-2022 走看看