装饰器:在不改变原有代码的情况下,为该原函数扩展新功能
特征:返回新函数,替换旧函数
语法:@ 语法糖

1.装饰器原型

#例1:

def kuozhan(func):
    def newfunc():
        print("吃饭前,无精打采")
        func()
        print("吃饭后,精神百倍")
    return newfunc
def func():
    print("我是个吃货")
#手动的 把新函数 赋值 给 旧函数
func = kuozhan(func)
func()

2.装饰器 @

#例 2:

print("=====例2=====")
def kuozhan(func):
    def newfunc():
        print("吃饭前,无精打采")
        func()
        print("吃饭后,精神百倍")
    return newfunc
@kuozhan
def func():
    print("我是个吃货")
func()
print("=================")
步骤解析:
第一步:先把下面的func当成参数传递给kuozhan
第二步:把返回的新函数重新赋值给func
* 谁跟在@ 这个装饰器的下面,就会自动把谁当成参数传递
func = kuozhan(func)

3.互相嵌套的装饰器函数

#例3:
def kuozhan1(func):
    def newfunc():
        print("吃饭前前,化化妆1")
        func()
        print("吃饭后,补补妆2")
    return newfunc
def kuozhan2(func):
    def newfunc():
        print("吃饭前,洗洗手3")
        func()
        print("吃饭后,簌簌口4")
    return newfunc
@kuozhan2
@kuozhan1
def func():
    print("我是一个白富美5")
func()  #3 1 5 2 4

4.带有参数的装饰器

原函数在扩展之前是几个参数,那么扩展之后也相应有几个参数

#例4:
def kuozhan(func):
    def newfunc(who,where):
        print("开饭前,安安静静")
        func(who,where)
        print("开饭后,热热闹闹")
    return newfunc

@kuozhan
def func(who,where):
    print("{}进{}吃饭".format(who,where))

func("one","食堂")

5.带有参数返回值的装饰器

'''通过装饰器改造之后,原函数返回什么,新函数返回什么'''
print("=================")
#例5:

def kuozhan(func):
    def newfunc(*args, **kwargs):
        print("留下之前")
        res = func(*args, **kwargs)
        print("留下之后")
        return res

return newfunc

@kuozhan
def func(*args, **kwargs):
    print(args)
    for i in args:
        print("藏东西的地点:", i)
    dic = {'p1': "one", "p2": "two"}
    '''

#法一:for循环再将元素加入列表得到:
    lst = []
    for k,v in dic.items():
        #如果k在dic这个字典里,说明这个字典存在这个键,然后我就通过键取值
        if k in dic:
        lst.append("{}留下了黄金{}".format(dic[k],v))

'''

#法二:推导式方法得出:
    lst = ["{}留下了黄金{}".format(dic[k], v) for k, v in kwargs.items() if k in dic]
    return lst
res = func("电影院", "游泳池", p1="15克", p2="150克")
print("=================")
print(res)
print("=================")

回忆以前的知识点:
*  ** 的魔术方法(函数调用处)
#例:

def func(a,b,c):
    print(a,b,c)

func(*[1,2,3])

def func(a=1,b=2,c=3,*,d=4):
    print(a,b,c)

func(**{"a":3,"b":4,"c":5,"d":6})

6.用装饰器修饰原函数

#例6:

class MyClass():

def __call__(self,func):
        #pass
        return self.kuozhan2(func)
    def kuozhan1(func):
        def newfunc():
            print("酒店前,饥肠辘辘")
            func()
            print("酒店后,酒足饭饱")
        return newfunc
    def kuozhan2(self,func):
        def newfunc():
            print("酒店前,茶饭不思")
            func()
            print("酒店后,大肚偏偏")
        return newfunc
#方法一
@MyClass.kuozhan1
def func():
    print("吃饭进行时...  ....")
func()
#方法二:
@MyClass()
def func():
    print("吃饭进行时... ...")
func()

#代码解析:
先把 @ 符号右边的值算出来,在通过 @ 符号把下面的函数当成参数进行传递
@MyClass() 就相当于 @obj
func当成参数传递给obj => obj(func)
obj 当成一个函数再进行调用,自动触发__call__魔术方法
return newfunc
func = newfunc
func() 就相当于 newfunc()

