概念
类:
类是对一群具有相同特征或行为的事物的一个统称,用来描述具有相同的属性和方法的对象的集合。
它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
是一个抽象的,没有实体的,负责创建对象的模板
实例化:
创建一个类的实例,类的具体对象。
对象:
通过类定义的数据结构实例。 对象包括两个数据成员(类变量和实例变量)和方法。
属性:
这一类对象的特征
方法:
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同, 类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
self 的名字并不是规定死的(因为是形参),也可以使用 this,但是最好还是按照约定是用 self。
私有属性:
两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。
私有方法
两个下划线开头,声明该方法为私有方法,只能在类的内部调用,不能在类地外部调用。
注意:其他语言定义成私有了是真正访问不到,但是python的私有只不过是进行了伪装而已。
当在类中定义私有成员时,在程序内部会将其处理成_类名 + 原有成员名称的形式。
也就是会将私有成员的名字进行一下伪装而已,如果使用处理之后的名字,还是能够进行访问的。
类变量:
类变量在整个实例化的对象中是公用的。
类变量定义在类中且在函数体之外。
类变量通常不作为实例变量使用。
实例变量:
在类的声明中,属性是用变量来表示的,
这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
继承:
即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样 一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a) "关系(例图,Dog是一个Animal)。
多继承
经典类的继承算法: 深度优先算法
新式类的继承算法: 广度优先算法
多态
子类和父类存在相同方法时,子类会覆盖父类方法,运行时总会调用子类方法–> 多态
方法重写:
如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
动态属性
Python提供了如下的内建函数,用来操作对象的属性。
hasattr(obj,name):
判断obj对象中是否存在name指定的属性名,存在返回True,否则返回False。
setattr(obj,name,value):
将obj对象的name属性设置为value值。相当于执行如下的操作:obj.name = value。如果name属性存在,则覆盖,如果不存在,则为对象obj新增name属性。
getattr(obj,name):
返回obj对象的name属性值,相当于执行如下的操作:obj.name。如果name属性值存在,则返回属性值,如果属性值不存在,返回default参数值,如果属性值不存在,default参数也不存在,则产生AttributeError。
delattr(obj,name,value):
删除obj对象的name属性。相当于执行如下的操作:del obj.name.如果指定的属性不存在,则会产生AttributeError。
# 新式类,定义一个类,并且继承object类,父类、基类、超类
class Teacher(object):
pass
# 经典类,参数列表中没有object
class Student():
# 类变量,可以被类中所有的实例方法调用,不作为实例变量使用
head = '天气真好'
# 构造方法,又称构造函数,初始化类的属性
# 当创建对象的时候, 自动执行的函数
# 在类下面,双下划线构成私有方法,只能被自身或子类访问
def __init__(self, name, age):
# 实例变量(用self修饰)
self.name = name
self.age = age
# 实例方法(实例函数)
def study(self):
print(self.name + '今年' + self.age + '岁了')
# 这个实例方法是调用上面play的实例方法
def to_study(self):
self.study()
# 类方法的装饰器
# 在类中, @开头的称为装饰器
# 装饰器本身也是个函数,在不影响原有功能基础上,增加新的功能
@classmethod
# 类方法,以cls修饰的方法,类方法的特性:单例模式
def func1(cls):
print('1')
# 也是个类方法,上面有@classmethod装饰的不一样
def func2(cls):
# 类方法变量
cls.value = 20
print(cls.value)
# 静态方法的装饰器
# 静态方法:写在类中的普通方法,能被实例方法和类方法调用,但是不能调用实例方法和类方法
@staticmethod
def func():
print('2')
# 当前对象销毁时调用这个方法,可以执行一些清理的工作
def __del__(self):
print("对象销毁")
# 使用内建函数str,format,print时调用,需要返回一个str类型的对象
def __str__(self):
return "Student类型对象"
# 在使用内建函数repr时调用,需要返回一个str类型的对象
# __str__与__repr__的区别:都返回字符串,__str__返回的是让人容易阅读的格式,__repr__通常返回
# 的是面向Python解释器的。当需要调用__str__的场合,没有定义__str__,就是要__repr__替代
def __repr__(self):
return "<Student class>"
# 当使用内建函数bytes时调用,返回字节类型
def __bytes__(self):
return b"byte student class"
# 当将对象当成函数调用会执行该方法
def __call__(self):
print("对象当函数调用")
class Dog():
# __new__是一个不使用@classmethod修饰的类方法,在创建对象时,首先会调用这个方法,返回当前类的对象
# 如果该方法返回当前类的对象,那么接下来会调用__init__方法,对对象进行初始化,否则__init__方法不会得到执行
def __new__(cls):
print("new执行")
# return cls()不能这么做会无限递归
# 通过super调用__new__就不会出现无限递归
return super().__new__(cls)
def __init__(self):
print('1')
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print('running。。。')
class Cat(Animal):
def __init__(self, name, age):
super(Cat, self).__init__(name, age)
def run(self):
super(Cat, self).run()
# 主函数调用
if __name__ == '__main__':
# 类直接调用实例方法
Student('张三', '15').study()
# 根据类创建一个对象zhangsan,创建对象的过程被称为实例化
zhangsan = Student('张三', '15')
# 查看对象的属性
print(zhangsan.name)
print(zhangsan.age)
# 对象zhangsan可以调用类中所有的实例方法(实例函数)和实例变量
zhangsan.to_study()
面向对象
封装
隐藏具体的实现细节,只提供给外界调用的接口。只要提供给外界的接口不变即可,底层细节改变的时候,不会对外界造成影响。
property
- property函数
- @property装饰器
super关键字
- super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,产生了一个super对象
- super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例
- super(B, self).func的调用并不是用于调用当前类的父类的func函数
- Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super)
- 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次。