第三章 函数也是对象 -- 高阶函数以及装饰器

第零章 学前准备
第一章 数据结构 – 基本数据类型
第一章 数据结构 – 字符串
第一章 数据结构 – 列表、元组和切片
第一章 数据结构 – 字典
第一章 数据结构 – 集合
第一章 – 数组、队列、枚举
第一章 数据结构 – 序列分类
第二章 控制流程
第三章 函数也是对象 – 函数定义以及参数
第三章 函数也是对象 – 高阶函数以及装饰器


第三章 函数也是对象 – 高阶函数以及装饰器

3.3 函数是一等对象

3.3.1 一等对象

Python 中,函数是一等对象。编程语言理论家把"一等对象"定义为满足下述条件的程序实体:

  1. 在运行时创建;
  2. 能赋值给变量或数据结构中的元素;
  3. 能作为参数传给函数;
  4. 能作为函数的返回结果;

Python 中,整数、字符串和字典都是一等对象。

def fibonacci(n):    # write Fibonacci series up to n
    """Print a Fibonacci series up to n."""
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result


# 1、函数也是对象,是function类的实例
print("fibonacci", fibonacci)
# 2、把fibonacci函数赋值给fib,然后通过变量名调用
fib = fibonacci
print("fib(10)", fib(10))
# 3、fibonacci作为参数传给map函数
print(list(map(fibonacci, range(5))))
# 4、作为函数返回值


def get_fibonacci_func():
    return fibonacci


print("get_fibonacci_func()(5)", get_fibonacci_func()(5))
fibonacci <function fibonacci at 0x10bd604c0>
fib(10) [0, 1, 1, 2, 3, 5, 8]
[[], [0], [0, 1, 1], [0, 1, 1, 2], [0, 1, 1, 2, 3]]
get_fibonacci_func()(5) [0, 1, 1, 2, 3]

3.3.2 高阶函数

接受函数为参数,或者把函数作为结果返回的函数是高阶函数( higher-order function

3.3.2.1 高阶函数应用:装饰器

装饰器实现动态地给一个对象增加一些额外的职责而不改变原来的代码。

比如,需要计算函数 decorated_hi 的运行时长,这时,你当然可以修改原来的函数代码加上计算时长的代码。如下所示,虽然这样可以实现,但是违反了程序开放封闭原则(软件实体(如类", “模块”, "函数等)应该对拓展开放,对修改封闭。即在增加一个功能时,应当尽可能地不去改动已有的代码,当修改一个模块时不应该影响到其他模块)。

import time


def decorated_hi(name):
    print(f"hi, {name}")
    time.sleep(3)


def decorated_hi_period(name):
    start_time = time.time()
    print(f"hi, {name}")
    time.sleep(3)
    print("consumed time:", time.time()-start_time)


decorated_hi_period("nfc")
hi, nfc
consumed time: 3.005100965499878
3.3.2.2 使用无参装饰器

如下,我们不需要修改原来 decorated_hi 函数的代码,,就可实现计算 decorated_hi 函数的运行时长。

如果我们需要增加需求,需要在函数运行前和运行后增加日志的打印,那么可以继续增加代码。

# 1、使用装饰器实现计算函数运行时长
def decorater_period(fun):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        ans = fun(*args, **kwargs)
        print(time.time()-start_time)
        return ans
    return wrapper


decorater_period(decorated_hi)("nfc")

# 2、增加日志打印需求
def decorater_logging(fun):
    def wrapper(*args, **kwargs):
        print("函数开始运行...")
        ans = fun(*args, **kwargs)
        print("函数运行结束...")
        return ans
    return wrapper


print('-'*30)
decorater_logging(decorater_period(decorated_hi))("nfc")
hi, nfc
3.0050690174102783
------------------------------
函数开始运行...
hi, nfc
3.002124786376953
函数运行结束...
3.3.2.3 无参装饰器语法糖
@decorater_logging
@decorater_period
def decorated_hi(name):
    print(f"hi, {name}")
    time.sleep(3)


decorated_hi("nfc")
函数开始运行...
hi, nfc
3.0020031929016113
函数运行结束...
3.3.2.4 使用有参装饰器

上面只是一个简单的日志记录,并不能给定日志的级别,为实现有日志级别的日志记录,需要使用到有参数的装饰器,如下所示。

from datetime import datetime


def logger(level="Info"):
    def outer_wrapper(func):
        def inner_wrapper(*args, **kwargs):
            print(f"[{level}]\t开始执行\t{datetime.now()}")
            func(*args, **kwargs)
            print(f"[{level}]\t执行完毕\t{datetime.now()}")
        return inner_wrapper
    return outer_wrapper


def function_hi(name, age):
    print(f"hi {name} ,age:{age}")


logger("debug")(function_hi)("nfc", 4)
[debug]    开始执行    2022-11-27 23:01:16.212278
hi nfc ,age:4
[debug]    执行完毕    2022-11-27 23:01:16.212313
3.3.2.5 使用有参装饰器语法糖
@logger("error")
def function_hi(name, age):
    print(f"hi {name} ,age:{age}")


function_hi("nwq", "18")
[error]    开始执行    2022-11-27 23:02:38.671494
hi nwq ,age:18
[error]    执行完毕    2022-11-27 23:02:38.671523
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值