0%

Python编程—面向对象

本文主要记录Python中支持面向对象编程的特性、类的定义、封装、继承等概念。

1. 类的定义及实例化

面向对象编程是通过类来实现的,类提供了一种组合数据和操作的方法。Python中定义一个类的基本语法如下:

1
2
3
4
5
6
7
8
9
10
11
class Student: # 创建了一个Student类
school = 'SCU' # 类变量
def __init__(self,name): # 初始化函数
self.name = name # 实例变量
self.course = []
@property
def printName(self): # 实例方法
print(self.name)
@classmethod
def printGrade(cls,grade): # 类方法
print(grade)

类支持两种操作:属性引用实例化

  • 属性引用,使用的是Python中属性引用的标准语法,即obj.varStudent.schoolStudent.printName是有效的属性引用,分别返回一个字符串对象和一个函数对象。
  • 实例化,类的实例化使用函数表示法,即stu=Student('lihua'),创建了类的实例并将其分配给局部变量stu。类有一个__init__()构造方法,该方法在类实例化时会自动调用。

2. 类的变量和方法

2.1 类变量和实例变量

  • 类变量:类内部定义的变量,其属于类,可以通过类直接访问,所有实例都可以访问,类似于C++中的静态成员变量。
  • 实例变量:以self开头定义的变量,self代表类的实例,实例变量属于特定的实例。

NOTE:实例变量的访问优先级高于类变量,所以当实例变量和类变量同名时,优先访问实例变量,屏蔽对类变量的访问。

2.2 类方法、实例方法和静态方法

在类的内部,通过使用def关键字来定义方法。在类内部定义的方法分为三种:实例方法、类方法和静态方法。

  • 实例方法:类内部定义的没有装饰器且第一个参数为self的方法。可通过实例直接访问,如果要通过类访问,需要将实例作为参数传入。
    1
    2
    stu.printName() # 实例访问,输出:lihua
    Student.printName(stu) # 类访问,必须传入实例对象,输出:lihua
  • 类方法:类内部定义的以@classmethod装饰的方法,其第一个参数为cls,表示将类对象本身传入方法。可以通过类直接访问,不需要实例化。类方法的一个主要用途是定义多个构造器来对类进行初始化
    1
    2
    Student.printGrade('grade 2019') # 可以通过类直接访问,输出:grade 2019
    stu.printGrade('grade 2016') # 可以通过实例进行访问,输出:grade 2016
  • 静态方法:类内部定义的以@staticmethod装饰的方法。实例和类都可对其进行直接访问,与类方法不同在于静态方法不需要传入参数cls

2.3 property使用

Python中property的作用有两个:

  • 作为装饰器@property将类方法转为类变量
    1
    stu.printName # 作为属性而不是方法进行访问,输出:lihua
  • property重新实现setter和getter方法

2.4 属性和方法的访问限制

在Python中,类的访问权限有公开和私有两种:

  • public:公开访问,正常的函数和变量名都是公开的,可以被外部访问
  • private:私有访问权限,通过在属性名和方法名前面加双下划线__进行标识。私有化后的属性和函数只能在类的内部访问

3. 继承

Python中类的继承有单继承多继承两种方式,派生类定义的一般格式如下:

1
2
class DerevedClass(BaseClass1[,BaseClass2,BaseClass3]):
pass

3.1 继承实现的原理

对于定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,这个MRO列表是一个简单的线性顺序表,里面存储的是基类对象。MRO列表遵循如下准则:

  • 派生类会先于基类被检查
  • 多个基类会根据它们在列表中顺序被检查
  • 如果基类有相同的方法名,子类中使用时未加指定,Python从左至右进行搜索基类中是否包含该方法,并选择第一个遇到的基类

3.2 派生类中调用基类的方法

在派生类中往往需要重用基类的方法,实现的方法有两种:

  • 通过属性引用的方式,即BaseClass.func()
  • 通过super()方法,super()依赖于继承,即使没有直接继承关系,super()仍然按照MRO继续查找
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A:
    def test(self):
    super().test()
    class B:
    def test(self):
    print('from class B')
    class C(A,B):
    pass
    c = C()
    c.test() # 输出:from class B

参考文献 & 资源链接