函数 —— 匿名函数 与 装饰器

Python 学习笔记


一、匿名函数

  • 匿名函数一般都是作为参数使用,其他地方一般不用.

1.1、filter( function, iterable )

  • 可以从序列当中过滤出符合条件的元素,保存到一个新的序列中
  • 参数一:传递函数,参数二:需要过滤的序列
  • 返回值 过滤后新的序列
list1 = [1,2,3,4,5,6,7,8,9,10]

def fn2(i):									# 定义一个函数, 用来检测一个任意数的偶数
    return i % 2 == 0

def fn3(i):									# 定义一个函数, 用来检测指定数字是否大于 5
    return i > 5

def fn4(i):									# 定义一个函数, 用来检测指定数字是否为 3 的倍数
    return i % 3 == 0

print(filter(fn2,list1))
print(list(filter(fn2,list1)))

以上代码存在一个问题:
        以上函数都十分简单,若是在项目中,有可能我们只是用一次,然后为此其定义一个函数,就显得有点多余。
        那么有没有什么方法可以更好的解决这样的问题 ?当然有,就是我们接下来讲到 lambda 函数


1.2、lambda 表达式

  • lambda 函数表达式专门用来创建一些 简单的函数 ,它是函数创建的另外一种方式,用完就丢弃(从内存中消失)
  • 匿名函数一般都是作为参数传递,其他情况不用。

语法:lambda 参数列表[a,b,c...] : 返回值

def fn(a,b):
    return a + b
print(fn(30,20))

# 相当于
fn2 = lambda a,b:a+b
print(fn2(30,20))

# 相当于
print((lambda a,b : a+b)(30,20))

1.3、结合 lambda 和 filter

  • 两个函数结合使用,就能很好的解决上面的问题
list1 = [1,2,3,4,5,6,7,8,9,10]

# fn2() 相当于  lambda i:i % 2 == 0
# fn3() 相当于  lambda i:i > 5
# fn4() 相当于  lambda i:i % 3 == 0

print(list(filter(lambda i:i % 2 == 0, list1)))
print(list(filter(lambda i:i > 5, list1)))
print(list(filter(lambda i:i % 3 == 0, list1)))

1.4、map()

  • map()函数可以对可迭代对象中所有的元素做指定操作,然后将其添加到一个新的对象返回
list1 = [1,2,3,4,5,6,7,8,9,10]

r = map(lambda i:i+1, list1)
print(list(r))

1.5、sort()

  • 该方法用来对列表当中的元素进行排序(默认升序)
  • sort() 方法,默认比较列表中元素的大小
l = ['bb','aaaa','c','fff','dddddddd']
l.sort()									# 默认有个参数 l.sort(reverse = False) ,  True 为降序
print(l)
  • 在 sort() 函数中可以接收一个关键字参数 key
  • key 需要一个函数作为参数
l = ['bb','aaaa','c','fff','dddddddd']
l.sort(key=len)								# 按照字符串长度来排序
print(l)

l2 = [2,3,'1',3,'5','4']
l2.sort(key=int)
print(l2)

1.6、sorted() 有返回值,返回一个新的列表

l = [2,3,'1',3,'5','4']
print('排序前:',l)

r = sorted(l,key=int)
print(r)

print('排序后:',l)



二、闭包


2.1、什么是闭包?

  • 将函数作为返回值返回,也是一种高阶函数,叫做 闭包。
def fn():
    a = 10
    def inner():                # 在函数内部在定义一个函数
        print('我是fn2',a)

    return inner                # 将内部函数 inner()作为返回值返回

r = fn()                        # r 是调用 fn() 后返回的函数. 所以这个函数是在 fn()内部定义的, 并不是全局函数
r()                             # 所以这个函数总是能访问到 fn() 函数内部的变量

2.2、它有什么好处?

  • 通过闭包可以创建一些只有当前函数可以访问到的变量(可以将一些私有的数据藏到闭包当中)。
# 求多个数的平均值

nums = []									# 如此, nums 就是一个全局变量, 容易出现重名导致的错误

def average(n):
    nums.append(n)
    # 求平均值
    return sum(nums)/len(nums)

print(average(10))
print(average(30))

# # nums.append('python')					# 不小心被别人使用同名变量,修改了变量,程序报错

