面向对象编程

面向对象编程:把一组数据和处理数据的方法组成对象,把行为相同的对象归纳为类,通过封装隐藏对象的内部细节,通过继承实现类的特化和泛化,通过多态实现基于对象类型的动态分派。

关键词:对象(object)、类(class)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)。

在面向对象编程中,类是一个抽象的概念,对象是一个具体的概念。我们把同一类对象的共同特征抽取出来就是一个类,比如我们经常说的人类,这是一个抽象概念,而我们每个人就是人类的这个抽象概念下的实实在在的存在,也就是一个对象。

在面向对象编程的世界中,一切皆为对象对象都有属性和行为每个对象都是独一无二的,而且对象一定属于某个类。对象的属性是对象的静态特征,对象的行为是对象的动态特征。按照上面的说法,如果我们把拥有共同特征的对象的属性和行为都抽取出来,就可以定义出一个类。

定义类

在 Python 中,可以使用class关键字加上类名来定义类,通过缩进我们可以确定类的代码块,就如同定义函数那样。在类的代码块中,我们需要写一些函数,我们说过类是一个抽象概念,那么这些函数就是我们对一类对象共同的动态特征的提取。写在类里面的函数我们通常称之为方法,方法就是对象的行为,也就是对象可以接收的消息。方法的第一个参数通常都是self,它代表了接收这个消息的对象本身。

class Student:
    def study(self, course_name):
        print(f'学生正在学习{course_name}.')

    def play(self):
        print(f'学生正在玩游戏.')

创建和使用对象(实例)

在我们定义好一个类之后,可以使用构造器语法来创建对象(也叫创建实例),代码如下所示:

class Student:
    def study(self, course_name):
        print(f'学生正在学习{course_name}.')

    def play(self):
        print(f'学生正在玩游戏.')

stu1 = Student() # stu1 被称为 Student 类的对象或者实例
stu2 = Student()
print(stu1) # <__main__.Student object at 0x103373310>
print(stu2) # <__main__.Student object at 0x103224d00>

在类的名字后跟上圆括号就是所谓的构造器语法,上面的代码创建了两个学生对象,一个赋值给变量stu1,一个复制给变量stu2。当我们用print函数打印stu1stu2两个变量时,我们会看到输出了对象在内存中的地址(十六进制形式)。现在我们可以告诉大家,我们定义的变量其实保存的是一个对象在内存中的逻辑地址(位置),通过这个逻辑地址,我们就可以在内存中找到这个对象。

调用对象的方法有两种方式:

  • 可以使用对象.方法(参数)的语法来调用具体方法。
  • 可以使用类名.方法(实例对象, 参数)的语法来调用具体方法,

代码如下所示:

class Student:
    def study(self, course_name):
        print(f'学生正在学习{course_name}.')

    def play(self):
        print(f'学生正在玩游戏.')

stu1 = Student()
stu1.play() # 学生正在玩游戏.
stu1.study('Python程序设计') # 学生正在学习Python程序设计.

Student.play(stu1) # 学生正在玩游戏.
Student.study(stu1, 'Python程序设计') # 学生正在学习Python程序设计.

__init__ 初始化方法

修改 Student 类,为其添加一个名为 __init__ 的方法。在我们调用 Student 类的构造器创建对象时,首先会在内存中获得保存学生对象所需的内存空间,然后通过自动执行 __init__ 方法,完成对内存的初始化操作,也就是把数据放到内存空间中。所以我们可以通过给 Student 类添加 __init__ 方法的方式为学生对象指定属性,同时完成对属性赋初始值的操作,正因如此,__init__方法通常也被称为初始化方法。

学生对象添加 name(姓名)和 age(年龄)两个属性:

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def study(self, course_name):
        print(f'{self.name}正在学习{course_name}.')
    def play(self):
        print(f'{self.name}正在玩游戏.')

stu1 = Student('Stan', 25)
stu1.study('Python程序设计')		#Stan正在学习Python程序设计.

打印对象

在 Python 中,以两个下划线__(读作“dunder”)开头和结尾的方法通常都是有特殊用途和意义的方法,我们一般称之为魔术方法或魔法方法。如果我们在打印对象的时候不希望看到对象的地址而是看到我们自定义的信息,可以通过在类中放置 __repr__ 魔术方法来做到,该方法返回的字符串就是用print函数打印对象的时候会显示的内容,代码如下所示。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def study(self, course_name):
        print(f'{self.name}正在学习{course_name}.')
    def play(self):
        print(f'{self.name}正在玩游戏.')
    def __repr__(self):
        return f'{self.name}: {self.age}'

stu1 = Student('Stan', 25)
print(stu1) # Stan: 25

双下划线方法(魔术方法)

在 Python 中,所有以__双下划线包起来的方法,都统称为魔术方法。比如上面我们学习到的 __init__ 和 __repr__ 方法。它用于在类中定义特定的行为,比如 __init__ 是专门用来做初始化的方法,__repr__ 是专门用来在 print 打印时调用的方法。