装饰器

装饰器: 在不改变原有代码的基础上,实现功能的扩充.用原函数扩展新功能,用新功能去代替旧功能,用@表示

情况一: 基本用法(闭包函数),通过闭包函数来扩展新功能
def kuozhan(tree):
    def new_tree():
        print("旁边有小草")
        tree()
        print("旁边有小花")
    return new_tree

def tree():
    print("一棵大树")

tree = kuozhan(tree)
tree()
# 旁边有小草
# 一棵大树
# 旁边有小花

情况二:用@符号来表示装饰器,@符号自动把下面的函数传递给装饰器,把新函数返回,让新函数代替旧函数,以实现功能的扩充

def kuozhan(tree):
    def new_tree():
        print("旁边有小草")
        tree()
        print("旁边有小花")
    return new_tree

@kuozhan
def tree():
    print("一棵大树")

tree()
# 旁边有小草
# 一棵大树
# 旁边有小花

情况三:装饰器的嵌套

def kuozhan2(tree):
    def new_tree():
        print("小草会长成草坪5")
        tree()
        print("小花会长成花卉4")
    return new_tree

def kuozhan1(tree):
    def new_tree():
        print("旁边有小草3")
        tree()
        print("旁边有小花2")
    return new_tree

@kuozhan1 # 再到装饰器1,返回3,5,1,4,2
@kuozhan2 # 先到装饰器2,返回5,1,4
def tree():
    print("一棵大树1")

tree()
# 旁边有小草3
# 小草会长成草坪5
# 一棵大树1
# 小花会长成花卉4
# 旁边有小花2

情况四:用装饰器修饰带有参数的函数,装饰器内的函数也需有一一对应的参数

def kuozhan(tree):
    def new_tree(name):
        print("{}旁边有小草".format(name))
        tree(name)
        print("旁边有小花")
    return new_tree

@kuozhan
def tree(name):
    print("{name}有一棵大树".format(name=name))

tree("bob")
# bob旁边有小草
# bob有一棵大树
# 旁边有小花

情况五:用装饰器修饰带有参数返回值的函数

def kuozhan(person):
    def new_person(*args,**kwargs):
        print("新学期的开始")
        lst = person(*args,**kwargs)
        print("大家加油")
        return lst
    return new_person

@kuozhan
def person(*args,**kwargs):
    list1 = ["bob","alice","jack"]
    for i in args:
        print("班主任是:"+i)
    return [(k,v) for k,v in kwargs.items() if k in list1 ]
res = person("张三","李四",bob=18,alice=19,jack=20,lisa=21)
print(res)
# 新学期的开始
# 班主任是:张三
# 班主任是:李四
# 大家加油
# [('bob', 18), ('alice', 19), ('jack', 20)]

情况六:用类装饰器来拓展原函数

# 方式一: 用类.方法来调
class Kuozhan():
    def kuozhan1(tree):
        print("大树旁边有小草")
        tree()
        print("大树旁边有小花")

@Kuozhan.kuozhan1
def tree():
    print("我是一颗大树")
# 大树旁边有小草
# 我是一颗大树
# 大树旁边有小花

# 方式二: 直接用类()调,配合__call__方法
class Kuozhan():
    def __call__(self,tree):
        return self.kuozhan2(tree)
    
    def kuozhan1(tree):
        print("大树旁边有小草")
        tree()
        print("大树旁边有小花")
        
    def kuozhan2(self,tree):
        print("小草长大成草坪")
        tree()
        print("小花长大成花卉")

@Kuozhan()
def tree():
    print("我是一颗大树")
# 小草长大成草坪
# 我是一颗大树
# 小花长大成花卉

情况七:带有参数的函数装饰器

def outter(num):
    def kuozhan(func):
        def new_tree(self):
            print("大树小的时候是小树")
            res = func(self)
            print("小树长大了是大树")
            return res

        def new_grass(self):
            print("小草小的时候是一棵草")
            res = func(self)
            print("小草长大了是草坪")
            return res

        if num == 1:
            return new_tree
        elif num == 2:
            return new_grass
        elif num == 3:
            return "我把flower方法变成了属性"
    return kuozhan


