Python 之基于面向对象三大特征思想的函数式编程补充——闭包和装饰器

高阶函数

  可以接受其他方法作为参数的函数称为高阶函数。
  这个还是因为Python的变量名不是固定一成不变的,不像Java、C#需要直接指明该变量的类型后就无法改变。通过多次画内存图我们可以得知,变量名只是一个指针,它可以随时指向任何类型的变量,也包括可以指向一个函数。
  下面我们用代码尝试一下:

def addNum(x,y):
    return  x +y

x = 3
y = 5
print(addNum(x,y))
#把addNum方法赋值给了_f,那么_f现在就是指向此函数的,可以把它当作函数调用
#可以仿照C++ typedef关键字的理解,理解为给函数去了一个别名
_f = addNum
print(_f(x,y))

输出:

C:/Users/ZBZ/PycharmProjects/untitled/excise03.py
8
8

Process finished with exit code 0

  那么既然这样,按照高阶函数的定义,把函数当作变量传进来,其实在前面函数式编程讲继承与多态的时候我们已经应用了。我们换个例子,比如现在有三个方法,一个求平方的、一个求乘法的】,让使用这两个方法写一个求aX^2的方法,代码如下:

def sqrNum(x):
    return  x * x
def mulNum(x,y):
    return  x * y

def doublesqr(a,x,sqr,mul):
    return mul(a,sqr(x))


#把addNum方法赋值给了_f,那么_f现在就是指向此函数的,可以把它当作函数调用
#可以仿照C++ typedef关键字的理解,理解为给函数去了一个别名

x = 10 
a = 5
s = sqrNum
m = mulNum
print(doublesqr(a,x,s,m))

输出结果:

500

Process finished with exit code 0

  讲完了这个再记录下几个常用的Python内置高阶函数:

  • filter:根据传入的方法贵族筛选、自动过滤掉不符合条件的元素并且返回符合条件的可迭代对象。注意看下每个返回值的类型:
class skill:
    def __init__(self,name,atk):
        self.__name = name
        self.__atk = atk

    @property
    def atk(self):
        return self.__atk
    @atk.setter
    def atk(self,value):
        self.__atk = value
    def __str__(self):
        return "此技能名为%s伤害为%s"%(self.__name,self.__atk)

skills = []

skills.append(skill("九阴真经",99))
skills.append(skill("降龙十八掌",95))
skills.append(skill("蛤蟆功",85))

for item in filter(lambda item:item.atk >90, skills):
	print(type(item))
    print(item)

输出结果:

<class '__main__.skill'>
此技能名为九阴真经伤害为99
<class '__main__.skill'>
此技能名为降龙十八掌伤害为95

Process finished with exit code 0
  • map:返回筛选后的结果,不一定是原来的可迭代对象,返回新的可迭代对象。
class skill:
    def __init__(self,name,atk):
        self.__name = name
        self.__atk = atk

    @property
    def atk(self):
        return self.__atk
    @atk.setter
    def atk(self,value):
        self.__atk = value
    def __str__(self):
        return "此技能名为%s伤害为%s"%(self.__name,self.__atk)

skills = []

skills.append(skill("九阴真经",99))
skills.append(skill("降龙十八掌",95))
skills.append(skill("蛤蟆功",85))

for item in map(lambda item:item.atk, skills):
    print(type(item))
    print(item)
for item in map(lambda item:(item.atk +5)*2, skills):
    print(type(item))
    print(item)

输出结果:

<class 'int'>
99
<class 'int'>
95
<class 'int'>
85
<class 'int'>
208
<class 'int'>
200
<class 'int'>
180
  • max:求最大值
print(max(skills,key = lambda item:item.atk))

输出:

此技能名为九阴真经伤害为99

Process finished with exit code 0

从闭包到装饰器

  假如上面做的技能,有一个做好的攻击Attack(),后来觉得不合理,需要在Attack()之前有一个释放的状态,那么该如何做呢?代码向下面:

# m = mulNum
class skill:
    def __init__(self,name,atk):
        self.__name = name
        self.__atk = atk

    @property
    def atk(self):
        return self.__atk
    @atk.setter
    def atk(self,value):
        self.__atk = value
    def __str__(self):
        return "此技能名为%s伤害为%s"%(self.__name,self.__atk)
    def Attack(self):
        print("用%s造成了%s点伤害"%(self.__name,self.__atk))
skills = []

skills.append(skill("九阴真经",99))
skills.append(skill("降龙十八掌",95))
skills.append(skill("蛤蟆功",85))

for Skill in skills:
    Skill.Attack()

输出:

用九阴真经造成了99点伤害
用降龙十八掌造成了95点伤害
用蛤蟆功造成了85点伤害

Process finished with exit code 0

  闭包这个知识点就是为了装饰器的实现,而装饰器的作用就是解决此类问题。
  闭包有三个要素才称为闭包:

	- 必须有一个内嵌函数
	- 内嵌函数必须引用外部函数中的变量
	- 必须返回内嵌函数

  觉得仅仅这么说,不好理解,直接上代码看内存图。

