面向对象编程简介
我们首次对Python基础的探索向我们介绍了基础对象类型:数字,字符串,和列表。相似的,我们对NumPy的讨论也是围绕着N维数组展开的。这些对象类型之间很大的区别和它们绑定的不同函数。绑定(bound)到数组上的函数叫做方法(method)。比如说,字符串有着多个旨在操作其储存的字符序列的方法,而NumPy数组有着很多操作数组内置数字数据的方法。
# 不同类型的对象可以储存不同的方法 >>> string = "hello world" >>> string.capitalize() # 使用字符串方法 `capitalize` 'Hello world' >>> import numpy as np >>> array = np.array([[0, 1, 2], ... [3, 4, 5]]) >>> array.sum() # 使用数组方法 `sum` 15
更加广义来讲,对象可以拥有总结关于对象信息的属性(attribute)。比如说,数组属性 ndim
和 shape
提供了关于数组数字数据索引布局的信息。
# 访问对象的属性 >>> array.ndim 2 >>> array.shape (2, 3)
在本模组中,我们将学习如何定义我们自己的,可自定义的,有着不同集合的属性和方法的对象类型。通过这么做·,我们将将Python作为一个“面向对象”(object-oriented)编程语言使用;这将大幅提升我们作为Python用户的能力并让我们更加深入地理解Python这门语言。
作为一个预览,让我们创建我们自己的名为 Rectangle
的类(class):
class Rectangle: """ 一个描述长方形特性的Python对象 """ def __init__(self, width, height, center=(0.0, 0.0)): """ 设置某个 `Rectangle` 实例的属性。 Parameters ---------- width : float 这个长方形实例的x长度。 height : float 这个长方形实例的y长度。 center : Tuple[float, float], optional (default=(0, 0)) 这个长方形的中心的 (x, y) 位置""" self.width = width self.height = height self.center = center def __repr__(self): """ 返回在打印某个长方形时使用的字符串。""" return "Rectangle(width={w}, height={h}, center={c})".format(h=self.height, w=self.width, c=self.center) def compute_area(self): """ 返回长方形的面积 Returns ------- float""" return self.width * self.height def compute_corners(self): """ 计算这个长方形的四角的 (x, y) 位置,首先返回“左上”角,然后顺时针继续。 Returns ------- List[Tuple[float, float], Tuple[float, float], Tuple[float, float], Tuple[float, float]]""" cx, cy = self.center dx = self.width / 2.0 dy = self.height / 2.0 return [(cx + x, cy + y) for x,y in ((dx, dy), (dx, -dy), (-dx, -dy), (-dx, dy))]
这个 Rectangle
类的一个实例(instance)是一个属性包括长度,高度,和中心坐标的单个长方形。同时,我们可以使用这个长方形的方法(它为函数的属性)来计算它的面积和四角的坐标。
# 创建一个长度为4,高度为0,中心为 (0, 0) 的长方形 # 这将执行 __init__ 方法并设置它的width/height/center属性 >>> rect1 = Rectangle(4, 10) # __repr__ 方法定义了长方形实例在命令行中将如何显示 >>> rect1 Rectangle(width=4, height=10, center=(0, 0)) # 计算这个长方形的面积 >>> rect1.compute_area() 40 # 计算这个长方形的四角坐标 >>> rect1.compute_corners() [(2.0, 5.0), (2.0, -5.0), (-2.0, -5.0), (-2.0, 5.0)]
就像我们遭遇过的任何其它Python对象一样,我们可以将我们的 Rectangle
实例放在字符串中,存储为词典的值,作为参数输入到函数中,使用多个变量引用它们,等等。
流行的科学,数据分析,和机器学习Python模组都很依赖定义Python自定义类的能力。比如说,pandas定义了一个类似表格的 DataFrame
类;PyTorch,MXNet,和TensorFlow都定义了能够自动求导数的张量类;这对训练神经网络极其重要。理解Python的类系统会将大幅提升你使用像以上这些的模组(无耻广告:如果你对自动求导的进行纯Python/NumPy实现的模组感兴趣,请查阅MyGrad模组——译者注:这是作者自己写的模组,很厉害的哦!)。
在本模组,我们将会讨论类定义的基础;这将允许我们定义自己的对象类(class)(也就是类型(type))。然后,我们将学习如何创建某个对象类型的不同的实例并定义方法。这将导致我们初次见到特殊方法;它们将允许我们修改我们对象类型在配合各种Python操作符时的行为。比如说,我们可以定义 +
操作符会如何和我们的对象互动。最后,我们将快速地讨论类继承(class inheritance)的概念。
经验:
本模组旨在理解如何定义和使用我们自己的Python对象类。这将极大地成熟化我们对Python作为一门面向对象语言的理解并提升我们完整使用Python所有功能的能力。
类vs类型:关于术语的重要注释
在我们深入讨论之前,我们应该花一些时间来了解术语“类型”(type)和“类”(class)在Python的实际操作中是同义的。到现在为止,我们仅仅使用过术语“类型”来将对象互相区分。比如说,1
术语类型 int
,而 "cat"
术语类型 str
。但是,我们将马上学习用来创造新类型对象的类定义并学习如 issubclass
的函数。虽然如此,请记住,类和类型指的是同一个东西!存在两个不同术语的历史遗留,但是Python 2.2之后类型和类的概念被完全统一了。
在实际操作中,人们一般使用“类型”一词来指内置的类型(如 int
和 str
),而“类”则指用户定义的类型。最后重申一遍,在Pythond的现代版本中,这两次并没有任何实际的区别。
经验:
两个术语“类型”和“类”是同义的;它们都指着对某一类型/类的Python对象的包装定义。虽然它们在Python语言中不能互换——我们将编写类定义,而不是类型定义,而我们将使用 type
而不是 class
来检查对象——但这些区别仅仅是早期Python版本的遗留物而已。
官方说明文档链接
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论