python函数式编程

1、函数作为参数(回调函数)

函数也是一种数据:function类型的数据。

回调函数:

                作为参数的函数,将回调函数作为其他函数参数。

定义一个函数,该函数接收一个函数作为参数,并在函数执行完毕后执行回调函数。

def f1(a,b):  # 定义一个函数,作为回调函数
  return a+b

def f2(a,b):  # 定义一个函数,作为被调用函数
   return a-b


def fn(x,y,fun):   #fun必须是函数
    print(fun(x,y))

# 调用fn函数,并传入f2函数和f1函数作为参数
fn(10,5,f1)
fn(10,5,f2)

f1 和 f2 被定义为回调函数,而 fn 是一个被调用函数。回调函数是指作为参数传递给另一个函数的函数,这个被调用的函数在适当的时候会调用这个回调函数。

具体来说:

  • f1(a, b) 是一个回调函数,它接收两个参数 a 和 b,并返回它们的和。
  • f2(a, b) 也是一个回调函数,它接收两个参数 a 和 b,并返回它们的差。
  • fn(x, y, fun) 是一个被调用函数,它接收两个数值参数 x 和 y,以及一个函数参数 fun。在函数体内,fun(x, y) 被调用,即回调函数在 fn 函数内部被调用。

在代码的最后两行中,fn(10,5,f1) 和 fn(10,5,f2) 分别将 f1 和 f2 作为回调函数传递给 fn 函数,并执行相应的操作:

  • fn(10,5,f1) 会调用 f1(10,5),输出结果为 15
  • fn(10,5,f2) 会调用 f2(10,5),输出结果为 5

2、函数作为返回值(闭包)

闭包是指引用了此函数外部嵌套函数的变量的函数,并把该函数作为返回值,是一种思想。

        函数内部有函数,内部的那个函数就是闭包。

        使用闭包(函数)来把环境的值单独保存起来,让变量不要相互污染。

闭包必须满足以下三个条件:

  • 必须有一个内嵌函数

  • 内嵌函数必须引用外部函数中变量

  • 外部函数返回值必须是内嵌函数

# 闭包的定义和使用

def outer(x):
    def inner(y): 
        return x + y
    return inner # 这里返回的是 inner 函数的引用,而不是 inner 函数的执行结果

# 调用
f = outer(10) # 这里返回的是 inner 函数的引用
print(f(5)) # 15

3、装饰器

装饰器是Python对闭包思想的具体语法实现,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。

  1. 日志记录:可以使用装饰器来记录函数的输入、输出或执行时间。

  2. 认证和授权:装饰器可以用于检查用户是否有权限执行特定操作。

  3. 缓存:装饰器可以缓存函数的结果,从而提高执行效率。

  4. 参数验证:可以使用装饰器来验证函数的输入参数是否符合预期。

  5. 代码注入:装饰器可以在函数的执行前后注入额外的代码。

3.1基本装饰器

通过一下过程来理解装饰器

计算x内的平方和

#计算x内的平方和
def f(x):
  s = 0
  for i in range(x):
    s += i**2
  return s

print(f(10000000))

 我想知道f()函数的运行时间。

#我想知道f()函数的运行时间,可以用time模块来测试。
import time
def f(x):
  t = time.time()
  s = 0
  for i in range(x):
    s += i**2
  t1 = time.time()
  print("f()函数运行时间:", t1-t)
  return s

print(f(50000000))

如果我还有很多函数(几千几万个函数)需要测试运行时间,每个函数都要写一遍time.time()和print()语句,那岂不是很麻烦?

将每个函数相同的功能都放在一个函数(装饰器函数)里,要使用时就对目标函数装饰。

所以,我们可以用装饰器来自动测试运行时间。

import time

# 装饰器函数
def fun(func):
  def fn(*a,**b):  # *a、**b 不管有多少参数,都接受
    t = time.time()
    result = func(*a,**b)  # 调用原函数
    t1 = time.time()
    print(f"{func.__name__}函数运行时间:{t1-t}")
    return result  # 返回原函数的返回值
  return fn  # 返回装饰器函数

#目标函数
def f(x):
  s = 0
  for i in range(x):
    s += i**2
  return s


# 现在只要把f()函数转入fun(),f()函数没有计算时间的语句也会自动计算运行时间。
f = fun(f)
print(f(50000000))

可以不用写f = fun(f)也能实现同样的效果。python提供了一个语法糖@fun,可以直接把fun()函数应用到f()函数上。

#在目标函数前面加上@+装饰器函数名,如:@fun,相当于f = fun(f)。

import time

# 装饰器函数
def fun(func):
  def fn(*a,**b):  # *a、**b 不管有多少参数,都接受
    t = time.time()
    result = func(*a,**b)  # 调用目标函数
    t1 = time.time()
    print(f"{func.__name__}函数运行时间:{t1-t}")
    return result  # 返回原函数的返回值
  return fn  # 返回装饰器函数

#目标函数f()
@fun
def f(x):
  s = 0
  for i in range(x):
    s += i**2
  return s

print(f(50000000))  #这里的f()函数已经不是原来的目标函数f()了,而是经过fun()函数装饰过的函数,只是函数名没有变化。

#现在,我们可以用@fun装饰器来自动测试需要测试的函数的运行时间,而不需要在每个函数中都写一遍time.time()和print()语句。
#不管有多少函数,都可以用同样的方式来测试运行时间。

 

3.2 带参装饰器

def repeat(num):
    print('...函数名...()...函数执行...')

    def decorator(func):
        print('...装饰器...()...装饰器执行...')

        def wrapper(*args, **kwargs):
            for _ in range(num):
                func(*args, **kwargs)

        return wrapper

    return decorator


@repeat(3)  # 应用装饰器,重复执行下面的函数3次
def greet(name):
    print(f"Hello, {name}!")


greet("Alice")  # 调用被装饰的函数
  • repeat 是一个接受参数的装饰器工厂函数,它返回一个装饰器。

  • decorator 是真正的装饰器,它接受一个函数 func 作为参数。

  • wrapper 函数重复执行被装饰的函数 num 次。

3.3 装饰器链

def uppercase(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()

    return wrapper


def exclamation(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + "!"

    return wrapper


@exclamation
@uppercase
def say_hello(name):
    return f"Hello, {name}"


greeting = say_hello("Bob")
print(greeting)  # 输出 "HELLO, BOB!"

  • uppercase 和 exclamation 是两个装饰器,分别将文本转换为大写和添加感叹号。

  • 使用 @exclamation@uppercase 创建装饰器链,它们按照声明的顺序依次应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值