这是第四天的博客了。在紧张的一周的开发后,终于完成了作业 ATM+购物商城的系统 虽然还是有些瑕疵,来不及了,容错先不做了 哈哈 整理下今天学的内容吧,在用过后反而会有一些自己的感悟
今天我们学到了一个特别牛逼的东西 就是我们下面介绍的这个
一、装饰器
1.1 定义:
本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能
1.2 装饰器原则:
1) 不能修改被装饰函数的源代码;
2) 不能修改被装饰函数的调用方式;
下面是一个简单的装饰使用方法、结合我们这周的开发项目,来说一下这个装饰器的使用方法
很多人学会了装饰器、也会写了,但是就是不知如何使用。实际上这就是一层窗户纸,只要你发力捅破他,你就会发现,他真的很牛逼,并且很酷炫。
首先说下我们的项目需求
作业需求:
模拟实现一个ATM + 购物商城程序
- 额度 15000或自定义
- 实现购物商城,买东西加入 购物车,调用信用卡接口结账
- 可以提现,手续费5%
- 每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息
- 支持多账户登录
- 支持账户间转账
- 记录每月日常消费流水
- 提供还款接口
- ATM记录操作日志
- 提供管理接口,包括添加账户、用户额度,冻结账户等。。。
- 用户认证用装饰器
首先我们来分析下下面装饰器的组成部分:
1.3 实现装饰器知识储备:
1.3.1 函数即“变量”
定义一个函数相当于把函数体赋值给了函数名
>>> def func(): ...... print("这是一个函数") >>> print(func) >>> func() <function func at 0x0000000000D2CD08> 这是一个函数 #func()是函数调用,而func是函数本身。 #要获得函数调用结果,我们可以把结果赋值给变量: >>> a = func() 这是一个函数 #函数本身赋值给变量 >>> a = func <function func at 0x0000000000D2CD08> #结论:函数本身也可以赋值给变量,即:变量可以指向函数。 #猜想:是否可以通过变量直接调用函数? >>> a=func >>> a() 这是一个函数 #说明变量指向了func函数本身,直接调用a()和func()完全相同
1.3.2 高阶函数
高阶函数:能接收函数作为参数的函数。
满足下列条件之一就可成函数为高阶函数
-
某一函数当做参数传入另一个函数中(用处:在不修改被装饰函数源代码的情况下为其添加功能)
>>> def bar(): ......print('in the bar') >>> def foo(func): ......res=func() ......return res >>> foo(bar) in the bar
2、函数的返回值包含n个函数,n>0(用处:不修改函数调用方式)
>>>def bar(): ......time.sleep(3) ......print("in the bar") >>> def test2(func): ......print(func) ......return func >>> print(test2(bar)) >>> bar = test2(bar) >>> bar() <function bar at 0x0000000000D6CD08> <function bar at 0x0000000000D6CD08> <function bar at 0x0000000000D6CD08> in the bar
高阶函数示例
- map()
map函数会根据提供的函数对指定序列做映射。
map函数的定义:
map(function, sequence[, sequence, ...]) -> list
通过定义可以看到,这个函数的第一个参数是一个函数,剩下的参数是一个或多个序列,返回值是一个集合。
function可以理解为是一个一对一或多对一函数,map的作用是以参数序列中的每一个元素调用function函数,返回包含每次function函数返回值的list。
>>> def f(x): ...... return x*x >>> r = map(f,[1,2,3,4,5,6,7,8,9]) >>> print(list(r)) [1, 4, 9, 16, 25, 36, 49, 64, 81]
- reduce()
reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) >>> from functools import reduce >>> def add(x, y): ......return x + y >>> print(reduce(add, [1, 3, 5, 7, 9]))
- filter()
filter函数会对指定序列执行过滤操作。
filter函数的定义:
filter(function or None, sequence) -> list, tuple, or string
function是一个谓词函数,接受一个参数,返回布尔值True或False。
filter函数会对序列参数sequence中的每个元素调用function函数,最后返回的结果包含调用结果为True的元素。
返回值的类型和参数sequence的类型相同。
>>> def is_odd(n): ...return n % 2 == 1 >>> print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))) [1, 5, 9, 15]
- sorted()
对列表内容进行正向排序,即可以保留原列表,又能得到已经排序好的列表;
>>> a = {6:2,8:0,1:4,-5:6,99:11,4:22} >>> print(sorted(a.items())) #按key排序 [(-5, 6), (1, 4), (4, 22), (6, 2), (8, 0), (99, 11)] >>> print(sorted(a.items(),key=lambda x:x[1])) #按value排序 [(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)]
1.3.3 嵌套函数
定义:在一个函数体内用def去声明一个新函数
>>> def foo(): #定义函数foo() ...m=3 #定义变量m=3; ...def bar(): #在foo内定义函数bar() ...n=4 #定义局部变量n=4 ...print(m+n) #m相当于函数bar()的全局变量 ...bar() #foo()函数内调用函数bar() >>> foo() #调用foo()函数 7
1.3.4 装饰器
高阶函数+嵌套函数=>装饰器
不带参数的装饰器
#装饰器 import time def timer(func): def deco(): start_time=time.time() func() #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return deco #返回函数deco的内存地址 def test1(): print("in the test1") time.sleep(1) test1 = timer(test1) #重新赋值test1 此时test1=deco的内存地址 test1() #执行test1 ###########打印输出########### #in the test1 #func runing time is 1.0000572204589844
带固定参数的装饰器:
#装饰器 import time def timer(func): def deco(name): start_time=time.time() func(name) #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return deco #返回函数deco的内存地址 @timer #test1 = timer(test1) test1=deco def test1(name): print("in the test1 name %s"%name) time.sleep(1) test1("cc") #执行test1 ###########打印输出########### #in the test1 name cc #func runing time is 1.0000572204589844
带返回值的装饰器:
#装饰器 import time def timer(func): def deco(*args,**kwargs): start_time=time.time() res = func(*args,**kwargs) #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return res return deco #返回函数deco的内存地址 @timer #test1 = timer(test1) test1=deco def test1(name): print("in the test1 name %s"%name) time.sleep(1) return "return form test1" print(test1("cc")) #执行test1 ###########打印输出########### #in the test1 name cc #func runing time is 1.0000572204589844 #return form test1
通过以上我们会发现一个问题,选用的装饰器只能选择统一带形参或者统一不带形参;那么问题来了,我想要用一个装饰器,带形参的能调用,不带形参的也能调用,可不可以呢?
带不固定参数的装饰器:
# 装饰器 import time def timer(func): def deco(*args, **kwargs): start_time = time.time() func(*args, **kwargs) # 执行形参func() end_time = time.time() print("func runing time is %s" % (end_time - start_time)) return deco # 返回函数deco的内存地址 @timer # test1 = timer(test1) test1=deco def test1(name): print("in the test1 name %s" % name) time.sleep(1) @timer def test2(): print("in the test2 no name") time.sleep(1) test1("cc") # 执行test1 test2() # 执行test2 ###########打印输出########### in the test1 name cc func runing time is 1.0010571479797363 in the test2 no name func runing time is 1.0000572204589844
终极版装饰器:
# Author:houyafan import time '''装饰器demo''' def auth(type): # 接受装饰器的变量 def timer(func): # 装饰器 接受源代码的方法内存地址 def deco(*args, **kwargs): # 新加的功能 if type == 'file': start = time.time() # 新增的功能 func(*args, **kwargs) # 通过传过来的地址调用 为了兼容有参数的 和无参数的函数 可以默认填写上*args和**kwargs stop = time.time() # 新增的功能 print(stop - start) elif type == 'abc': print("type is abc") return deco return timer @auth(type='file') def test1(): time.sleep(1) print('test1') @auth(type='abc') def test2(name, age): time.sleep(1) print('test2', name, age) test1() test2('houyafan', 22)
我们根据上面的作业需求,和下面的装饰器代码思考下,这个作业中什么地方会用到装饰器,首先我们ATM系统最注重的就是,安全问题,首先校验的就是我们是否有登陆ATM,
然后我们才会有权限去操作我们的银行卡,这时就有一个问题出现了,我如何在每次选择一个功能是让他去校验我是否登陆了呢?
我们的装饰器的牛逼之处就出现了,如果我定义一个装饰器他是判断我是否有登陆?如果登陆了就执行我的功能逻辑代码,如果没登陆,就先登录后在执行我的代码。这样是不是就实现了在每个功能操作前,都校验下我是否已经登陆了呢? 答案是肯定的 好的 对于装饰器 通过我这个例子我想你应该能够举一反三在开发过程中想到如何用装饰器了吧。。。。