geekdoc-python-zh/docs/pythonland/21.md

268 lines
12 KiB
Markdown
Raw Permalink Normal View History

2024-03-03 22:54:39 +08:00
# Python 中的类和对象
> 原文:[https://python.land/objects-and-classes](https://python.land/objects-and-classes)
Python 类和 Python 对象是该语言的重要组成部分。不了解 Python 类和对象,就无法正确学习 Python。在本章中您将学习:
* 在 Python 中一切都是对象
* 定义自己的 Python 类
* 基于类创建对象
* 什么是继承
当您只是创建小脚本时,您可能不需要创建自己的 Python 类。但是一旦你开始创建更大的应用程序,对象和类允许你自然地组织你的代码。对对象和类的良好理解会帮助你更好地理解语言本身。
目录
* [Python 对象:引擎盖下的一瞥](#Python_objects_a_look_under_the_hood "Python objects: a look under the hood")
* [什么是 Python 对象?](#What_is_a_Python_object "What is a Python object?")
* [什么是 Python 类?](#What_is_a_Python_class "What is a Python class?")
* [创建一个 Python 类](#Creating_a_Python_class "Creating a Python class")
* [创建一个 Python 对象](#Create_a_Python_object "Create a Python object")
* [Python 中的 self 是什么?](#What_Is_self_in_Python "What Is self in Python?")
* [创建多个 Python 对象](#Creating_Multiple_Python_Objects "Creating Multiple Python Objects")
* [继续学习](#Keep_learning "Keep learning")
## Python 对象:引擎盖下的一瞥
在我们深入了解所有细节之前,让我们先来看看引擎盖下的情况。我这样做是因为我相信这会让你更好地理解这些概念。不要因为这一页的长度而气馁。通读一遍并亲自尝试示例后,您应该对 Python 中的类和对象有了很好的理解。
OK让我们开始吧你大概知道内置的`len()`函数。它只是返回你给它的物体的长度。但是,比如说,数字 5 的长度是多少呢?我们来问问 Python:
```py
>>> len(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
```
我喜欢错误,因为它们说明了 Python 内部是如何工作的。在这种情况下Python 是在告诉我们 5 是一个对象,它没有`len()`。在 Python 中,一切都是对象。字符串、布尔值、数字,甚至 [Python 函数](https://python.land/introduction-to-python/functions)都是对象。我们可以使用内置函数`dir()`检查 REPL 中的对象。当我们在数字 5 上尝试`dir`时,它显示了一个函数的大列表,这些函数是任何数字类型对象的一部分:
```py
>>> dir(5)
['__abs__', '__add__',
'__and__', '__bool__',
'__ceil__', '__class__',
...
'__str__', '__sub__',
'__subclasshook__', '__truediv__',
'__trunc__', '__xor__',
'bit_length', 'conjugate',
'denominator', 'from_bytes',
'imag', 'numerator',
'real', 'to_bytes']
```
为了清楚起见,我把列表缩短了一点。
列表以这些名字古怪的包含下划线的函数开始,比如`__add__`。这些被称为魔术方法,或 dunder(双下划线的缩写)方法。如果你仔细观察,你会发现对于类型为`int`的对象没有`__len__` dunder 方法。Python 的`len()`函数就是这样知道一个数没有长度的。所有的`len()`所做的,就是在你提供给它的对象上调用`__len__()`方法。这也是 Python 抱怨“int类型的对象没有 len()”的原因
### 什么是 Python 方法?
我在这里随便介绍了一下方法这个词。让我更正式地定义它:
Method
When a [function](https://python.land/introduction-to-python/functions) is part of an object or Python class, we call it a method.
字符串是有长度的,所以一个字符串必须有一个 **`len`** 的方法,对吗?让我们来了解一下!
```py
>>> dir("test")
['__add__', '__class__',
'__contains__', '__delattr__',
'__dir__', '__doc__',
'__eq__', '__format__',
'__ge__', '__getattribute__',
'__getitem__', '__getnewargs__',
'__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__',
'__le__', '__len__', '__lt__',
'__mod__', '__mul__', '__ne__',
'__new__', '__reduce__',
'__reduce_ex__', '__repr__',
'__rmod__', '__rmul__',
'__setattr__', '__sizeof__',
'__str__', '__subclasshook__',
'capitalize', 'casefold', 'center',
'count', 'encode', 'endswith',
'expandtabs', 'find', 'format',
'format_map', 'index', 'isalnum',
'isalpha', 'isascii', 'isdecimal',
'isdigit', 'isidentifier', 'islower',
'isnumeric', 'isprintable', 'isspace',
'istitle', 'isupper', 'join', 'ljust',
'lower', 'lstrip', 'maketrans',
'partition', 'replace', 'rfind',
'rindex', 'rjust', 'rpartition',
'rsplit', 'rstrip', 'split',
'splitlines', 'startswith', 'strip',
'swapcase', 'title', 'translate',
'upper', 'zfill']
```
是的,在那里。既然这是一个方法,我们也可以称它为:
```py
>>> "test".__len__()
4
```
这相当于`len("test")`但是少了很多优雅,所以不要这么做。这只是为了说明这东西是如何工作的。
还有一系列其他不那么神奇的方法向我们展示。随意尝试几个,比如`islower`:
```py
>>> "test".islower()
True
```
该方法检查整个字符串是否是小写,如果是,那么 Python 返回布尔值`True`。其中一些方法需要一个或多个参数,如 replace:
```py
>>> 'abcd'.replace('a', 'b')
'bbcd'
```
它用“b”替换所有出现的“a”。
Thank you for reading my tutorials. I write these in my free time, and it requires a lot of time and effort. I use ads to keep writing these *free* articles, I hope you understand! **Support me by disabling your adblocker on my website** or, alternatively, **[buy me some coffee](https://www.buymeacoffee.com/pythonland)**. It's much appreciated and allows me to keep working on this site!
有时候编程可能有点像变魔术,尤其是当你刚刚开始的时候。但是一旦你在引擎盖下瞥了一眼,看到事情实际上是如何工作的,那种魔力就消失了。让我们继续来看看对象到底是什么,以及它们是如何定义的。
## 什么是 Python 对象?
既然我们已经使用了对象,并且知道 Python 中的一切都是对象,那么是时候定义什么是对象了:
Object
An object is a collection of data ([variables](https://python.land/introduction-to-python/variable)) and methods that operate on that data. Objects are defined by a Python class.
对象和面向对象编程是 20 世纪 90 年代初开始流行的概念。早期的计算机语言,如 C没有对象的概念。然而事实证明对于人类来说对象是一种易于理解的范式。对象可以用来模拟现实生活中的许多概念和情况。如今大多数(如果不是全部的话)新语言都有对象的概念。所以你将要学习的东西在概念上也适用于其他语言:这是基础计算机科学。
## 什么是 Python 类?
因为对象是 Python 语言的组成部分,所以您也可以自己创建对象。如果你想创建你自己类型的对象,你首先需要定义它的方法和它能保存什么数据。这个蓝图叫做类。
Class
A class is the blueprint for one or more objects
所有 Python 对象都基于一个类。当我们创建一个对象时,我们称之为“创建一个类的实例”。字符串、数字甚至布尔也是类的实例。让我们用内置函数`type`来探索一下:
```py
>>> type('a')
<class 'str'>
>>> type(1)
<class 'int'>
type(True)
<class 'bool'>
```
显然,有被称为`str`、`int`和`bool`的类。这些是 Python 的一些原生类,但是,正如我所说的,我们也可以构建自己的类类型!
## 创建一个 Python 类
没有汽车类比的教程是不完整的,所以让我们创建一个代表汽车的 Python 类。要输入的内容很多,而且每一个错误都要重新开始。尽管试,但如果你想走捷径,我理解。只需将下面的类复制并粘贴到您的 Python REPL 中。粘贴后,确保**按两次回车键:**
```py
class Car:
speed = 0
started = False
def start(self):
self.started = True
print("Car started, let's ride!")
def increase_speed(self, delta):
if self.started:
self.speed = self.speed + delta
print('Vrooooom!')
else:
print("You need to start the car first")
def stop(self):
self.speed = 0
print('Halting')
```
## 创建一个 Python 对象
不要担心,我们将一步一步地检查类定义,但是让我们首先创建并使用一个 Car 类型的 Python 对象:
```py
>>> car = Car()
>>> car.increase_speed(10)
You need to start the car first
>>> car.start()
Car started, let's ride!
>>> car.increase_speed(40)
Vrooooom!
```
如果你愿意,你也可以使用下面的面包屑来玩我们新创建的汽车类:
[https://crumb.sh/embed/GzaEerCX65E](https://crumb.sh/embed/GzaEerCX65E)
Python 中的对象总是一个类的实例。一个类可以有许多实例。我们刚刚用`Car()`创建了类`Car`的一个实例,并将它赋给了(小写)变量`car`。创建一个实例看起来像调用一个函数;你以后会知道为什么。
接下来,我们调用我们的一个汽车对象方法:试图在它还没有启动的时候增加它的速度。哎呀!只有启动汽车后,我们才能提高它的速度,享受它发出的噪音。
现在让我们一步一步地复习我们的汽车课程:
* Python 中的类是使用 class 语句定义的,后跟类名(Car)。我们以冒号开始缩进的代码块。
* 我们定义了两个变量,速度和启动。这是该类的所有实例都将拥有的数据。
* 接下来,我们定义了三个操作变量的方法。
在这些方法的定义中,我们遇到了一些奇特的东西:它们都有一个名为 self 的参数作为它们的第一个参数。
## Python 中的 self 是什么?
老实说,如果你问我的话,这是 Python 不太优雅的语言结构之一。
还记得我们调用 car 对象上的方法吗,比如`car.start()`?我们不必传递`self`变量,即使`start()`在类中被定义为`start(self)`。
事情是这样的:
* 当我们在 Python 对象上调用一个方法时Python 会自动填充第一个变量,按照惯例我们称之为 self。
* 第一个变量是对对象本身的引用,因此得名。
* 我们可以用这个变量来引用这个对象的其他实例变量和函数,比如`self.speed`和`self.start()`。
因此,只有在 Python 类定义内部,我们才使用`self`来引用作为实例一部分的变量。为了修改属于我们类的`started`变量,我们使用了`self.started`,而不仅仅是`started`。通过使用`self`,很明显我们操作的是这个实例中的一个变量,而不是在对象之外定义的、碰巧同名的其他变量。
## 创建多个 Python 对象
因为 Python 类只是一个蓝图,所以您可以用它来创建多个对象,就像您可以构建多辆外观相同的汽车一样。它们的行为都相似,但它们都有自己的数据,这些数据不在对象之间共享:
```py
>>> car1 = Car()
>>> car2 = Car()
>>> id(car1)
139771129539104
>>> id(car2)
139771129539160
```
我们在这里创建了两个 car 对象car1 和 car2并使用内置方法 id()来获取它们的 id。Python 中的每个对象都有一个惟一的标识符,所以我们刚刚证明了我们从同一个类中创建了两个不同的对象。我们可以独立使用它们:
```py
>>> car1.start()
Car started, let's ride!
>>> car1.increase_speed(10)
'Vrooom!'
>>> car1.speed
10
>>> car2.speed
0
```
我们刚刚启动了`car1`并提高了它的速度,而`car2`仍然处于暂停状态。对速度的检查证实了这些是不同状态的不同汽车!
## 继续学习
* 您可能也会对 [Python 数据类](https://python.land/python-data-classes)感兴趣
* [如何从函数中返回多个值](https://python.land/return-multiple-values-from-function)
* 关于课程的官方文件