• 描述符的了解:

    描述符协议:

    python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有:

    __get__, __set__, 和__delete__

    如果这些方法中的任何一个被定义在一个对

    象中,这个对象就是一个描述符

  • 总结下说人话:就是当一个类中实例化另一个类的时候,通过本类来调用另一个类的功能,控制实例对象 访问 这个属性做一些额外的操作

    class Fee:       #先定义一个Fee类
        def __get__(self, instance, owner):
            print('get:疏楼龙宿人间至帅')
        def __set__(self, instance, value):
            print('set:疏楼龙宿%s'%value)
        def __delete__(self, instance):
            print('delete:疏楼龙宿人间无敌')

    class Fdd:      #在定义一个类Fdd
        fee = Fee()    #我们在Fdd中实例化Fee

  • 我们可以通过Fdd实例化来调用Fee中功能,如何实现呢?

  • a = Fdd()     #先实例化,接下来我们需要了解功能的对应调用情况

    a.fee       # 即调用fee属性,fee属性是什么,就是Fee实例化,这时候会触发__get__功能

    a.fee = '人间至帅'             #即对fee属性进行修改,会触发类Fee中的__set__功能,将修改内容传入参数value

    del a.fee         # 删除a实例化中fee属性,就是要删掉Fee(),会触发Fee类中__delete__属性