# nums = []
# print(average(30))						# 结果不准确

用闭包实现,则可以避免私有数据 nums 被使用

def make_average():
    nums = []    							# 创建一个空的列表
    
    def average(n):    						# 创建一个函数,用来求平均值
        nums.append(n)
        return sum(nums)/len(nums)    		# 求平均值

    return average

num = make_average()
print(num(10))
nums = []									# 为对程序产生影响
print(num(30))

2.3、总结:形成闭包的条件

  1. 函数嵌套
  2. 将内部函数作为返回值返回
  3. 内部函数必须要使用到外部函数的变量



三、装饰器


3.1、装饰器的引用

  1. 普通方法
    (1) 如果要修改的函数过多,修改起来比较麻烦
    (2) 不方便后期维护
    (3) 会违反一个开闭原则(ocp)。在开发的时候,要求可以开发对程序的扩展,但是不可以关闭对程序的修改
#  打印开始计算 打印计算结束

def add(a,b):
    print('计算开始...')						# 添加的代码
    r = a + b                   			# 求任意两个数的和
    print('计算结束...')						# 添加的代码
    return r

def mul(a,b):
    print('计算开始...')						# 添加的代码
    r = a * b                   			# 求任意两个数的积
    print('计算结束...')						# 添加的代码
    return r

r = add(1,2)
r2 = mul(1,2)
print(r,r2)

  1. 在不修改原函数的情况下,来对函数进行扩展
def add(a,b):
    r = a + b      
    return r

def new_add(a,b):
    print('函数开始执行......')
    r = add(a,b)
    print('函数执行结束......')
    return r
    
r = new_add(1,2)
print(r)

同样存在问题: 若需要扩展的函数有多个,则需要创建多个新的函数

3.2、装饰器的使用

def fn():
    def add(a,b):
        pass
        
    return add

r = fn()
w = fn()
print(r)					# <function fn.<locals>.add at 0x000002A9639AD7B8>
print(w)					# <function fn.<locals>.add at 0x000002A9639C4D90>

注意:两次调用同一函数,它们不是同一对象。(即,返回一个新的函数)

def fn():
    print('我是fn函数')

def add(a,b):
    r = a + b      
    return r

def start_end(old):
    # 用来对其他函数(old)进行扩展, 使(old)函数可以在执行前打印 "执行开始",执行后打印 "执行结束"

    def new_function(a,b):          		# 创建一个函数 
        print('开始执行.....')
        result = old(a,b)           		# 调用被扩展的函数
        print('开始结束.....')

        return result

    return new_function

# f = start_end(fn)  						# 报错
f = start_end(add)
r = f(1,2)
print(r)

又存在问题: 函数的参数个数可能不一致

  1. 加强版
    (1) 类似 start_end(old) 这种函数,就称之为装饰器
    (2) 通过装饰器, 可以在不修改原来函数的基础之上来对函数进行扩展
    (3) 在开发当中, 都是通过对装饰器来扩展函数的功能
def fn():
    print('我是 fn 函数')


def add(a,b):
    print('我是 add 函数')
    r = a + b      
    return r


def start_end(old):

    # 用来对其他函数进行扩展, 使其他函数可以在执行前打印执行开始,执行后打印执行结束

    # 创建一个函数 
    # *args 接收的是所有的 "位置参数"
    # **kwargs 接收所有的 "关键字参数"
    
    def new_function(*args,**kwargs):       # 把参数装成 元组(字典)
        print('开始执行.....')

        # 调用被扩展的函数
        result = old(*args,**kwargs)        # 把位置参数(关键字参数)拆包成一个一个元组(字典)传入

        print('开始结束.....')

        return result

    # 返回函数
    return new_function
    

f = start_end(fn)
r = f()
print(r,'\n')               				# 因为 fn 函数没有写返回值 (return), 所以默认返回 None
f2 = start_end(add)
r2 = f2(123,456)
print(r2)

3.3、另一种装饰器使用方法

def start_end(old):
    def new_function(*a,**k):
        print('开始执行...')
        result = old(*a,**k)
        print('结束执行...')
        return result
    return new_function

@ start_end									# 在此处进行装饰
def say_bye(a,b):
    print('再见')
    return a + b

r = say_bye(8,8)							# 此处则调用原函数
print(r)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值