7.带有参数的函数装饰器

#例7:

def outer(num):
    def kuozhan(func):
        def newfunc1(self):
            print("人前,老实巴交")
            func(self)
            print("人后,张牙舞爪")

def newfunc2(self):
            print("人前,衣冠楚楚")
            func(self)
            print("人后,衣冠禽兽")

if num == 1:
            return newfunc1
        elif num == 2:
            return newfunc2
        elif num == 3:
            return "今天天气好晴朗哦"
    return kuozhan

class MyClass():
    @outer(1)
    def func1(self):
        print("走一步")
    @outer(2)
    def func2(self):
        print("再走一步")
    @outer(3)
    def func3(self):
        print("换个角度想想")
print("=================")
obj = MyClass()
obj.func1()
print("=================")
obj.func2()
print("=================")
print(obj.func3)

#代码解析:
outer(1)  => 返回kuozhan 函数
@kuozhan
func1

@符号开始发挥作用
func1当成参数进行传递,传给kuozhan中的func进行接收
obj.func1 = newfunc1
obj.func1() <====>newfunc1

@outer(3) => 返回kuozhan 函数
@kuozhan
func3
@符号开始发挥作用
func3当成参数进行传递,传给kuozhan中的func进行接收
obj.func3 = "今天天气好晴朗哦"
print(该值) [因为函数名可以作为变量使用]

8.带有参数的类装饰器

如果传递的参数是1 ,我就为该类,添加成员属性和方法
如果传递的参数是2,我就把该类当中的run方法变成属性
#例8:
class KuoZhan():
    ad = "高档餐厅,欢迎您来,欢迎您再来"
    def __init__(self,num):
        self.num = num

def __call__(self,cls):
        if self.num == 1:
            return self.kuozhan1(cls) #newfunc 返回
        elif self.num == 2:
            return self.kuozhan2(cls)

def money(self):
        print("收费标准,最低消费每人500")

def kuozhan1(self,cls):
        def newfunc():
            #添加成员属性
            cls.ad = KuoZhan.ad
            #添加成员方法
            cls.money = KuoZhan.money
            return cls()
        return newfunc
    def kuozhan2(self,cls):
        def newfunc():
            #先判断run方法是否在cls当中
            if "run" in cls.__dict__:
                #调用一个类中得run方法拿到返回值"亢龙有悔"
                res = cls.run()
                #成员属性run从方法变成属性,值替换了
                cls.run = res #把"亢龙有悔" 进行替换赋值给run成员属性
            return cls()
        return newfunc

@KuoZhan(1) # @obj = > obj(MyClass)
class MyClass():
    def run():
        return "亢龙有悔"
obj = MyClass()
print(obj.ad)
obj.money()

"""

#代码解析:
KanZhan(1) => obj 自动触发init方法 ,存储num => self.num = num
@obj
@符发挥作用把MyClass 当成一个参数传递给obj => obj(MyClass)
触发__call__ 魔术方法,最后将newfunc进行返回
MyClass = newfunc 以前是类 现在是函数
obj = MyClass <========> newfunc()
obj = cls() #cls() 是一个对象,是以前MyClass 这个类的对象
"""
@KuoZhan(2)
class MyClass():
    def run():
        return "亢龙有悔"

obj = MyClass()
print(obj.run)
print("=====================================")
#外面全局的abc 与函数内部局部的 abc 两者不发生冲突,彼此独立
class abc():
    a = 19
def func(cls):
    cls.b = 20
    return cls
obj2 = func(abc)
print(abc().a)
abc = 68970
print(abc)
print(obj2.b)
print(obj2.a)

