python是一种面向对象的变成语言。
python几乎所有的东西都是对象,包括对象和属性。
一.类的定义
python类的定义:
class ClassName:
pass:
实例:
注意:
- 类中的函数称为方法,有关于函数的一切适用于方法,唯一的区别在于函数的调用方式。
- 方法__init__()是一个特殊的方法,每当你根据类进行实例化时(创建对象),Python都会自动调用,方法名是一种约定,旨在避免与普通方法发生冲突。相当于C++中的构造函数。
- 当使用类实例化的对象,调用类中的方法时,Python会自动将实例化的对象传入,类中的方法必须用一个变量接收,如实例中的self变量(变量名可以随便取)。使用该变量调用实例中的方法和属性。
- 类的组成包括:类的属性,实例方法,静态方法,类方法。类名在python中也是对象,是一个没有实例(实例属性和方法)的对象。
类的属性:分为实例属性和类属性。
实例属性是指在实例化一个类时动态添加到实例对象中的变量,可以通过实例化对象访问。
类属性是指被类的所有实例化对象,包括类名本身对象共享的变量,可以通过类名或类的实例化对象访问。类属性就是静态属性。
实例方法,静态方法和类方法:python实例方法,类方法和静态方法区别_两片空白的博客-CSDN博客
二.类实例化对象
- 对象创建和属性方法的使用
实例对象=类名()
使用通过'.'点操作符来访问属性和方法。
- 实例方法的调用有两种方式:
实例对象.方法(...)
类名.方法(实例对象, ...)
my_dog=Dog("tager", 10)
Dog.sit(my_dog)
- 对象的打印__str__()方法
当我们实例化一个类对象,使用print打印类对象时,得到的时对象的地址。没有得到对象的属性。
可以在类中定义__str__()方法,print时会调用__str__()方法,__str__()方法中需要返回字符串类型。
三.封装
封装的作用:一是可将属性和行为包装到类对象中,需要通过实例化对象或类名来访问。二是在变量或者函数名前加两个"_",使属性和方法实现私有化。只能在类中访问,不能在类外访问。
python中实现私有化的方法比较的方法比较简单,即在准备实现私有化的方法和属性名字前面加两个下划线即可。类中所有双下划线的名称都会自动变成:_类名__数据名的形式。比如:__x,python会自动将其变形成:_类名__x。
由于python将__x转化成了_类名__x,于是会有下面的情况:
以_类名__x的形式可以访问到python的私有变量,这种情况是需要程序员来避免的。
四.继承
在python中,一个类可以继承另外一个类。原有的类称为父类,而新的类称为子类。子类继承父类的所有属性和方法,同时还可以定义自己的属性和方法。
没有在括号中填父类,默认继承object类。
继承的作用可以实现代码的复用。
语法:
class 子类类名(父类1, 父类2...):
pass
4.1 子类的__init()__方法
创建子类实例时,python首先需要完成的任务是给父类的所有属性赋值。在子类__init()__中实现。
在实例化子类对象时,需要将子类和父类的成员都传入。
4.2 方法和属性重写
- 属性重写
- 方法重写
子类继承父类方法,当父类方法不符合子类行为时,可以对父类的方法进行重写。重写的条件在于,需要子类的重写的方法和父类方法同名(只需要方法名相同即可,参数不需要相同)。
4.3 继承原理(MRO——方法搜索顺序)
- 主要用于继承中方法和属性的调用顺序,这个MRO列表就是一个简单的所有基类的线性顺序列表。
- python中针对类提供了一个内置属性__mro__可以查看搜索顺序,搜索方法和属性时按照MRO列表顺序来进行搜索的。
- 而这个MRO列表的构造是通过一个C3线性化算法来实现的。
搜索方法和属性规则:
- 如果在当前类中找到方法直接执行,不再搜索。
- 如果当前类中没有找到方法,玩后面的顺序找,找到后执行,不在搜索。
- 如果在整个搜索顺序中都没有找到,程序报错。
- 使用super来查找和直接查找属性和方法都是这个规则。
python的继承不像C++中的继承,会在派生类中继承成员变量,实例化对象时,也会创建基类的成员变量。这样会导致在菱形继承时,会出现变量的冗余和二义性。
而python中的继承通过MRO机制避免了这个问题,按照列表顺序在基类中查找方法或者属性,而不是在子类中创建父类变量。
重写原理:
按照mro顺序列表查找方法和属性时,当子类重写了方法或者属性,调用方法或者属性时,在子类中找到方法(与参数无关)和属性,不会继续搜索。 基类的方法和属性等价于被隐藏了。
4.3 super()用法
4.2.1 定义
super()是python中调用父类(超类)的一种方法。在子类中可以通过super()方法调用父类的方法和属性。超类是指具有两层以上继承关系的类。
4.2.2 作用
- 在继承中让代码维护更加简单。
- 解决菱形继承带来重复调用,查找顺序(MRO)问题。
4.2.3 使用——通过super()来调用子类和父类同名的方法
- 单继承
super().add(num)确实调用了父类的add()方法,并且父类中的实例和子类中的实例地址相同,说明是一个实例self。在父类中的self.n实际是子类的n,所以算出来n的结果是7。
- 多继承
五.多态
多态是在继承体系中,调用相同的方法,通过传入不同的对象,有不同的动作。
python中的多态没有C++中这么复杂,由于python中的变量无序声明数据类型就可以赋值,python对变量赋值就是创建一个新的变量,这个变量就是对应的类型。
python中的多态是通过子类继承父类,子类重写父类的方法。在当使用该方法时,会根据变量的不同来调用不同的方法。
- 非继承和多态,不同类中有相同方法。
由于没有继承关系,所以不属于多态。
- 多态,重写父类方法
六.特殊属性和方法
6.1 特殊属性
- __dict__
放回类中方法或属性的字典
- __class__
- __bases和__base__:使用类调用
__base__:输出第一个父类类型。
__bases__:输出父类类型的元组。元组每一个位置都是一个类类型,都可以定义变量。
- __mro__
输出继承了那些父类类型的元组,查找属性和方法的顺序表。
6.2 特殊方法
- __subclasses__()
输出子类列表。
- __add__():重载+操作符
类不支持'+'操作,支持需要实现__add__()方法。
- __len__()内置方法计算长度
len()函数中会调用类的__len__()方法
- __new__()在创建对象时调用,__init__()在初始化对象时调用
想看下图发现:
实例化对象时,先调用的__new__方法,再调用__init__方法。
cls地址和A类对象地址相同。新创建的对象的obj和a和__init__方法中的self相同。
即,
- 在调用A的__new__时A对象地址赋值给了cls
- cls传给super().__new__方法,新建完的对象传给obj
- 调用完A的__new__后调用__init__,obj对象传给了self
- self初始化后赋值给了a。
- __repr__()
在print()时会调用类的__repr__方法。我们可以重写__repr__方法,来实现需要的打印。