自学python_10 函数04

装饰器:

闭包的升级,在开发上的应用例如判断用户的登录状态。修改丰富已经写好的函数。

回顾:以函数作为参数(也是装饰器的基础):

def test():
	print("test")

t = test
t()
# test 
print(f)
# <function test at 0x000002BA5B9F7678>
print(test)
# <function test at 0x000002BA5B9F7678>

把test的地址赋值给了t,t加()就相当于test(),具体的过程在上一篇笔记闭包的介绍里。

下面介绍装饰器:

特点:
1.函数A是作为参数出现的。
2.有闭包的特点出现。

具体使用情景:当一个函数已经定义完成,但是想丰富它的内容时。

但是问题来了,我们怎么做才能实现这些功能呢?
我们可以尝试:
1.直接修改原来的函数。
2.重新定义一个函数调用原来的函数,并且加上新的内容。
比如下列代码:

def house():
	print("毛坯房")
def house1():
	house()
	print("刷漆")
	print("铺地板")
house()

这两种方法都不是可行的,因为在修改的时候,会改变调用这个函数位置的代码,如果那里的代码已经完成,修改会很耗费时间。

这时候我们就要引出装饰器了,它可以在不改变函数名的情况下对函数进行装饰丰富。

定义一个装饰器:

def decorate(func):
	a = 100
	print("wrapper外层")
	def wrapper():
		func()
		print("1111")
		print("2222")
	print("wrapper加载完成")
	return wrapper
# 使用装饰器
# @后加装饰器函数表示使用这个函数作为装饰函数。
@decorate
def house():
	print("毛坯房")
# wrapper外层
# wrapper加载完成

注意:这里并没有调用house函数,但是却执行了decorate里的一些步骤。

下面说明一下当执行到@decorate之后底层执行的工作:
1.确定house为被装饰函数。
2.将house作为被装饰函数作为参数给decorate函数。
3.调用decorate里的代码,注意里面定义的函数(例如wrapper)不会执行。
4.然后再用house接收返回值wrapper。

def decorate(func):
	a = 100
	print("wrapper外层")
	def wrapper():
		func()
		print("1111")
		print("2222")
	print("wrapper加载完成")
	return wrapper
@decorate
def house():
	print("毛坯房")
	
print(house)
# <function decorate.<locals>.wrapper at 0x00000236C3D1FC18>

可以看出wrapper和house的地址是一样的。

装饰器decorate并没有改变原函数的名字和结构,但是对原函数的功能进行了改变,但是此时的house执行的代码和原来的不一样了,执行的是返回的wrapper区域里的代码。当然,wrapper里的代码是经过装饰器decorate修改加工的。

带参数的装饰器:

def decorate(func):
	a = 100
	print("wrapper外层")
	def wrapper():
		func(x)
		print(x)
		print("1111")
		print("2222")
@decorate
def house(n):
	print("毛坯房")
house(5)

还是一上面的代码为例。因为在装饰之后house的地址指向的是wrapper的地址,如果想要装饰,wrapper和house还有decorate里的参数func使用时都必须要有参数,或者同时没有。不然的话在传递参数的时候会报错。


此外,还有一种万能的装饰器,就是把wrapper和func中的参数变成可变参数。

def decorate(func):
	a = 100
	def wrapper(*x):
		func(*x)
	return wrapper


@decorate
def house(x):
	print("house函数")
	for i in x:
		print(i)
	print("house函数end")
num = [1,2,3]
house(num)

# house函数
# 1
# 2
# 3
# house函数end

在这里func里的变量也要加 * ,因为不加 * 表示的是一个列表,列表不拆包的时候只能作为一个形参传递进去。

注意当有多个装饰器的时候先装饰离函数最近的。

装饰器的一个应用:付款(非常简陋):

import time

users = dict() # 定义一个字典。
# 定义初始的用户名密码。
users["1234"] = "123456"
users["12345"] = "1234567"

islogin = False # 判断是否登录,默认是没有登录的。

# 登录页面。
def login():
	username = input("输入用户名:")
	password = input("输入密码:")
	if users.get(username) == password:
		return True
	else:
		return False


# 定义一个装饰器,进行付款验证。
def login_required(func):
	def wrapper(*args,**kwargs):
		global islogin
		while islogin == False:
			# 跳转登录页面。
			print("未登录无法付款!")
			islogin = login()
		func(*args,**kwargs)
	return wrapper


# 付款函数。
@login_required
def pay(money):
	print("正在付款中,付款金额是:{}元".format(money))
	print("付款中....")
	time.sleep(2)
	print("付款成功!")

pay(100000000)
# 未登录无法付款!
# 输入用户名:>? 1234
# 输入密码:>? 123456
# 正在付款中,付款金额是:100000000元
# 付款中....
# 付款成功!

pay(8000)
# 正在付款中,付款金额是:8000元
# 付款中....
# 付款成功!

这里可以很好地体现出装饰器的作用,代码一定要多实践,写完之后我就明白了为什么要设置装饰器这个东西了。装饰函数的时候可以用在很多地方,比如说这个登录页面,如果只是单纯地在pay等使用它的函数上增加代码,会造成代码的重复,使程序就会变得非常复杂。比如说当我们要修改登陆验证代码的时候。会在各个地方修改,非常不好找。


作用域搜索顺序:LEGB

L:local本地,局部变量。
E:encloseing嵌套。
G:global全局变量。
B:built-in内置的。

b = 4
def f():
	a = 1
	def f1():
		a = 3
		print(a)
		print(b)
		print(max)
	f1()

f()
# 3
# 4
# <built-in function max>

不知不觉已经学了123集了,希望能坚持下去,做自己热爱的事业是人生最幸福的事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值