类的定义和使用
类是对某一类事物的抽象描述,如动物类、玩具类等。它是一个抽象的概念。类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实的个体,他是类的实例。所以对象时根据类创建的,并且一个类可以用于多个对象。
类是由类名、属性和方法三部分组成:
- 类名:类的名称,习惯上,他的首写字母是大写,不能用阿拉伯数字开头
- 属性:用于描述事务的特征
- 方法:用于描述事物的行为
在Python中,可以使用class关键字声明一个类,其基本语法格式如下:
class 类名:
类的属性
类的方法
程序要想完成具体的功能,仅有类是不够的,还需要根据类创建实例对象.将类实例化为一个对象语法如下:
对象名 = 类名([相关参数])
给对象添加属性格式如下:
对象名.新的属性名 = 值
数据成员与成员方法
私有成员与共有成员
从形式上看,在定义类的成员时,如果成员名以两个下划线(__开头)则表示是私有成员,但是Python并没有对私有成员提供严格的访问保护机制.私有成员在类的外部不能直接访问.Python提供了一种特殊方式‘对象名._类名__xxx
’可以访问私有成员,但这会破坏类的封装,不推荐使用.
在Python中,以下划线开头和结束的成员名含有特殊含义,类定义中用下划线作为变量名和方法名前缀和后缀来表示类的特殊成员.
- _xxx:保护成员,不能用‘from moudel import *’,自由类对象和子类对象可以访问这些成员。
__xxx__
: 系统定义的特殊成员__xxx
:类中的私有成员,一般只有类对象自己能访问,子类对象也不能访问到这个成员,但是在对象外部可以通过‘对象名._类名__xxx
’这样的特殊方式访问- python不存在严格意义上的私有成员
数据成员
数据成员用来说明对象特有的一些属性,数据成员大体分为两类:属于对象的数据成员和属于类的数据成员.属于对象的数据成员主要指在构造函数__init__()
中定义的,定义和使用必须以self为前缀,同一个类的不同对象之间的数据成员互不影响;属于类的数据成员时该类所有对象共享的,不属于任何一个对象,在定义类时这类数据成员不在任何一个成员方法的定义中
方法
公有方法和私有方法
在类中定义的方法可以分为四类:公有方法、私有方法、静态方法和类方法
公有方法和私有方法一般是指属于对象的实例方法,其中私有方法的名称以两个下划线(__)开始,每个对象都有自己的私有方法和公有方法,这两类方法都可以访问属于类和对象的成员;公有方法通过对象名直接调用,私有方法不能通过对象名字直接调用,只能在实例方法中通过self调用或者在外部通过Python支持的特殊方式调用.
类的所有实例方法都至少有一个名为self的参数,并且是方法的第一形参,self代表对象自身.
静态方法和类方法都可以通过类名和对象名调用,但不能直接访问属于对象的成员,智能访问属于类的成员。一般将cls作为类方法的第一个参数,表示该类自身,在调用类方法时不需要为该参数传递值
静态方法
Python中允许声明与类的对象实例无关的方法,称为静态方法。静态方法不对特定实例进行操作,在静态方法中访问对象实例会导致错误。静态方法中访问对象会导致错误。静态方法通过装饰器@staticmethod
进行定义,其格式如下:
@staticmethod
def 静态方法([形参列表]):
函数体
静态方法一般通过类名进行访问,也可以通过对象实例进行调用.其格式如下:
类名.静态方法名([实参列表])
类方法
Python中允许声明属于类本身的方法,即类方法.类方法不对特定实例进行操作,在类方法中访问对象实例属性会导致错误.类方法通过@classmethod
进行定义,第一个形式参数必须为类对象本身,通常是cls.类方法的生命格式如下:
@classmethod
def 类方法名(cls,[形参列表]):
函数体
类方法一般通过类名进行访问,也可以通过对象实例进行调用,格式如下:
类名.类方法([实参列表])
属性
类的数据成员是在类中定义的成员变量(域),用来存储描述类的特征的值,称为属性,属性可以被类中的方法访问,也可以通过类对象或者实例对象进行访问.而在函数体或代码块中定义的局部变量,则只能在其定义的范围内进行访问.
属性实际上是类中的变量.python中定义变量不需要声明,可以直接使用.建议在类定义的开始位置初始化类属性,或者在构造函数(__init__
)中初始化实例属性
实例属性
通过self.变量名
定义的属性称为实例属性,又称为实例变量。类的每个实例都包含该类的实例变量的一个单独副本,实例变量属于特定的实例。实例变量在类的内部通过self访问,在外部通过对象实例访问。
实例属性一般在__init__()
方法中通过如下形式初始化:
self.实例变量名 = 初始值
然后在其他实例函数中,通过self访问:
self.实例变量名 = 值 #写入
self.实例变量名 #读取
创建对象实例后,通过对象实例访问:
obj = 类名() #创建对象实例
obj1.实例变量名 = 值 #写入
obj1.实例变量名 #读取
类属性
Python允许声明类对象本身的变量,即类属性,又称为类变量、静态变量。类属性属于整个类,不是特定实例的一部分,而是所有实例之间共享一个副本。
类属性一般在类体中通过如下形式初始化:
类变量名 = 初始值
然后在其类定义的方法中或外部代码中,通过类名访问:
类名.类变量名 = 值 #写入
类名.类变量名 #读取
注意:类属性如果通过obj.属性名
进行访问,则属于该实例的实例属性.虽然类属性可以使用对象实例来访问,但这样容易造成困惑,应该使用标准的访问方式: 类名.类变量名
私有属性和共有属性
Python类的成员没有访问控制限制,这与其他面相对象的语言不同。
通常约定两个下划线开头,但是不以两个下划线结束的属性还私有的,其他为公共的,不能直接访问私有属性,但是可以在方法中访问。
@property装饰器
面向对象编程的封装性性原则要求不直接访问类中的数据成员。Python中可以定义私有属性,然后定义相应的访问该私有属性属性的函数,并且使用@property装饰器装饰这些函数。程序可以把函数‘当作’属性访问,从而提供更加友好的访问方式
@property装饰器默认提供一个只读属性,如果需要,可以使用对应的getter、setter和deleter装饰器实现其他访问器函数。
特殊属性
python对象中包含许多以双下划线开始和结束的方法,称为特殊属性,常用特殊属性如下:
特殊方法 | 含义 |
---|---|
object.__dict__ | 对象的属性字典 |
instance.__class__ | 对象所属的类 |
class.__对象所属的类__ | 对象所属的类 |
class.__bases__ | 类的基本元组 |
class.__base__ | 类的基类 |
class.__name__ | 类的名称 |
class.__mro__ | 方法查找顺序,基类元组 |
class.mro() | 同上,可被子类重写 |
class.__subclasses__() | 子类列表 |
自定义属性
Python中,可以赋予一个对象自定义的属性,即类定义中不存在的属性.对象通过特殊属性__dict__
存储自定义属性。
通过重载__getattr__
和__setattr__
,可以拦截对成员的访问,从而自定义属性的行为。__getattr__
只有在访问不存在的成员时才被调用,__getattribute__
拦截所有获取操作.在__getattribute__
中不要使用return self.__dict__[name]
返回结果,因为在访问self.__dict__
时同样会被__getattribute__
拦截,从而造成无限递归想成列循环
__getattr__(self,name) # 获取属性,比__getattribute__优先调用
__getattribute__(self,name) # 获取属性
__setatt__(self,name,value) # 设置属性
__delattr__(self,name) #删除属性
继承多态封装
继承
单继承
在Python中,所谓‘继承’就是在一个已存在的类的基础上建立一个新类,已存在的类称为‘基类’或‘父类’,新建立的类称为‘派生类’或者‘子类’。
继承语法如下:
class 子类名(父类名):
假设一个类名为A,B类是A类的子类,例如:
class A(object):
class B(A):
如果在定义类的时候没有标注出父类,那么这个类默认是继承自object的.
多继承
现实中一个子类往往会有多个父类.多继承可以看做对单继承的扩展,通过在子类名称的括号中标注出要继承的多个父类,并且多个父类间使用逗号分割,多继承的格式如下:
class 子类(父类1,父类2,...,父类n)
多态
在强类型语言(Java或者C#)中,多态是指允许使用一个父类类型的变量或常量来引用一个子类类型对象,根据被引用子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果及时用父类类型来调用子类的方法。
在python中,多态指在不考虑对象类型下使用对象,相比于强类型,Python更推崇‘鸭子类型’,即它不关注对象的类型,而是关注对象具有的行为。
特殊方法与运算符重载
对象的特殊方法概述
Python对象中包含了许多以双下划线开始和结束的方法,称为特殊方法。特殊方法通常在针对对象的某种操作时自动调用。
特殊方法 | 含义 |
---|---|
__It__ 、__add__ 等 | 对应运算符<、+等 |
__init__ 、__del__ | 创建或销毁对象时调用 |
__len__ | 对应于内置函数len() |
__setitem__ 、__getitem__ | 按索引赋值取值 |
__repr__(self) | 对应于内置函数repr() |
__str__(self) | 对应于内置函数str() |
__bytes__(self) | 对应于内置函数bytes() |
__format__(self,format_spec) | 对应于内置函数format() |
__bool__(self) | 对应内置函数bool() |
__hash__(self) | 对应于内置函数hash() |
__dir__(self) | 对应于内置函数dir() |
运算符重载与对象的特殊方法
Python的运算符实际上是通过调用对象的特殊方法实现的.
运算符 | 特殊方法 | 含义 |
---|---|---|
>、>=、!=、<、<=、== | __ge__ __gt__ __ne__ __It__ __le__ __eq__ | 比较运算符 |
|、^、& | __or__ __ror__ __xor__ __rxor__ __and__ __rand__ | 按位与、异或、与 |
|=、^=、&= | __ior__ __ixor__ __iand__ | 按位复合赋值运算 |
<<、>> | __lshift__ __rlshift__ __rshift__ __rrshift__ | 移位运算 |
<<=、>>= | __ilshift__ __irlshift__ __irshift__ __irrshift__ | 移位复合赋值运算 |
+、- | __add__ __radd__ __sub__ __rsub__ | 加法与减法 |
+=、-= | __iaddr__ __isub__ | 加减符合赋值运算 |
*、/、%、// | __mul__ __rmul__ __truediv__ __rturediv__ __mod__ __rmod__ __rfloordiv__ __floordiv__ | 乘法、除法、取余、整数除法 |
*=、/=、%=、//= | __imul__ __idiv__ __itruediv__ __imod__ __ifloordiv__ | 乘除复合赋值运算 |
+x、-x | __pos__ __neg__ | 正负号 |
~X | __invert__ | 按位翻转 |
** 、** = | __pow__ __rpow__ __ipow__ | 指数运算 |