装饰器:重点啊重点啊重点啊!

    • 什么是装饰器?

      装饰器本质上也是函数,他是用来修饰其他函数,给其他函数添加额外功能的

    • 装饰器原则:

      1--不改变被修饰函数的源代码

      2--不改变被修饰函数的调用方式

    • 装饰器的本质是什么?

      高阶函数+函数嵌套+闭包

    • 我们回顾下,什么是高阶函数?

      --函数接受的参数是另一个函数的函数名

      --函数的返回值另一个函数的函数名

      满足上述两个条件中的一个,可以称为高阶函数

      【注意:如果返回值是这个函数本身的调用方式,那么这是递归!】

    • 我们再回顾下,什么闭包?

      就是函数的返回值是其内部嵌套函数的函数名

    • 按照上述的规则,我们来推导下装饰器应该是什么样子

    • 比如,我们需要测试一下isinstance()这个函数的运行时间

      首先,根据原则要求,我们不能改变被修饰函数的源代码,也就是说,isinstance()函数写完后要放在一边,我们先写一个运行代码:

    • def test_isinstance():
          for i in range(0,100000):
              if isinstance(i,int) is True:
                  pass
          pass

      由于一次运行的时间太短,我们运行10W次,

      按照原则1,这个时候,这个代码就不能动了,我们应该如何测试他的时间呢?

    • 导入时间模块包,写一段高阶函数,将上述函数传入其中作为参数,在运行前,记录下时间,然后运行该函数,运行完,再记录下时间,做个差运算,得出时间差,即运行时间

      import time
      def test_time(fun):
              star_time = time.time()
              fun()
              stop_time = time.time()
              run_time = stop_time - star_time
          print('运行时间是%s' %run_time)

    • OK,我们已经完美的得出了运行时间,而且源代码也没动

    • 那么问题来,函数调用方式,按照test_isinstance()的方式调用,我们没有得到运行时间。。。。。如果要同时得到结果,我们就要使用test_time(test_isinstance)这个方法,和原则2冲突

    • 到目前为止,我们已经解决了需求问题,即测试代码运行时间,那么如果进一步使调用方式不变呢?我们想到了高阶函数中的返回函数名,如果我返回值是需要测试的函数的函数名呢?

    • 代码:

      def test_isinstance():
          for i in range(0,100000):
              if isinstance(i,int) is True:
                  pass
          pass

      import time
      def test_time(fun):
          star_time = time.time()
          fun()
          stop_time = time.time()
          run_time = stop_time - star_time
          print('运行时间是%s' %run_time)

      return test_isinstance

    • 这个时候,我们再做如下操作:

      test_isinstance = test_time(test_isinstance)

      问题似乎解决了,我直接使用就可以得到结果

    • 至此,我们已经得到了 装饰器的雏形,至于最后一部复制问题,装饰器的格式,可以解决,又称为 语法糖

      @test_time

      def test_isinstance():

      .......

      .......

      最开的时候@test_time的功能效果即是:

      test_isinstance = test_time(test_isinstance)

    • 仔细检查后,发现我们似乎运行了两次test_isinstance函数?

      test_time中运行了一次,接受返回函数名后我们加上括号,又运行了一次,问题来了,这下怎么办?

    • 遇到问题,解决问题,多运行了一次,我们看看能不能少运行一次

      常规手段无法达成目的,我们回忆下装饰器的的本质是什么

      高阶函数(已有)+函数嵌套(无)+闭包(无)

      我们还有其他手段可以用,比如函数嵌套,和闭包

    • 我们要实现的终极目的是test_isinstance()的同时会让上述的两个函数都运行一次,且只运行一次,而且,要获得原函数结果,上述test_time函数已经可以获得时间,同时喊运行了一次test_isinstance函数,如果我们截取下他内部test_isinstance的运行结果,作为本函数的返回值呢?

      import time

      def test_time(fun):
          star_time = time.time()
          res = fun()
          stop_time = time.time()
          run_time = stop_time - star_time
          print('运行时间是%s' %run_time)

      return res

      我们可以发现,运行这个函数,我们可以得到和运行test_isinstance函数一样的结果,因为返回值就是他的运行结果

    • 我们似乎离真相越来越近了

    • 如同上面说的一样,我们需要test_isinstance()的时候,让函数运行一次,而不是两次,函数运行是加括号直接运行,少运行一次,我们就要少一个括号,即test_isintance的时候不运行,test_isintance上面我们等于了 test_time(test_istntance),也即是,这个时候,我不运行函数,等加上括号的时候,在运行函数,兼顾上述我们测试出来所需要的所有功能【增加附加功能,获取本函数原返回值】

    • 经过思考和测试,使用闭包功能

      import time
          def test_time(fun):
              def test():
                          star_time = time.time()
                          res = fun()
                          stop_time = time.time()
                          run_time = stop_time - star_time
                  print('运行时间是%s' %run_time)
                  return res
              return test

    • 解释代码:

      在测试函数上挂上@test_time,即:test_isintance = test_time(test_isintance),这个时候,同等于test_isintance=test【因为装饰器函数test_time的返回值是test,test为内嵌函数】;当test_isintance加上括号()运行的时候,等于运行了test()然后会进行下面一系列操作,同时,会返回原函数的返回值。

    • 至此,装饰器函数出炉了。

    • 增加问题:

      如果我函数本身就有参数呢。。。。。。。

      比如:test_isintance(1,2,3,4,5)

      这个等于什么?不就等于 test(1,2,3,4,5) 么!

      也就是说我内嵌函数中,有可能会有参数!代码,需要普适性,这种情况也需要考虑进去!参数形式能确定么?似乎不能,同样,我们也不应该根据测试函数的参数特点再去修改函数。

    • 我们需要把参数传给,那么函数参数形参和实参的赋值关系主要分为哪几类?

      位置参数、关键字参数,即*args **kwargs,我们在test_isintance的括号内加上参数,也就是在test的括号内加上参数,可能是0个,可能是若干个,*args和**kwargs完美接收了上述参数,在原本的函数test_isintance()的参数传给test()后,再由test在代码块内部传给test_isintance()【即代码中的fun()】

    • 最后我们的代码应该如下:

    • import time
      def test_time(fun):
          def test(*args,**kwargs):
                      star_time = time.time()
                      res = fun(*args,**kwargs)
                      stop_time = time.time()
                      run_time = stop_time - star_time
              print('运行时间是%s' %run_time)
              return res
          return test

    • 至此,装饰器完全体

    • 使用方式:在上述代码已经提前写好的情况下,使用语法糖即可

    • @test_time

      def test_isinstance():
          for i in range(0,100000):
              if isinstance(i,int) is True:
                  pass
          pass

