Python基础—装饰器

装饰器

一、装饰器前奏

①装饰器是什么:装饰器是用来装饰函数的,能够在不修改函数的情况下给函数增加新的功能

②为什么函数能够被装饰:《流畅的Python》书中提到,Python中的函数是一等对象

二、函数的性质:

1.在运行时创建(函数)

2.能赋值给变量

3.能够作为参数传递给函数

4.函数还可以作为其他函数的返回结果

三、函数中传递函数

def func_1(a, b):
	print('函数func_1正在执行')
	return a + b

def func_2(func, c, d)
	print('函数func_2正在执行')
	return func(c, d)

print(func_1(1, 2))
print(func_2(func_1,34))

运行结果:函数func_1正在执行
         3
         函数func_2正在执行
         函数func_1正在执行
         7

四、函数中定义函数

def func_3():
	print('函数func_3正在执行')
	
	def func_4():
		print('函数func_4正在执行')

	func_4()

func_5()

运行结果:函数func_3正在执行
         函数func_4正在执行

五、函数返回函数

def func_5(a):
	print('函数func_5正在执行')

	def func_6(b):
		print('函数func_6正在执行')
		return a + b
	return func_6

x = func_5(1)     此时,func_5执行完,func_6这个函数被返回出来并且赋值给了x
print(x(2))       相当于x就是func_6,调用x等于等于调用func_6

运行结果:函数func_5正在执行
         函数fanc_6正在执行
         3

七、无参装饰器

def first_decorator(func):
	def name_wrapper():
		# func一会必须传值函数,__name__是一个魔术(魔法)方法,能够查看函数的名字
		print(f'被装饰的函数【{func.__name__}】即将执行')
		func()
		print(f'被装饰的函数【{func.__name__}】即将执行')
	return name_wrapper

def twoSum():
	print('函数twoSum正在执行')

twoSum = first_decorator(twoSum)  # 调用first_decorator函数,
                                  # 通过twoSum这个实参传入first_decorator这个函数
                                  # 此时twoSum又传值给了func(实参传值给了形参)
                                  # 由于name_wrapper函数没有被调用只是被返回了
                                  # 因此twoSum变量等价于包含了原来的twoSum函数的name_wrapper函数
                                  
twoSum()   # 此处等价于将所有函数一同执行

运行结果:被装饰的函数【twoSum】即将执行
         函数twoSum正在执行
         被装饰的函数【twoSum】执行完成

由于上面的写法不易看懂,不好理解,于是Python有了下面这种写法

@first_decorator
def twoSum():
    print('函数twoSum正在执行')

twoSum()

运行结果:被装饰的函数【twoSum】即将执行
         函数twoSum正在执行
         被装饰的函数【twoSum】执行完成

上面的@first_decorator被叫做语法糖(语法糖衣),语法糖,指计算机语言中添加的某种语法,对语言本身没有任何影响,并且增加了新的功能。优点:语法糖能够增加程序的可读性,并且减少代码量和出错的可能性

八、使用装饰器测试程序性能

import time


# 编写装饰器
def first_decorator(func):
    def name_wrapper():
        start = time.time()
        result = func()
        end = time.time()
        print(f'程序执行花费时间{end - start}秒')
        return result

    return name_wrapper


nums = [i for i in range(1, 101)]


# 问题:对比reduce和for循环性能,以100的阶乘为例
# 被测试程序一:
@first_decorator
def test_for():
    result = 1
    for i in nums:
        result *= i
    return result


print(test_for())


# 被测试程序二:
@first_decorator
def test_reduce():
    from functools import reduce
    return reduce(lambda x, element: x * element, nums, 1)


print(test_reduce())

运行结果:程序执行花费时间0.093326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
         程序执行花费时间0.093326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

九、有参装饰器

装饰器的应用场景:1.插入日志、性能测试、事务处理、web权限校验、Cache有效性测试等位置可以使用(web开发涉及的场景)

装饰器优点:能够不改变原函数从而使其具有新功能

缺点:不好理解,性能不太好

# 1.一个登录系统,判断某位用户是会员用户还是白嫖用户
# 定义判断用户身份的装饰器
def id_judge(kind = ''):
    def outter(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            if result == '登录成功':
                id_kind = '尊敬的VIP用户' if kind == 'VIP' else '万恶的白嫖用户'
                return f'{id_kind}, 登录成功'
            else:
                return '登录失败'
        return wrapper
    return outter

@id_judge('VIP')
def login(user, password):
    if user == 'admin' and password == '123456':
        return '登录成功'
    else:
        return '登录失败'

result = login('admin', '123456')
print(result)

你可能感兴趣的:(Python基础,python,开发语言,numpy)