1.对象是特征(属性)和技能(方法)的结合体
2.类是一系列具有相似特征和技能的对象的结合体
3.类在定义阶段就会执行类体代码,生成类的名称空间
类实例化时发生的事情
1.产生一个空对象
2.触发__init__方法,将空对象和需要的参数传入,为空对象的名称空间赋值
类中定义的函数本质都是绑定给对象使用的
1.不同对象就是不同绑定方法
2.绑定给谁,就应该由谁来调用,谁来调用就会把谁当做第一个参数传给对应的函数
继承 URL
一种新建类的方式,子类会继承父类的属性,可以减少代码的冗余
什么是什么的关系
python2
新式类:继承object类的类,以及该类的子类
经典类:没有继承object的类python3
类默认都继承object,所以python3中都是新式类,没有经典类
obj.mro() 可以查看类的查找顺序
属性查找
obj -> 父类 -> 父父类
经典类: 深度优先
新式类: 广度优先
引用父类中的属性
-
super()
专门用来引用父类的属性,依赖于继承,即使没有直接继承也会按照MRO继续查找
super(自己类名,self).__init__()
可以把super()看做是一个特殊的对象,这个对象调用__init__默认传入self, 所以往__init__()中传参时,不用写self
super严格按照mro表查找方法
-
指明道姓
这种方式与继承没有关系
class Teacher(People): def __init__(self,name,sex,age,title): People.__init__(self,name,age,sex) #调用的是__init__函数,因而需要传入self self.title=title
派生
子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找
组合
一个类中以另外一个类的对象作为数据属性,称为类的组合。组合与继承都是用来解决代码的重用性问题
组合是一种“有”的关系
封装 URL
对属性的封装:对象.属性 = 值
对方法的封装:类中定义的方法
私有属性
不想外界或obj访问就可以采用封装
私有的属性、方法,不会被子类继承,也不能被访问
1.只是语法意义上的变形,不能访问,这种变形只在定义阶段发生一次 (_类名__变量名)
2.封装对外不对内
3.在定义阶段封装语法就已经被扫描,类内用到的被封装的变量名统一变形,所以内部可以访问
多态 URL
多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪
多态性的本质在于不同的类中定义有相同的方法名---衍生出鸭子类型
1.多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象,这就需要在设计时,把对象的使用方法统一成一种:例如cat、dog、pig都是动物,
但凡是动物肯定有talk方法,于是我们可以不用考虑它们三者的具体是什么类型的动物,而直接使用
2.多态性的好处在于增强了程序的灵活性和可扩展性
高级用法
绑定方法与非绑定方法
1.类中定义的函数分为两大类:绑定方法和非绑定方法
2.其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。
-
classmethod
1.在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类。
2.类绑定方法通常用来在__init__的基础上提供额外的初始化实例的方式
-
staticmethod
为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法
总结绑定方法与非绑定方法的使用:若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法、需要引用类则将其定义成类方法、无需引用类或对象则将其定义成静态方法。
反射 URL
通过字符串操作类或对象的属性或方法
1.hasattr(obj, "key") 返回布尔值
2.getattr(obj, "key", default=None)
3.setattr(obj, "key", value)
4.delattr(obj, "key")
元类 URL
python中一切皆对象,类也是对象
认识元类真正的目的是自定义元类控制类的创建
1.类的类就是type
2.我们用class定义的类是用来产生我们自己的对象的
3.内置元类type是专门用来产生class定义的类
calss 类名 的时候就触发了type实例化出定义的这个类
实例化生成类的两种方法
- 方法一
class 类名:pass
-
方法二
type(类名, 基类, dict)
类的三大要素:
1.类名
2.基类:默认object
3.类体代码:即类的局部名称空间(__dict__)
类的名称空间里的变量在类定义阶段就生成,丢到了类的名称空间中(包括:属性变量,方法变量)
补充: exec(字符串形式代码, {}, {})
自定义元类
1.控制类的创建过程
2.控制类的实例化过程
metaclass
class Mymeta(type): # 控制类的创建过程 def __init__(self, calss_name, class_bases, class_dic): super(Mymeta,self).__init__( calss_name, class_bases, class_dic) # 控制类的实例化过程 def __call__(self, *args, **kwargs) # 1.产生一个空对象 obj = self.__new__(self) # 2.实例化该对象 self.__init__(obj,*args,**kwargs) # 3.返回该对象 return obj # Foo = Mymeta('Foo', (object,), class_dic) class Foo(object, metaclass=Mymeta): pass
场景:
自定义元类可以拿到类名,基类,类的名称空间,从而可以实现一些特定的功能,如往名称空间中添加键值对,判断类名是否符合首字母大写等
内置方法
双下划线的方法都是在达到某种条件时自动触发(内部自调用)
- __init__(self)
1.对象绑定方法
2.实例化对象时触发
场景:实例化对象时,会将 空对象和参数传给__init__
- __str__(self)
1.对象绑定方法
2.打印obj时触发
场景:可以自定义print(obj)打印结果
注意: 必须要有返回值,且是字符串类型
- __del__(self)
1.对象绑定方法
2.在对象被python系统回收之前触发,即:删除对象时
场景:脚本文件运行完python系统就会回收所有的变量,包括类的对象,如果此时在类中开启了一个需要操作系统才能回收掉的资源(如:发开文件),就需要在触发__del__函数体内将打开的文件关闭
- __call__(self, *args, **kwargs)
1.对象绑定方法
2.调用对象或调用类时触发,即:obj(),class 类名()
3.__call__的返回值就是obj
注意: class 类名() 时,触发的是元类中的__call__
发生了三件事:
1). 调用object.__new__ 得到一个空对象obj
obj=self.__new__(self)
2). 调用obj.__init__,将空对象和参数传进去
self.__init__(obj, *args, **kwargs)
3). 将obj return出来
return obj
场景: 用来自定义类的创建过程
- __doc__
类名.__doc__ 可以查看类中写的文档注释
- __new__(self)
类加括号时,用来产生一个空对象的
- __slots__
何禁止从外部修改实例属性
我们可以通过 __slots__ 来严格防止别人访问定义的实例属性
Python在存储实例的过程实际上是存储到 __dict__ 字典里
__slots_ 的作用就是一旦在类里定义了该属性,那么Python将再不会创建dict了,而是把实例属性存储到
__slots__ 里面(实际上是定义了一个描述器来存储)
- 用点访问属性时
__getattr__ 用点访问属性时 如果属性不存在时执行
__setattr__ 用点访问属性时
__delattr__ 用 del 对象.属性 删除属性时执行
- 用[ ]访问属性时
__getitem__ 当你用中括号取获取属性时 执行
__setitem__ 当你用中括号设置属性时 执行
__delitem__ 当你用中括号删除属性时 执行
单例模式 URL
python中分为函数(function)和方法(method),函数是python中的一个可调用对象(用户定义的课调用对象,及
lambda表达式创建的函数,都是函数,其类型都是Functiontype),方法是一种特殊的类函数
类方法和类进行绑定,实例方法与实例进行绑定,所以两者的类型都是method。
而静态方法,本身即不和类绑定,也不和实例绑定,不符合上述定义,所以其类型应该是function
如果一个类实现了 __call__ 方法,那么其实例也会成为一个可调用对象,其类型为创建这个实例的类,而不是
函数或方法