1.装饰器
角色扮演:你是一家视频网站的后端开发工程师,你们网站有以下几个版块:
def
home():
(
"---首页----"
)
def
america():
(
"----欧美专区----"
)
def
japan():
(
"----日韩专区----"
)
def
henan():
(
"----河南专区----"
)
视频刚上线初期,为了吸引用户,你们采取了免费政策,所有视频免费观看,迅速吸引了一大批用户,免费一段时间后,每天巨大的带宽费用公司承受不了了,所以准备对比较受欢迎的几个版块收费,其中包括“欧美” 和 “河南”专区,你拿到这个需求后,想了想,想收费得先让其进行用户认证,认证通过后,再判定这个用户是否是VIP付费会员就可以了,是VIP就让看,不是VIP就不让看就行了呗。 你觉得这个需求很是简单,因为要对多个版块进行认证,那应该把认证功能提取出来单独写个模块,然后每个版块里调用 就可以了,与是你轻轻的就实现了下面的功能 。
#_*_coding:utf-8_*_
user_status
=
False
#用户登录了就把这个改成True
def
login():
_username
=
"alex"
#假装这是DB里存的用户信息
_password
=
"abc!23"
#假装这是DB里存的用户信息
global
user_status
if
user_status
=
=
False
:
username
=
input
(
"user:"
)
password
=
input
(
"pasword:"
)
if
username
=
=
_username
and
password
=
=
_password:
(
"welcome login...."
)
user_status
=
True
else
:
(
"wrong username or password!"
)
else
:
(
"用户已登录,验证通过..."
)
def
home():
(
"---首页----"
)
def
america():
login()
#执行前加上验证
(
"----欧美专区----"
)
def
japan():
(
"----日韩专区----"
)
def
henan():
login()
#执行前加上验证
(
"----河南专区----"
)
home()
america()
henan()
此时你信心满满的把这个代码提交给你的TEAM LEADER审核,没成想,没过5分钟,代码就被打回来了, TEAM LEADER给你反馈是,我现在有很多模块需要加认证模块,你的代码虽然实现了功能,但是需要更改需要加认证的各个模块的代码,这直接违反了软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块不应该被修改
- 开放:对现有功能的扩展开放
这个原则你还是第一次听说,我擦,再次感受了自己这个野生程序员与正规军的差距,BUT ANYWAY,老大要求的这个怎么实现呢?如何在不改原有功能代码的情况下加上认证功能呢?你一时想不出思路,只好带着这个问题回家继续憋,媳妇不在家,去隔壁老王家串门了,你正好落的清静,一不小心就想到了解决方案,不改源代码可以呀。
你师从沙河金角大王时,记得他教过你,高阶函数,就是把一个函数当做一个参数传给另外一个函数,当时大王说,有一天,你会用到它的,没想到这时这个知识点突然从脑子 里蹦出来了,我只需要写个认证方法,每次调用 需要验证的功能 时,直接 把这个功能 的函数名当做一个参数 传给 我的验证模块不就行了么,哈哈,机智如我,如是你啪啪啪改写了之前的代码
#_*_coding:utf-8_*_
user_status
=
False
#用户登录了就把这个改成True
def
login(func):
#把要执行的模块从这里传进来
_username
=
"alex"
#假装这是DB里存的用户信息
_password
=
"abc!23"
#假装这是DB里存的用户信息
global
user_status
if
user_status
=
=
False
:
username
=
input
(
"user:"
)
password
=
input
(
"pasword:"
)
if
username
=
=
_username
and
password
=
=
_password:
(
"welcome login...."
)
user_status
=
True
else
:
(
"wrong username or password!"
)
if
user_status
=
=
True
:
func()
# 看这里看这里,只要验证通过了,就调用相应功能
def
home():
(
"---首页----"
)
def
america():
#login() #执行前加上验证
(
"----欧美专区----"
)
def
japan():
(
"----日韩专区----"
)
def
henan():
#login() #执行前加上验证
(
"----河南专区----"
)
home()
login(america)
#需要验证就调用 login,把需要验证的功能 当做一个参数传给login
# home()
# america()
login(henan)
你很开心,终于实现了老板的要求,不改变原功能代码的前提下,给功能加上了验证,但是又犯了一个大忌,什么大忌?你改变了调用方式呀, 想一想,现在没每个需要认证的模块,都必须调用你的login()方法,并把自己的函数名传给你,人家之前可不是这么调用 的, 试想,如果 有100个模块需要认证,那这100个模块都得更改调用方式,这么多模块肯定不止是一个人写的,让每个人再去修改调用方式 才能加上认证,你会被骂死的。。。。
home()
login(america)
#需要验证就调用 login,把需要验证的功能 当做一个参数传给login
# home()
# america()
login(henan)
你之所改变了调用方式,是因为用户每次调用时需要执行login(henan),类似的。其实稍一改就可以了呀
home()
america
=
login(america)
#你在这里相当于把america这个函数替换了
henan
=
login(henan)
这样你,其它人调用henan时,其实相当于调用了login(henan), 通过login里的验证后,就会自动调用henan功能。
最终的代码如下:
#_*_coding:utf-8_*_
user_status
=
False
#用户登录了就把这个改成True
def
login(func):
#把要执行的模块从这里传进来
def
inner(
*
args,
*
*
kwargs):
#再定义一层函数
_username
=
"alex"
#假装这是DB里存的用户信息
_password
=
"abc!23"
#假装这是DB里存的用户信息
global
user_status
if
user_status
=
=
False
:
username
=
input
(
"user:"
)
password
=
input
(
"pasword:"
)
if
username
=
=
_username
and
password
=
=
_password:
(
"welcome login...."
)
user_status
=
True
else
:
(
"wrong username or password!"
)
if
user_status
=
=
True
:
func(
*
args,
*
*
kwargs)
# 看这里看这里,只要验证通过了,就调用相应功能
return
inner
#用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
def
home():
(
"---首页----"
)
@login
def
america():
#login() #执行前加上验证
(
"----欧美专区----"
)
def
japan():
(
"----日韩专区----"
)
@login
def
henan(style):
(
"----河南专区----"
)
america()