python基础学习之描述符和装饰器的更多相关文章

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

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

  2. Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)

    Python:高级主题之(属性取值和赋值过程.属性描述符.装饰器) 背景 学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同.还有词法作用域这个东西,这也是我学习任何一门语 ...

  3. 【python】闭包、@修饰符(装饰器)、

    闭包:(返回函数的行为叫闭包??) #函数也是对象,所以可以被传递 def line_conf(a,b): def line(x): return a*x+b return line line1=li ...

  4. python基础学习1-描述符

    #!/usr/bin/env python # -*- coding:utf-8 -*- #描述符就是将某种特殊类型的类的实例指派给另一个类的属性 #特殊类型指 实现了 # __get__(self, ...

  5. Python__new__方法、定制属性访问、描述符与装饰器

    __new__方法的运行顺序 装饰器的概念的用法 三个内置装饰器 类中属性的访问过程 __new__方法 创建实例的方法 __new__方法是在类创建实例的时候自动调用的 实例是通过类里面的__new ...

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

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

  7. 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 ...

  8. 潭州课堂25班:Ph201805201 第十二课 new方法,定制属性访问,描述符与装饰器 (课堂笔记)

    1,new方法: 类每次实例化时都会创建一个新的对象, class Textcls: # cls 是指类本身, def __new__(cls, *args, **kwargs): # 在 __ini ...

  9. 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) --------- ...

随机推荐

  1. woj1013 Barcelet 字符串 woj1014 Doraemon's Flashlight 几何

    title: woj1013 Barcelet 字符串 date: 2020-03-18 18:00:00 categories: acm tags: [acm,字符串,woj] 字符串,字典序. 1 ...

  2. virtualBox 设置增强功能粘贴和拖放

    virtualBox 5.2.8 (在运行的虚拟里中) 设备 -> 安装增强功能 virtualBox 管理器中设置(要在虚拟机关机的情况下配置) 常规 -> 高级里设置双向粘贴和拖放

  3. vue 单文件组件最佳实践

    vue 单文件组件最佳实践 生命周期 template <template> <section> <h1>vue single file components te ...

  4. Semantic Pull Requests All In One

    Semantic Pull Requests All In One https://github.com/zeke/semantic-pull-requests docs: Update direct ...

  5. O&#178; & O₂

    O² & O₂ special symbol O² & O₂ HTML HTML subscript and superscript Tags HTML 下标元素 HTML 上标元素 ...

  6. node.js & fs & file read & file write

    node.js & fs & file read & file write https://nodejs.org/api/fs.html const fs = require( ...

  7. CSS Modules in depth

    CSS Modules in depth https://github.com/css-modules/css-modules https://webpack.js.org/loaders/css-l ...

  8. NGK公链存储技术,如何开创应用落地新格局?

    尽管无人预测未来,但是资本的眼光总是那么灵敏,最近几年,国际资本市场纷纷将目光投到了公链市场上.从TPS高点备受抢占,再到DApp生态的不断涌现,再到目前Staking和Defi的新概念生态的不断发力 ...

  9. Baccarat项目专用代币BGV的价值如何?

    NGK投资者对于NGK平台自身的DeFi项目呼声越来越高,经过数月的紧张研发,检验和内测工作,NGK官方将于近日推出其去中心化金融项目--Baccarat,此项目为避免以太坊易被攻击,网络拥堵出块慢以 ...

  10. 云原生系列5 容器化日志之EFK

    上图是EFK架构图,k8s环境下常见的日志采集方式. 日志需求 1 集中采集微服务的日志,可以根据请求id追踪到完整的日志: 2 统计请求接口的耗时,超出最长响应时间的,需要做报警,并针对性的进行调优 ...