def travel():
    aim = "上海"
    def go():
        nonlocal aim
        aim = "坐车去" + aim
        print(aim)
    print(aim)
    return go

a = travel()
a()

输出结果:

上海
坐车去上海

这就组成了一个闭包。然后再来看一下内存图:
闭包内存图
  闭包最重要的就是一个整合的作用,把内嵌函数和它外面一层的函数资源的整合。这样调用外部函数的时候,返回的go()函数赋值给了变量a,当a调用执行的时候,也就是go()执行完毕后资源才会释放。这样最后一个大的红色框体框起来的,包含了内嵌函数、外部函数整体资源的,就成为一个闭包。

装饰器

  下面叙述一个场景,假如做一个英雄,有四个技能,然后英雄根据技能别人,类设计如下:

class skill:
    def __init__(self,name,atk,supernatural):
        self.__name = name
        self.__atk = atk
        self.__supernatural = supernatural

    @property
    def name(self):
        return self.__name
    @property
    def atk(self):
        return self.__atk
    @atk.setter
    def atk(self,value):
        self.__atk = value
    @property
    def supernatural(self):
        return self.__supernatural

    def __str__(self):
        return "此技能名为%s伤害为%s"%(self.__name,self.__atk)
    def Attack(self):
        print("用%s造成了%s点伤害"%(self.__name,self.__atk))
class Hero:
    supernatural = 700
    def __init__(self,name):
        self.__name = name
        self.__skills = []
        self.__skills.append(skill("九阴真经", 99, 100))
        self.__skills.append(skill("降龙十八掌", 65, 50))
        self.__skills.append(skill("蛤蟆功", 85, 30))
    def xiangLongShiBaZhang(self):
        for _skill in self.__skills:
            if(_skill.name == "降龙十八掌"):
                _skill.Attack()
    def JiuYinZhenJing(self):
        for _skill in self.__skills:
            if(_skill.name == "九阴真经"):
                _skill.Attack()
    def HaMaGong(self):
        for _skill in self.__skills:
            if(_skill.name == "蛤蟆功"):
                _skill.Attack()

h = Hero("慕容复")
h.HaMaGong()
h.xiangLongShiBaZhang()
h.JiuYinZhenJing()

输出:

用蛤蟆功造成了85点伤害
用降龙十八掌造成了65点伤害
用九阴真经造成了99点伤害

现在要加一个新的需求,想调用攻击方法的时候,检查蓝条是否足够释放并且增加是谁攻击的播报。下面就要用到装饰器了:

class Hero:
    supernatural = 700
    def __init__(self,name):
        self.__name = name
        self.__skills = []
        self.__skills.append(skill("九阴真经", 99, 100))
        self.__skills.append(skill("降龙十八掌", 65, 50))
        self.__skills.append(skill("蛤蟆功", 85, 30))
    def xiangLongShiBaZhang(self):
        for _skill in self.__skills:
            if(_skill.name == "降龙十八掌"):
                _skill.Attack()
    def JiuYinZhenJing(self):
        for _skill in self.__skills:
            if(_skill.name == "九阴真经"):
                _skill.Attack()
    def HaMaGong(self):
        for _skill in self.__skills:
            if(_skill.name == "蛤蟆功"):
                _skill.Attack()
    def UseSkill(self,_skill):
        print(self.__name,"释放技能")
        return _skill


h = Hero("慕容复")
HaMaGong = h.UseSkill(h.HaMaGong)
HaMaGong()

JiuYinZhenJing = h.UseSkill(h.JiuYinZhenJing)
JiuYinZhenJing()

xiangLongShiBaZhang = h.UseSkill(h.xiangLongShiBaZhang)
xiangLongShiBaZhang()

输出:

慕容复 释放技能
用蛤蟆功造成了85点伤害
慕容复 释放技能
用九阴真经造成了99点伤害
慕容复 释放技能
用降龙十八掌造成了65点伤害

  在上面的类中使用Usekill方法,通过使用闭包的概念,对每次释放技能之前添加释放者播报。这是最基础的方法对调用原来的方法进行拦截。这样的缺点是,调用的时候太过麻烦。再来个过渡版,解决调用问题。由于写的类使用属性拦截执行时报错,下面的举例参考教学视频里的视频暂时使用函数式编程,暂时不用类。代码如下:

def verify_permissions(func):
    def wrapper(*args, **kwargs):
        print("权限验证")
        func(*args, **kwargs)

    return wrapper


# 已有功能
@verify_permissions
def enter_background(login_id, pwd):
    print(login_id, pwd, "进入后台")

@verify_permissions
def delete_order(id):
    print("删除订单", id)

enter_background("abc", 1234)
delete_order(101)

这是最终的版本,包括了带不通传参的装饰器构建。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值