Fork me on GitHub

第十五章 new方法和装饰器

# 第十五章 new方法和装饰器
 
  Python入门共15章节,这是最后一章节了,【完结撒花】。这一章节比较特殊,知识难度大一点,在入门不需要百分比掌握,了解一下即可,以后学习Python进阶的时候,就翻回来看看。
## 一、new方法
### 1、new定义
  只有继承于object的新式类才能有__new__方法,__new__方法在创建类实例对象时由Python解释器自动调用,一般不用自己定义,Python默认调用该类的直接父类的__new__方法来构造该类的实例,如果该类的父类也没有重写__new__,那么将一直按此规矩追溯至object的__new__方法,因为object是所有新式类的基类。
  
一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 init()方法之前,Python首先调用new()方法:

 

 

 
下面用一个简单的案例说明:

 

 

- `__new__`至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供。
 
- `__new__`必须要有返回值,返回实例化出来的实例,这点在自己实现`__new__`时要特别注意,可以return父类`__new__`出来的实例,或者直接是object的`__new__`出来的实例。
 
 
### 2、new创建实例
  单例模式是一个经典设计模式,简要的说,一个类的单例模式就是它只能被实例化一次,实例变量在第一次实例化时就已经固定。
    
  在Python中常见的单例模式有None,这就是一个很典型的设计,通常使用 if xxx is None或者if xxx is not None来比较运算。

 

 

执行该结果,结果为:
 
 
- `_init__`有一个参数self,就是这个`__new__`返回的实例,`__init__`在`__new__`的基础上可以完成一些其它初始化的动作,`__init__`不需要返回值。
 
a = Base()该语句主要做了以下工作:
 
首先调用Base的__new__方法,该方法通过object.__new__(cls)创建了Base实例对象,并返回。最后调用了该Base实例对象的__init__方法。由结果得知a是Base类的实例.注意一个细节,Python解释器执行顺序,如果new()没有返回cls(即当前类)的实例,那么当前类的init()方法是不会被调用的。
 
### 3、new创建单例模式
  单例模式是一个经典设计模式,简要的说,一个类的单例模式就是它只能被实例化一次,实例变量在第一次实例化时就已经固定。单例模式是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
    
  在Python中常见的单例模式有None,这就是一个很典型的设计,通常使用 if xxx is None或者if xxx is not None来比较运算。
  

 

 

打印结果为:True True 。可见 a 和 b 都是同一个实例(实例 b 覆盖了实例 a)。
 
单例作用:
 
- 第一、控制资源的使用,通过线程同步来控制资源的并发访问;
- 第二、控制实例产生的数量,达到节约资源的目的;
- 第三、作为通信媒介使用,也就是数据共享。比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源。
 
应用场景:
 
- Python的logger就是一个单例模式,用以日志记录
 
- 线程池、数据库连接池等资源池一般也用单例模式
 
- Windows的资源管理器是一个单例模式
 
- 网站计数器
## 二、定制属性访问
### 1、如何判断一个实例里面有某个属性呢?
上一个案例里面,我们就是使用hasattr(实例,'属性')来判断属性是否在实例里面。
### 2、增删改查实例的属性值
下面就是增删改查实例的属性值:

 

 

 
接着,我们通过一个类的增删改查操作属性来熟悉这些方法:
 

 

 

注意:如果查找一个不存在的实例的属性,结果当然是报错,但是我不想看到系统反馈的一串错误,可以修改类。就在类里添加__getattr__方法。
 
 
### 3、描述符
如果在一个类中实例化另一个类,怎么访问这个被实例化的类呢?
 

 

 

执行该代码,结果为:
 

 

 

 
## 三、装饰器
  想要理解Python中的装饰器,不得不先理解闭包这个概念。闭包在第八章节《函数作用域》详细解说。简单来说,闭包可以理解为python得一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。  
 

 

 

msg是一个局部变量,在print_msg函数执行之后应该就不会存在了。但是嵌套函数引用了这个变量,将这个局部变量封闭在了嵌套函数中,这样就形成了一个闭包。
 
根据这个例子,认为闭包就是引用了自有变量的函数,这个函数保存了执行的上下文,可以脱离原本的作用域独立存在。
 
 
### 1、装饰器的定义
  python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
 
### 2、装饰器的作用
  装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
### 3、装饰器的案例
首先,根据闭包的特点,我们举一个闭包的案例:
 

 

 

这个闭包的逻辑比较绕,那么,引入装饰器,逻辑会不会就简易点呢?

 

 

### 4、内置装饰器
  property这个内建装饰器,它通常存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return的内容。
 
下面通过两个案例让你熟悉内置装饰器:@property、@staticmethod和@classmethod各自的作用。

 

 

 

 

 

 

 

### 5、类作为装饰器
  类也可以作为装饰器,但是需要定义__call__方法。

 

 

 
## 四、上一节课堂练习答案
 
#### 1、使用正则提取出字符串中的单词(s="""i love you not because of who 234 you are, 234 but 3234ser because of who i am when i am with you""")。
 

 

 

 
执行该代码,结果为:

 

 

 
#### 2、使用正则表达式匹配合法的邮件地址(s="""xiasd@163.com, sdlfkj@.com sdflkj@180.comsolodfdsf@123.comsdlfjxiaori@139.comsaldkfj.comoisdfo@.sodf.com.com""")。
 

 

 

 
执行该代码,结果为:
 

 

 

 
 
 
 
 
 
posted @ 2020-06-28 16:59  python终极者  阅读(212)  评论(0编辑  收藏  举报
AmazingCounters.com
页脚Html代码