class Plant():
    @outter(1)
    def tree(self):
        print("我是一颗大树")

    @outter(2)
    def grass(self):
        print("我是一颗小草")

    @outter(3)
    def flower(self):
        print("我是一朵花")

obj = Plant()
obj.tree()
# 大树小的时候是小树
# 我是一颗大树
# 小树长大了是大树
obj.grass()
# 小草小的时候是一棵草
# 我是一颗小草
# 小草长大了是草坪
print(obj.flower)
# 我把flower方法变成了属性

情况八:带有参数的类装饰器

class Kuozhan():
    name = "大树"
    def __init__(self,num):
        self.num = num
    def __call__(self,cls):
        if self.num == 1:
            return self.new_func1(cls)
        elif self.num == 2:
            return self.new_func2(cls)
    def grass(self):
        print("大树旁边有小草")

    def new_func1(self,cls):
        def func1():
            cls.name = Kuozhan.name
            cls.grass = Kuozhan.grass
            return cls()
        return func1

    def new_func2(self,cls):
        def func2():
            if "mytree" in cls.__dict__:
                res = cls.mytree()
                cls.mytree = res
                return cls()
        return func2

# 形式一: 为类添加方法或者属性
@Kuozhan(1)
class Tree():
    def mytree():
        return "我是一颗大树"
obj = Tree()
print(obj.name) # 大树
obj.grass() # 大树旁边有小草

# 形式二: 将类的方法改为属性
@Kuozhan(2)
class Tree():
    def mytree():
        return "我是一颗大树"
obj = Tree()
print(obj.mytree) # 我是一颗大树
面向对象中的方法:  普通方法,绑定方法,静态方法
class Tree():
    #普通方法: 可以有参也可以无参,相当于普通的函数
    def grow():
        print("小树长成大树")

    # 绑定方法: (对象) 自动传递参数为对象
    def green(self):
        print("大树有成片的绿叶子")

    # 绑定方法: (类) 自动传递参数为类
    @classmethod
    def sing(cls):
        print(cls)
        print("风吹叶子的声音像唱歌")

    # 静态方法: 不管是对象还是类,都可以调用,默认不会传递任何参数
    @staticmethod
    def air():
        print("大树可以净化空气")
obj = Tree()
Tree.grow() # 小树长成大树

obj.green() # 大树有成片的绿叶子  绑定方法推荐用对象调
Tree.green(111) # 大树有成片的绿叶子

Tree.sing()  # 绑定到类的方法推荐用类调
# <class '__main__.Tree'>
# 风吹叶子的声音像唱歌
obj.sing()
# <class '__main__.Tree'>
# 风吹叶子的声音像唱歌

# 静态方法有参数时保证参数一一对应.在类外,为对象添加的方法都是静态方法
Tree.air() # 大树可以净化空气
obj.air() # 大树可以净化空气
porperty装饰器:
        功能: 将方法变成属性使用,自动触发
        作用: 控制属性的获取(@property),设置(@属性名.setter),删除(@属性名.deleter)操作
        意义: 间接增加成员的安全性,可以通过自定义逻辑对成员进行控制

# 方式一: 使用相同的名称
class Myname():
    def __init__(self,name):
        self.name = name
    # 获取属性
    @property
    def username(self):
        return self.name
    #设置属性
    @username.setter
    def username(self,strval):
        self.name = strval
    #删除属性
    @username.deleter
    def username(self):
        pass
obj = Myname("bob")
print(obj.name) #bob 自动触发property

obj.name = "alice"
print(obj.name) #alice  自动触发设置方法,strval接收alice

del obj.username
print(obj.name) # alice  因为自动触发的删除属性,阻止了删除

# 方式二:
class Myname():
    def __init__(self,name):
        self.name = name
    # 获取属性
    @property
    def get_username(self):
        return self.name
    #设置属性
    def set_username(self,strval):
        self.name = strval
    #删除属性
    def del_username(self):
        pass
    username = property(get_username,set_username,del_username)
obj = Myname("bob")
print(obj.name)  # bob

obj.name = "jack"
print(obj.name)  # jack

del obj.username
print(obj.name) # jack

 
posted on 2020-06-01 19:51  fdsimin  阅读(124)  评论(0编辑  收藏  举报