回顾

一个完整的闭包函数要满足那些条件
1,函数里面套函数
2,外层函数返回的事内层函数的函数名
3,内层函数有对外部非全局变量的引用

多个装饰器并存

多个装饰器装饰同一个类,方法的时候,装饰器的加载和执行是什么样子的呢?

  1. @login_check
  2. @timer
  3. def func():
  4. print("被装饰的函数")

多个装饰器装饰同一个方法的时候,按照从下往上装饰的顺序
运行的时候从上往下执行。
即 从下往上装饰,从上向下执行。

python的内置装饰器三大件儿

classmethod

  1. @classmethod 被该装饰器装饰之后该方法就是一个类方法<br />被装饰之后方法就不能在写self的形参了,因为self代表实例本身,而变成类方法之后不能用self来代表类本身。<br />需要用cls来代替selfcls代表类本身,self代表实例本身。<br />**类方法可以直接通过类调用,无需实例化**

staticmethod

静态方法 静态方法默认是没有参数的,
加上之后就是一个静态方法,表示不经过实例化即可使用,类和实例均可调用

prperty

设定只读属性。装饰之后只可读儿不能修改,后面进行访问的时候也只能读取。
调用的时候可以直接像调用属性一样调用,
注意: 不可以通过类来调用,需要通过实例进行调用。

  1. @property # 设定只读属性
  2. def read_attr(self): # 只可读不能进行更改,后面访问的时候只能读取
  3. print("这个装饰器装饰完了之后该方法可以像属性一样被调用")
  4. return "年龄18岁" # 调用的时候可以直接调用属性一样来调用
  5. print(t.read_attr) # t为实例化之后产生的对象

调用关系
类不可以调用实例方法,可以直接调用类方法,静态方法
类属性可以被实例方法调用。

魔术方法

python中有趣的玩意儿很多,魔术方法是一个大类。
什么是魔术方法?
python中双下划綫开头,双下划綫结尾。
自定义方法的时候不要使用魔法方法命名方式。
抛出一个问题,我们常写的init方法有什么作用?是不是实例化对象时最先运行的方法。

实例化类的过程

实例化类的时候会自动调用init方法。但是第一个执行的方法并非init。
new方法是在init方法之前执行的,这个方法在所有类的祖宗 object类里面。
object是所有类的祖宗,所有类默认继承object

重写new方法

知道这一点后,我们可以在类实例化的时候重写new方法,加载一些私货进取。

  1. class MyClass(object):
  2. def __init__(self, name):
  3. self.name = name
  4. def __new__(cls, *args, **kwargs):
  5. print("这个是new方法")
  6. return super().__new__(cls)

此处穿插一下,子类中调用父类方法的方式 super().method or 父类.父类mehtod 两种调用方式去调用。
那么学会重写new方法有什么运用呢?

单例模式

什么是单例模式?
不管实例化多少次,只返回第一次创建的对象,即可得到这个对象中所有设置的属性和方法,不会因再次实例化而发生丢失。
需求:类每次实例化都会创建一个新的对象,如果要求类只能被实例化一次,就用到了单例模式

单例模式的实现思路

new方法在init之前执行。
通过重写new方法来对实力次数进行一个判断,如果已经创建,则不再进行重新创建对象,只返回第一次创建的对象,实现单例模式。
代码思路,设置一个类属性instance为None,重写new方法并在new方法体内对instance进行判断,如果为none就实例化,如果非none就调用父类的new方法吧对象赋值给instance

  1. # 单例模式
  2. class MyTest(object):
  3. instance = None # 设置一个类属性,用来记录这个类有没有创建过对象
  4. def __new__(cls, *args, **kwargs):
  5. # 判断instance是否等于none
  6. if not cls.instance:
  7. cls.instance = super().__new__(cls)
  8. return cls.instance
  9. else: # 如果已经创建,不是空,就返回原 就直接返回原对象
  10. # 返回对象
  11. return cls.instance

魔术方法三连 str,repr,call

思考一个问题,在python中print打印,与交互式变成直接打印有什么区别
使用print打印的时候触发的事str方法,使用交互式的时候触发的事repr方法
print方法打印出来的多是给用户看的,repr这种交互式更多是方便程序员去查看数据类型

当然str也可以进行重写,用来返回一些提示信息
重写str,repr方法时一定要写返回值,且返回值必须为字符串

str方法的触发

直接打印实例的时候会触发
str方法处理实例的时候会触发
format处理实例也会被触发

repr方法的触发

repr方法处理实例的时候会触发

总结

使用str函数或者print打印对象时会优先触发去寻找str方法,没定义str方法的情况下会去找repr方法,如果都没有,就会去找父类的str方法。
str—->repr—->object.str
使用repr方法或者交互环境下输入变量,会先寻找自身的repr方法,没有的话会去找父类的repr方法

Call方法

都说python中万物接对象,函数也是对象,那么为什么函数可以加个括号就直接调用,而其他对象不能呢?
进一步说,如果想让吧类实力出来的对象也可以像函数方法一样加个括号就可以调用,需要怎么实现?
答案是通过call方法就可以实现上面的需求。

  1. class MyClass1():
  2. def __init__(self, name):
  3. self.name = name
  4. def __str__(self): # 重写 str 和repr 方法时必须要写返回
  5. print("hhhhhh")
  6. return "str方法的返回值"
  7. def __repr__(self): # 且返回的必须是一个字符串对象
  8. print("233333")
  9. return "repr方法的返回值"
  10. def __call__(self, *args, **kwargs):
  11. print("像函数被调用的时候一样被出发")
  12. # str方法有三种方式出发
  13. # 直接打印实例,str方法处理实例,format处理实例
  14. m = MyClass1("adi")
  15. print(m)
  16. # repr(m) repr处理实例的时候会出发repr的魔法方法
  17. repr(m)
  18. m()