Python 基础之面向对象之八步理解装饰器的更多相关文章

  1. python基础之:九步认识装饰器

    step1. 先看个代码吧: def f(): ') f=lambda a:a +100 #覆盖上面的函数f print(f) #函数名指函数所在内存中的位置,入带后面括号表示执行函数 print(f ...

  2. python基础之迭代器、生成器、装饰器

    一.列表生成式 a = [0,1,2,3,4,5,6,7,8,9] b = [] for i in a: b.append(i+1) print(b) a = b print(a) --------- ...

  3. 7th,Python基础4——迭代器、生成器、装饰器、Json&pickle数据序列化、软件目录结构规范

    1.列表生成式,迭代器&生成器 要求把列表[0,1,2,3,4,5,6,7,8,9]里面的每个值都加1,如何实现? 匿名函数实现: a = map(lambda x:x+1, a) for i ...

  4. python基础-第五篇-5.3装饰器

    小白发呆的看着窗外,同事们陆陆续续的地来到公司,想起算法,小白就飘飘然了.突然后面传来一声呼唤,原来是小刘! 小刘:不好意思啊!堵车了,就来晚了点,不耽误你的时间,咱们就开启的今天的培训内容吧! 小白 ...

  5. Python基础4 迭代器,生成器,装饰器,Json和pickle 数据序列化

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  6. python 基础学习笔记(8)--装饰器

    **装饰器** - [ ] 装饰器和闭包有很大的联系.有时你需要在不改变源代码的情况下修改已经存在的函数.装饰器的运用可以提高效率,减少重复的代码. - [ ] 装饰器的实质是一个函数.它把一个函数作 ...

  7. python基础学习之描述符和装饰器

    描述符的了解: 描述符协议: python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有: __get__, __set__, 和__ ...

  8. python基础知识---迭代器、生成器、装饰器

    一.迭代器 二.生成器 http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html def func(): #定义生成器,和普通函数的区别是 ...

  9. python基础语法7 闭包函数与装饰器

    闭包函数: 1.闭包函数必须在函数内部定义 2.闭包函数可以引用外层函数的名字 闭包函数是 函数嵌套.函数对象.名称空间与作用域 结合体. # 直接传参 def func(x): print(x) f ...

随机推荐

  1. 8.10-Day2T2 吃喝大法好

    题目大意 略... 题解 开始两个人一定是一个向右走一个向下走,向右走的人最终会走到(n-1,m),向下走的人一定会走到(n,m-1). 那么不考虑重复的话总的路径数就是从(1,2)到(n-1,m)的 ...

  2. buuctf

    大白 | png图片改高度png图片改高度[外链图片转存失败(img-PojN2D3v-1567086301372)(evernotecid://74A3E6DA-E009-4797-AA60-5DE ...

  3. windows cmake与nmake

    在Linux下编库经常会使用CMakeLists.txt文件,然后一个cmake 再一个make就可以编译出来. 在Windows下有cmake,但是cmake出来是一个Visual Studio工程 ...

  4. 洛谷P1044栈(DP)

    题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即poppoppop(从栈顶弹出一个元素)和pushpushpush(将一个元素进栈) ...

  5. Go性能调优

    文章引用自   Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 pr ...

  6. redis位图命令

    概述 redis 的位图就是01的数据格式,redis 主要做有写入,读取和统计.位图相关的命令 : 其中set和get就是 read 和writer , bitcount 统计相关,bitop 是对 ...

  7. springBoot日志快速上手简单配置

    默认配置 日志级别从低到高分为: TRACE < DEBUG < INFO < WARN < ERROR < FATAL. 如果设置为 INFO ,则低于 INFO 的信 ...

  8. 创业学习---《调研黑客上:锁定调研目标》--D-2.调研模块---HHR计划---以太一堂

    第一,开始学习: 思考题: (1)你的项目有哪些值得关注的竞争对手?为什么是这些,你是如何分类的? (2)拿出其中一个产品,你会怎么分析他? 第一,<明确调研目标>(补充) 1,调研4大类 ...

  9. Bugku-CTF加密篇之贝斯家族(@iH<,{bdR2H;i6*Tm,Wx2izpx2!)

    贝斯家族 @iH<,{bdR2H;i6*Tm,Wx2izpx2!  

  10. Win下PHP5.6版本安装redis扩展

    首先说一下自己的环境啥的,我用的是phpstudy,其实没啥大用,就是看你的php版本啥的 1.运行phpinfo(),查看php的信息,php的位数和扩展信息,和要下载的扩展文件信息有关, 2.下载 ...