Skip to content

第1课 数据抽象类与Python类

Python中的基本数据类型

在每种编程语言中都会内置一些基本的数据类型供程序设计者使用。在Python中,同样内置了若干种数据类型。我们常用的内置数据类型有九种,这九种基本类型大致可以分为两类:基本类型组合类型。基本类型一般指单一的数据类型,也可以称做原始数据类型(Primitive Type)。而组合类型则可以简单地理解成由基本类型组合而成的数据类型。

在Python中,使用type(variable)内置函数,可以查看变量的数据类型。

  • 基本类型

    1. str 字符串
    2. int 整数型
    3. float 浮点型
    4. bool 布尔变量
  • 组合类型

    1. bytes 字节类型
    2. tuple 元组类型
    3. set 集合类型
    4. dictionary 字典类型
    5. list 列表类型

抽象数据类型(Abstract Data Type)

抽象数据类型的意义:

显然,光用以上的内置数据类型去解决现实生活中的问题是远远不够的。世界如此丰富多彩,那我们如何才能利用计算机去描述万事万物,解决现实问题呢?

在上学期中,我们学习了Python的基本语法(的一点点),学习程序设计中的基本流程控制:顺序结构、分支结构和循环结构。可以说完成了世界万事万物运行的流程的抽象。而在数据层面上,也需要将它抽象出来。

抽象数据类型 就是指一个数据元素集合以及在这些数据上的操作。我们要注意,抽象数据类型的定义与实现是分开的。首先我们要研究他的结构和定义,而非考虑他是如何实现的细节。只要将一种抽象数据类型定义完成,其可以用任何工具实现,所以在这个阶段是不考虑他具体是如何实现的。

抽象数据类型的表示方法

在描述一个抽象数据类型时,我们可以使用预先定义好的数据类型(比如:Python中已经定义好的数据类型:int, str, bool, float以及其他类型)来定义抽象数据类型。

在本课中,我们使用不严格的定义方法:

抽象数据类型名{
数据:
    预定义好的数据类型组合
操作:
    抽象数据类型的操作
}
这么看起来确定非常抽象,下面我用几个例子来说明怎么进行抽象数据类型的定义。

例如:一个二维平面中的点的抽象数据类型的定义为:

ADT Point {
数据:
    x: float # 定义横坐标
    y: float # 定义纵坐标
操作:
    distance(p: Point) -> float # 计算当前点到给定点p距离
}

例如:我们可以定义一个学生类型

ADT Student {
数据:
    name: str  # 学生姓名
    age: int   # 学生年龄
    grade: int # 年级
    courses: list[str] # 选修课程列表
操作:
    grow() # 增长1岁
    grade_up() # 年级升高1年
    sign_up_for(course: str) # 添加选修课程
    ...
}

再举1个例子,我们在上学期经常会遇到的例子,就是游戏中的Player。当时我们使用了dict来实现,现在有了抽象数据类,我们能更好定义Player这个数据抽象类。很快可以得出以下定义:

ADT Player {
数据:
    name: str  # 玩家姓名
    mp: int     # 魔法值
    hp: int     # 健康值
    level: int  # 级别
    ep: int     # 经验值
    weapons: list[str] # 武器列表
    equipments: list[str] # 装备列表
操作:
    attack(p: Player) # 攻击另一位玩家p
    level_up()        # 升级
    poison(t: int)          # 中毒t秒
    pick_up(weapon: str) # 装备weapon
    drop(weapon: str): # 扔掉装备
    ...
}

Python语言中的class

Python语言中,可以使用class来完成抽象数据类的定义与实现。

基本语法

Python语言中class的基本语法为:

class ADTName:

    def __init__(self, field1, field2...):
        # 在这里初始化类的属性、字段(Properties, Fields)
        self.field1 = field1
        slef.field2 = field2
        ...

        # 成员函数(member functions)或者方法(methods)
    def action1(self, params...):
        # function body

    def action2(self, params...):
        # function body 

Python Class

Class & Objects

类是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。

student_class_and_object

当类进行实例化后就会产生一个对象。对于前面我们实现的Student类,那么我们可以实例化出不同的对象:张三、李四等。如下图所示:

class_and_object

下面给出了抽象数据类Student的Python实现版本:

class Student:
    def __init__(self, name, age, grade, courses):
        self.name = name
        self.age = age
        self.grade = grade
        self.courses = courses

    def grow(self): # 增长1岁
        self.age += 1


    def grade_up(self): # 年级升高1年
        self.grade += 1

    def sign_up_for(self, course: str): # 添加选修课程
        if course not in self.courses:
            self.courses.append(course)

类构造(Construct)/初始化(Initialization)

Python中的类的构造函数是指在Python实例化时会调用的函数。他的主要工作是对对象内部的数据进行初始化的工作。他是一个特殊的函数,他由双下划线包裹着单词init构成。注意:这里的第一个参数是self, 用于指代对象本身。在下面我们可以看到,类中的方法(成员函数)都需要使用self做为第一个参数。

通常在python的构造函数中,要将所有数据都进行初始化。如下:

class Dog:
    def __init__(self, color: str, price: float):
        self.color = color
        self.price = price

定义好__init__函数后,我们就可以生成实例化对象了。下面的语句生成了两个不同的Dog对象,一个对象颜色为白色, 价钱为2000,另一个颜色的对象为黑色,价钱为100。

white_dog = Dog("white", 2000)
black_dog = Dog("black", 100)
white_black_dog

属性(Properties)

前面提到过,在类初始化的过程中,初始化了很多对象内的数据,在Python中一般称为属性。当对象建立后,可以使用obj.property的方式访问对象中的属性。

print("The color of the first dog is {}.".format(white_dog.color))
print("The price of the second is {}.".format(black_dog.color))

方法(Methods)

在类中的方法大多时候为对象的方法。定义方法时,需要将函数的第一个参数设为self, 表明在实际对象调用该方法时,会将实例对象当做self传进函数中。这时就可以使用如self.color等方式访问和修改对象当中的实例了。

如果你不把方法的第一个参数设置为self,那么就无法使用对象后的实例访问这个方法。而变成了一个 类方法。这种情况可以使用: 类名.方法()方式进行调用。如下面的例子:

class A:
    def method_a():
        print("This is a method from class")

    def method_b(self):
        print("This is a method from instance")

a = A()

a.method_a()
a.method_b()
A.method_a()

完整的示例

Point and Circle

import math
class Point:
    def __init__(self, x: float, y: float):
        self.x = x # 横坐标
        self.y = y # 纵坐标

    def distance(self, p: Point) -> float:
        return math.sqrt( (self.x - p.x) ** 2 + (self.y - p.y) ** 2)


class Circle:
    def __init__(self, center: Point, radius: float):
        self.center = center
        self.radius = radius

    def area(self) -> float:
        return math.pi * self.radius * self.radius

    def is_tangent_to(self, circle: Circle) -> bool:
        return self.center.distance(circle.center) == self.radius + circle.radius

日期类

class Date:
    def __init__(self, year: int, month: int, day: int):
        self.year = year
        self.month = month
        self.day = day

    def is_leap_year(self):
        return (self.year % 100 == 0 and self.year % 400 == 0) or (self.year % 100 != 0 and self.year % 4 == 0)

    def caculate_days_between(self, another_date: Date) -> int:
        # include end date in calculation.
        # homework

作业

完成OJ系统中的 C001、C002 两题。