更新了QQ交流群信息
parent
49ac6b8329
commit
e09c8de84f
Binary file not shown.
After Width: | Height: | Size: 393 KiB |
Binary file not shown.
After Width: | Height: | Size: 268 KiB |
|
@ -48,8 +48,14 @@ python --version
|
||||||
|
|
||||||
macOS自带了Python 2,但是我们需要安装和使用的是Python 3。可以通过Python官方网站提供的[下载链接](<https://www.python.org/downloads/release/python-376/>)找到适合macOS的“macOS installer”来安装Python 3,安装过程基本不需要做任何勾选,直接点击“下一步”即可。安装完成后,可以在macOS的“终端”工具中输入`python3`命令来调用Python 3解释器,因为如果直接输入`python`,将会调用Python 2的解释器。
|
macOS自带了Python 2,但是我们需要安装和使用的是Python 3。可以通过Python官方网站提供的[下载链接](<https://www.python.org/downloads/release/python-376/>)找到适合macOS的“macOS installer”来安装Python 3,安装过程基本不需要做任何勾选,直接点击“下一步”即可。安装完成后,可以在macOS的“终端”工具中输入`python3`命令来调用Python 3解释器,因为如果直接输入`python`,将会调用Python 2的解释器。
|
||||||
|
|
||||||
> **说明**:如果对安装Python环境有任何疑问,可以参考我们在**百度云盘**上提供的**视频讲解**。链接:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。如果愿意,也可以加入我们的**QQ交流群**来获得帮助,群号:**789050736**。
|
> **说明**:如果对安装Python环境有任何疑问,可以参考我们在**百度云盘**上提供的**视频讲解**。链接:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
||||||
|
|
||||||
### 总结
|
### 总结
|
||||||
|
|
||||||
到这里,大家已经对Python语言有一个基本的了解,知道它可以做很多的事情,所以也值得我们去学习。要用Python做开发,首先需要在自己的计算机上安装Python环境,上面我们为大家介绍了macOS和Windows两种环境下Python 3环境的安装方法,希望大家都能顺利的安装成功,以便开启我们后续的学习。如果安装过程中遇到任何问题,可以联系博主加入我们的免费体验课或答疑群。
|
到这里,大家已经对Python语言有一个基本的了解,知道它可以做很多的事情,所以也值得我们去学习。要用Python做开发,首先需要在自己的计算机上安装Python环境,上面我们为大家介绍了macOS和Windows两种环境下Python 3环境的安装方法,希望大家都能顺利的安装成功,以便开启我们后续的学习。如果安装过程中遇到任何问题,可以联系博主加入我们的免费体验课或答疑群。
|
||||||
|
|
||||||
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -79,4 +79,8 @@ print("你好,世界!")
|
||||||
|
|
||||||
到这里,我们已经把第一个Python程序运行起来了,是不是很有成就感?只要你坚持学习下去,再过一段时间,我就可以带着大家用Python程序制作小游戏、写美女图片爬虫、开发微信机器人。**写程序本身就是一件很酷的事情**,在未来编程就像英语一样,**对很多人来说或都是必须要掌握的技能**。
|
到这里,我们已经把第一个Python程序运行起来了,是不是很有成就感?只要你坚持学习下去,再过一段时间,我就可以带着大家用Python程序制作小游戏、写美女图片爬虫、开发微信机器人。**写程序本身就是一件很酷的事情**,在未来编程就像英语一样,**对很多人来说或都是必须要掌握的技能**。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -109,4 +109,8 @@ print(ord('a')) # 97
|
||||||
|
|
||||||
在Python程序中,我们可以**使用变量来保存数据**,**变量有不同的类型**,**变量可以做运算**(下一课会有详细的讲解),**也可以通过内置函数来转换变量类型**。
|
在Python程序中,我们可以**使用变量来保存数据**,**变量有不同的类型**,**变量可以做运算**(下一课会有详细的讲解),**也可以通过内置函数来转换变量类型**。
|
||||||
|
|
||||||
>**温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
>**温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
>付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
>免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -148,4 +148,8 @@ print(is_leap)
|
||||||
|
|
||||||
通过上面的例子相信大家感受到了,学会使用运算符以及由运算符构成的表达式,就可以帮助我们解决很多实际的问题,**运算符和表达式对于任何一门编程语言都是非常重要的**。
|
通过上面的例子相信大家感受到了,学会使用运算符以及由运算符构成的表达式,就可以帮助我们解决很多实际的问题,**运算符和表达式对于任何一门编程语言都是非常重要的**。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -143,5 +143,9 @@ else:
|
||||||
|
|
||||||
学会了Python中的分支结构和循环结构,我们就可以用Python程序来解决很多实际的问题了。这一节课相信已经帮助大家记住了`if`、`elif`、`else`这几个关键字以及如何使用它们来构造分支结构,下一节课我们为大家介绍循环结构,学完这两次课你一定会发现,你能写出很多很多非常有意思的代码。坚持努力,继续加油!
|
学会了Python中的分支结构和循环结构,我们就可以用Python程序来解决很多实际的问题了。这一节课相信已经帮助大家记住了`if`、`elif`、`else`这几个关键字以及如何使用它们来构造分支结构,下一节课我们为大家介绍循环结构,学完这两次课你一定会发现,你能写出很多很多非常有意思的代码。坚持努力,继续加油!
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
||||||
|
|
|
@ -153,4 +153,8 @@ for factor in range(x, 0, -1):
|
||||||
|
|
||||||
学会了Python中的分支结构和循环结构,我们就可以解决很多实际的问题了。通过这节课的学习,大家应该已经知道了可以用`for`和`while`关键字来构造循环结构。**如果知道循环的次数,我们通常使用**`for`**循环**;如果**循环次数不能确定,可以用**`while`**循环**。在循环中还**可以使用**`break`**来提前结束循环**。
|
学会了Python中的分支结构和循环结构,我们就可以解决很多实际的问题了。通过这节课的学习,大家应该已经知道了可以用`for`和`while`关键字来构造循环结构。**如果知道循环的次数,我们通常使用**`for`**循环**;如果**循环次数不能确定,可以用**`while`**循环**。在循环中还**可以使用**`break`**来提前结束循环**。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
|
@ -165,5 +165,9 @@ for num in range(2, 100):
|
||||||
|
|
||||||
还是那句话:**分支结构和循环结构非常重要**,是构造程序逻辑的基础,**一定要通过大量的练习来达到融会贯通**。刚才讲到的CRAPS赌博游戏那个例子可以作为一个标准,如果你能很顺利的完成这段代码,那么分支和循环结构的知识你就已经掌握了。
|
还是那句话:**分支结构和循环结构非常重要**,是构造程序逻辑的基础,**一定要通过大量的练习来达到融会贯通**。刚才讲到的CRAPS赌博游戏那个例子可以作为一个标准,如果你能很顺利的完成这段代码,那么分支和循环结构的知识你就已经掌握了。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
||||||
|
|
|
@ -276,4 +276,8 @@ Python标准库中还有一类函数是不需要`import`就能够直接使用的
|
||||||
|
|
||||||
**函数是功能相对独立且会重复使用的代码的封装**。学会使用定义和使用函数,就能够写出更为优质的代码。当然,Python语言的标准库中已经为我们提供了大量的模块和常用的函数,用好这些模块和函数就能够用更少的代码做更多的事情。
|
**函数是功能相对独立且会重复使用的代码的封装**。学会使用定义和使用函数,就能够写出更为优质的代码。当然,Python语言的标准库中已经为我们提供了大量的模块和常用的函数,用好这些模块和函数就能够用更少的代码做更多的事情。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -378,4 +378,9 @@ print(s.strip()) # jackfrued@126.com
|
||||||
|
|
||||||
知道如何表示和操作字符串对程序员来说是非常重要的,因为我们需要处理文本信息,Python中操作字符串可以用拼接、切片等运算符,也可以使用字符串类型的方法。
|
知道如何表示和操作字符串对程序员来说是非常重要的,因为我们需要处理文本信息,Python中操作字符串可以用拼接、切片等运算符,也可以使用字符串类型的方法。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
||||||
|
|
|
@ -118,4 +118,8 @@ while True:
|
||||||
|
|
||||||
在写代码尤其是开发商业项目的时候,一定要有意识的**将相对独立且重复出现的功能封装成函数**,这样不管是自己还是团队的其他成员都可以通过调用函数的方式来使用这些功能。字符串是非常重要的数据类型,**字符串的常用运算和方法需要掌握**,因为一般的商业项目中,处理字符串比处理数值的操作要更多。
|
在写代码尤其是开发商业项目的时候,一定要有意识的**将相对独立且重复出现的功能封装成函数**,这样不管是自己还是团队的其他成员都可以通过调用函数的方式来使用这些功能。字符串是非常重要的数据类型,**字符串的常用运算和方法需要掌握**,因为一般的商业项目中,处理字符串比处理数值的操作要更多。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**,当然也可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r。
|
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:<https://pan.baidu.com/s/10y7sGM016YBM7gDdauGqLw>,密码:4s6r,也可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -299,5 +299,9 @@ print(scores) # [[95, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
|
||||||
|
|
||||||
Python中的列表底层是一个可以动态扩容的数组,列表元素在内存中也是连续存储的,所以可以实现随机访问(通过一个有效的索引获取到对应的元素且操作时间与列表元素个数无关)。我们暂时不去触碰这些底层存储细节以及列表每个方法的渐近时间复杂度(执行这个方法耗费的时间跟列表元素个数的关系),等需要的时候再告诉大家。现阶段,大家只需要知道**列表是容器**,可以**保存各种类型的数据**,**可以通过索引操作列表元素**就可以了。
|
Python中的列表底层是一个可以动态扩容的数组,列表元素在内存中也是连续存储的,所以可以实现随机访问(通过一个有效的索引获取到对应的元素且操作时间与列表元素个数无关)。我们暂时不去触碰这些底层存储细节以及列表每个方法的渐近时间复杂度(执行这个方法耗费的时间跟列表元素个数的关系),等需要的时候再告诉大家。现阶段,大家只需要知道**列表是容器**,可以**保存各种类型的数据**,**可以通过索引操作列表元素**就可以了。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**。
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
||||||
|
|
|
@ -203,4 +203,8 @@ def find_max_and_min(items):
|
||||||
|
|
||||||
**列表和元组都是容器型的数据类型**,即一个变量可以保存多个数据。**列表是可变数据类型**,**元组是不可变数据类型**,所以列表添加元素、删除元素、清空、排序等方法对于元组来说是不成立的。但是列表和元组都可以进行**拼接**、**成员运算**、**索引和切片**这些操作,就如同之前讲到的字符串类型一样,因为字符串就是字符按一定顺序构成的序列,在这一点上三者并没有什么区别。我们**推荐大家使用列表的生成式语法来创建列表**,它很好用,也是Python中非常有特色的语法。
|
**列表和元组都是容器型的数据类型**,即一个变量可以保存多个数据。**列表是可变数据类型**,**元组是不可变数据类型**,所以列表添加元素、删除元素、清空、排序等方法对于元组来说是不成立的。但是列表和元组都可以进行**拼接**、**成员运算**、**索引和切片**这些操作,就如同之前讲到的字符串类型一样,因为字符串就是字符按一定顺序构成的序列,在这一点上三者并没有什么区别。我们**推荐大家使用列表的生成式语法来创建列表**,它很好用,也是Python中非常有特色的语法。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**。
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -178,4 +178,8 @@ for person in persons:
|
||||||
|
|
||||||
**列表和元组都很重要**,学会这两种数据类型,我们能做的事情又多了很多。
|
**列表和元组都很重要**,学会这两种数据类型,我们能做的事情又多了很多。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**。
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
|
@ -186,4 +186,8 @@ print(set1 < set2) # False
|
||||||
|
|
||||||
Python中的集合底层使用了**哈希存储**的方式,对于这一点我们暂时不做介绍,在后面的课程有需要的时候再为大家讲解集合的底层原理,现阶段大家只需要知道**集合是一种容器**,元素必须是`hashable`类型,与列表不同的地方在于集合中的元素**没有序**、**不能用索引运算**、**不能重复**。
|
Python中的集合底层使用了**哈希存储**的方式,对于这一点我们暂时不做介绍,在后面的课程有需要的时候再为大家讲解集合的底层原理,现阶段大家只需要知道**集合是一种容器**,元素必须是`hashable`类型,与列表不同的地方在于集合中的元素**没有序**、**不能用索引运算**、**不能重复**。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**。
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
|
@ -190,4 +190,8 @@ print(stocks2)
|
||||||
|
|
||||||
Python程序中的字典跟现实生活中字典非常像,允许我们**以键值对的形式保存数据**,再**通过键索引对应的值**。这是一种非常**有利于数据检索**的数据类型,底层原理我们在后续的课程中再研究。再次提醒大家注意,**字典中的键必须是不可变类型**,字典中的值可以是任意类型。
|
Python程序中的字典跟现实生活中字典非常像,允许我们**以键值对的形式保存数据**,再**通过键索引对应的值**。这是一种非常**有利于数据检索**的数据类型,底层原理我们在后续的课程中再研究。再次提醒大家注意,**字典中的键必须是不可变类型**,字典中的值可以是任意类型。
|
||||||
|
|
||||||
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问,群号:**789050736**。
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
|
@ -0,0 +1,238 @@
|
||||||
|
## 第016课:面向对象编程入门
|
||||||
|
|
||||||
|
面向对象编程是一种非常流行的**编程范式**(programming paradigm),所谓编程范式就是**程序设计的方法学**,也就是程序员对程序的认知和理解。
|
||||||
|
|
||||||
|
前面的课程中我们说过“**程序是指令的集合**”,运行程序时,程序中的语句会变成一条或多条指令,然后由CPU(中央处理器)去执行。为了简化程序的设计,我们又讲到了函数,**把相对独立且经常重复使用的代码放置到函数中**,在需要使用这些代码的时候调用函数即可。如果一个函数的功能过于复杂和臃肿,我们又可以进一步**将函数进一步拆分为多个子函数**来降低系统的复杂性。
|
||||||
|
|
||||||
|
不知大家是否发现,我们所谓的编程其实是写程序的人按照计算机的工作方式通过代码控制机器完成任务。但是,计算机的工作方式与人类正常的思维模式是不同的,如果编程就必须抛弃人类正常的思维方式去迎合计算机,编程的乐趣就少了很多,而“每个人都应该学习编程”这样的豪言壮语也就只能喊喊口号而已。不是说我们不能按照计算机的工作方式去编写代码,但是当我们需要开发一个复杂的系统时,这种方式会让代码过于复杂,从而导致开发和维护工作都变得举步维艰,这也就是上世纪60年代末,出现了“软件危机”、“软件工程”这些概念的原因。
|
||||||
|
|
||||||
|
随着软件复杂性的增加,解决“软件危机”就成了软件开发者必须直面的问题。诞生于上世纪70年代的Smalltalk语言让软件开发者看到了希望,因为它引入了一种新的编程范式叫面向对象编程。在面向对象编程的世界里,程序中的**数据和操作数据的函数是一个逻辑上的整体**,我们称之为**对象**,**对象可以接收消息**,解决问题的方法就是**创建对象并向对象发出各种各样的消息**;通过消息传递,程序中的多个对象可以协同工作,这样就能构造出复杂的系统并解决现实中的问题。当然,面向对象编程的雏形还可以向前追溯到更早期的Simula语言,但这不是我们现在要讨论的重点。
|
||||||
|
|
||||||
|
> **说明:** 今天我们使用的很多高级程序设计语言都支持面向对象编程,但是面向对象编程也不是解决软件开发中所有问题的“银弹”,或者说在软件开发这个行业目前还找不到这种所谓的“银弹”。
|
||||||
|
|
||||||
|
### 类和对象
|
||||||
|
|
||||||
|
如果要用一句话来概括面向对象编程,我认为下面的说法是相当精准的。
|
||||||
|
|
||||||
|
> **面向对象编程**:把一组数据和处理数据的方法组成**对象**,把行为相同的对象归纳为**类**,通过**封装**隐藏对象的内部细节,通过**继承**实现类的特化和泛化,通过**多态**实现基于对象类型的动态分派。
|
||||||
|
|
||||||
|
这句话对初学者来说可能难以理解,但是我们先为大家圈出几个关键词:**对象**(object)、**类**(class)、**封装**(encapsulation)、**继承**(inheritance)、**多态**(polymorphism)。
|
||||||
|
|
||||||
|
我们先说说类和对象这两个词。在面向对象编程中,**类是一个抽象的概念,对象是一个具体的概念**。我们把同一类对象的共同特征抽取出来就是一个类,比如我们经常说的人类,这是一个抽象概念,而我们每个人就是人类的这个抽象概念下的具体的实实在在的存在,也就是一个对象。简而言之,**类是对象的蓝图和模板,对象是类的实例**。
|
||||||
|
|
||||||
|
在面向对象编程的世界中,**一切皆为对象**,**对象都有属性和行为**,**每个对象都是独一无二的**,而且**对象一定属于某个类**。对象的属性是对象的静态特征,对象的行为是对象的动态特征。按照上面的说法,如果我们把拥有共同特征的对象的属性和行为都抽取出来,就可以定义出一个类。
|
||||||
|
|
||||||
|
![](./res/object-feature.png)
|
||||||
|
|
||||||
|
### 定义类
|
||||||
|
|
||||||
|
在Python中,可以使用`class`关键字加上类名来定义类,通过缩进我们可以确定类的代码块,就如同定义函数那样。在类的代码块中,我们需要写一些函数,我们说过类是一个抽象概念,那么这些函数就是我们对一类对象共同的动态特征的提取。写在类里面的函数我们通常称之为**方法**,方法就是对象的行为,也就是对象可以接收的消息。方法的第一个参数通常都是`self`,它代表了接收这个消息的对象本身。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
class Student:
|
||||||
|
|
||||||
|
def study(self, course_name):
|
||||||
|
print(f'学生正在学习{course_name}.')
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
print(f'学生正在玩游戏.')
|
||||||
|
```
|
||||||
|
|
||||||
|
### 创建和使用对象
|
||||||
|
|
||||||
|
在我们定义好一个类之后,可以使用构造器语法来创建对象,代码如下所示。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
stu1 = Student()
|
||||||
|
stu2 = Student()
|
||||||
|
print(stu1) # <__main__.Student object at 0x10ad5ac50>
|
||||||
|
print(stu2) # <__main__.Student object at 0x10ad5acd0>
|
||||||
|
print(hex(id(stu1)), hex(id(stu2))) # 0x10ad5ac50 0x10ad5acd0
|
||||||
|
```
|
||||||
|
|
||||||
|
在类的名字后跟上圆括号就是所谓的构造器语法,上面的代码创建了两个学生对象,一个赋值给变量`stu1`,一个复制给变量`stu2`。当我们用`print`函数打印`stu1`和`stu2`两个变量时,我们会看到输出了对象在内存中的地址(十六进制形式),跟我们用`id`函数查看对象标识获得的值是相同的。现在我们可以告诉大家,我们定义的变量其实保存的是一个对象在内存中的逻辑地址(位置),通过这个逻辑地址,我们就可以在内存中找到这个对象。所以`stu3 = stu2`这样的赋值语句并没有创建新的对象,只是用一个新的变量保存了已有对象的地址。
|
||||||
|
|
||||||
|
接下来,我们尝试给对象发消息,即调用对象的方法。刚才的`Student`类中我们定义了`study`和`play`两个方法,两个方法的第一个参数`self`代表了接收消息的学生对象,`study`方法的第二个参数是学习的课程名称。Python中,给对象发消息有两种方式,请看下面的代码。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
# 通过“类.方法”调用方法,第一个参数是接收消息的对象,第二个参数是学习的课程名称
|
||||||
|
Student.study(stu1, 'Python程序设计') # 学生正在学习Python程序设计.
|
||||||
|
# 通过“对象.方法”调用方法,点前面的对象就是接收消息的对象,只需要传入第二个参数
|
||||||
|
stu1.study('Python程序设计') # 学生正在学习Python程序设计.
|
||||||
|
|
||||||
|
Student.play(stu2) # 学生正在玩游戏.
|
||||||
|
stu2.play() # 学生正在玩游戏.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 初始化方法
|
||||||
|
|
||||||
|
大家可能已经注意到了,刚才我们创建的学生对象只有行为没有属性,如果要给学生对象定义属性,我们可以修改`Student`类,为其添加一个名为`__init__`的方法。在我们调用`Student`类的构造器创建对象时,首先会在内存中获得保存学生对象所需的内存空间,然后通过自动执行`__init__`方法,完成对内存的初始化操作,也就是把数据放到内存空间中。所以我们可以通过给`Student`类添加`__init__`方法的方式为学生对象指定属性,同时完成对属性赋初始值的操作,正因如此,`__init__`方法通常也被称为初始化方法。
|
||||||
|
|
||||||
|
我们对上面的`Student`类稍作修改,给学生对象添加`name`(姓名)和`age`(年龄)两个属性。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
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}正在玩游戏.')
|
||||||
|
```
|
||||||
|
|
||||||
|
修改刚才创建对象和给对象发消息的代码,重新执行一次,看看程序的执行结果有什么变化。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
# 由于初始化方法除了self之外还有两个参数
|
||||||
|
# 所以调用Student类的构造器创建对象时要传入这两个参数
|
||||||
|
stu1 = Student('骆昊', 40)
|
||||||
|
stu2 = Student('王大锤', 15)
|
||||||
|
stu1.study('Python程序设计') # 骆昊正在学习Python程序设计.
|
||||||
|
stu2.play() # 王大锤正在玩游戏.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 打印对象
|
||||||
|
|
||||||
|
上面我们通过`__init__`方法在创建对象时为对象绑定了属性并赋予了初始值。在Python中,以两个下划线`__`(读作“dunder”)开头的方法通常都是有特殊用途和意义的方法,我们一般称之为**魔术方法**或**魔法方法**。如果我们在打印对象的时候不希望看到对象的地址而是看到我们自定义的信息,可以通过在类中放置`__repr__`魔术方法来做到,该方法返回的字符串就是用`print`函数打印对象的时候会显示的内容,代码如下所示。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
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('骆昊', 40)
|
||||||
|
print(stu1) # 骆昊: 40
|
||||||
|
students = [stu1, Student('王小锤', 16), Student('王大锤', 25)]
|
||||||
|
print(students) # [骆昊: 40, 王小锤: 16, 王大锤: 25]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 面向对象的支柱
|
||||||
|
|
||||||
|
面向对象编程有三大支柱,就是我们之前给大家划重点的时候圈出的三个词:封装、继承和多态。后面两个概念在下一节课中会详细说明,这里我们先说一下什么是封装。我自己对封装的理解是:**隐藏一切可以隐藏的实现细节,只向外界暴露简单的调用接口**。我们在类中定义的对象方法其实就是一种封装,这种封装可以让我们在创建对象之后,只需要给对象发送一个消息就可以执行方法中的代码,也就是说我们在只知道方法的名字和参数(方法的外部视图),不知道方法内部实现细节(方法的内部视图)的情况下就完成了对方法的使用。
|
||||||
|
|
||||||
|
举一个例子,假如要控制一个机器人帮我倒杯水,如果不使用面向对象编程,不做任何的封装,那么就需要向这个机器人发出一系列的指令,如站起来、向左转、向前走5步、拿起面前的水杯、向后转、向前走10步、弯腰、放下水杯、按下出水按钮、等待10秒、松开出水按钮、拿起水杯、向右转、向前走5步、放下水杯等,才能完成这个简单的操作,想想都觉得麻烦。按照面向对象编程的思想,我们可以将倒水的操作封装到机器人的一个方法中,当需要机器人帮我们倒水的时候,只需要向机器人对象发出倒水的消息就可以了,这样做不是更好吗?
|
||||||
|
|
||||||
|
在很多场景下,面向对象编程其实就是一个三步走的问题。第一步定义类,第二步创建对象,第三步给对象发消息。当然,有的时候我们是不需要第一步的,因为我们想用的类可能已经存在了。之前我们说过,Python内置的`list`、`set`、`dict`其实都不是函数而是类,如果要创建列表、集合、字典对象,我们就不用自定义类了。当然,有的类并不是Python标准库中直接提供的,它可能来自于第三方的代码,如何安装和使用三方代码在后续课程中会进行讨论。在某些特殊的场景中,我们会用到名为“内置对象”的对象,所谓“内置对象”就是说上面三步走的第一步和第二步都不需要了,因为类已经存在而且对象已然创建过了,直接向对象发消息就可以了,这也就是我们常说的“开箱即用”。
|
||||||
|
|
||||||
|
### 经典案例
|
||||||
|
|
||||||
|
#### 例子1:定义一个类描述数字时钟。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
# 定义数字时钟类
|
||||||
|
class Clock(object):
|
||||||
|
"""数字时钟"""
|
||||||
|
|
||||||
|
def __init__(self, hour=0, minute=0, second=0):
|
||||||
|
"""初始化方法
|
||||||
|
:param hour: 时
|
||||||
|
:param minute: 分
|
||||||
|
:param second: 秒
|
||||||
|
"""
|
||||||
|
self.hour = hour
|
||||||
|
self.min = minute
|
||||||
|
self.sec = second
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""走字"""
|
||||||
|
self.sec += 1
|
||||||
|
if self.sec == 60:
|
||||||
|
self.sec = 0
|
||||||
|
self.min += 1
|
||||||
|
if self.min == 60:
|
||||||
|
self.min = 0
|
||||||
|
self.hour += 1
|
||||||
|
if self.hour == 24:
|
||||||
|
self.hour = 0
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
"""显示时间"""
|
||||||
|
return f'{self.hour:0>2d}:{self.min:0>2d}:{self.sec:0>2d}'
|
||||||
|
|
||||||
|
|
||||||
|
# 创建时钟对象
|
||||||
|
clock = Clock(23, 59, 58)
|
||||||
|
while True:
|
||||||
|
# 给时钟对象发消息读取时间
|
||||||
|
print(clock.show())
|
||||||
|
# 休眠1秒钟
|
||||||
|
time.sleep(1)
|
||||||
|
# 给时钟对象发消息使其走字
|
||||||
|
clock.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 例子2:定义一个类描述平面上的点,要求提供计算到另一个点距离的方法。
|
||||||
|
|
||||||
|
```Python
|
||||||
|
class Point(object):
|
||||||
|
"""屏面上的点"""
|
||||||
|
|
||||||
|
def __init__(self, x=0, y=0):
|
||||||
|
"""初始化方法
|
||||||
|
:param x: 横坐标
|
||||||
|
:param y: 纵坐标
|
||||||
|
"""
|
||||||
|
self.x, self.y = x, y
|
||||||
|
|
||||||
|
def distance_to(self, other):
|
||||||
|
"""计算与另一个点的距离
|
||||||
|
:param other: 另一个点
|
||||||
|
"""
|
||||||
|
dx = self.x - other.x
|
||||||
|
dy = self.y - other.y
|
||||||
|
return (dx * dx + dy * dy) ** 0.5
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'({self.x}, {self.y})'
|
||||||
|
|
||||||
|
|
||||||
|
p1 = Point(3, 5)
|
||||||
|
p2 = Point(6, 9)
|
||||||
|
print(p1, p2)
|
||||||
|
print(p1.distance_to(p2))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 简单的总结
|
||||||
|
|
||||||
|
面向对象编程是一种非常流行的编程范式,除此之外还有**指令式编程**、**函数式编程**等编程范式。由于现实世界是由对象构成的,而对象是可以接收消息的实体,所以**面向对象编程更符合人类正常的思维习惯**。类是抽象的,对象是具体的,有了类就能创建对象,有了对象就可以接收消息,这就是面向对象编程的基础。定义类的过程是一个抽象的过程,找到对象公共的属性属于数据抽象,找到对象公共的方法属于行为抽象。抽象的过程是一个仁者见仁智者见智的过程,对同一类对象进行抽象可能会得到不同的结果,如下图所示。
|
||||||
|
|
||||||
|
![](res/abstraction.png)
|
||||||
|
|
||||||
|
> **说明:** 本节课的插图来自于 Grady Booc 等撰写的《面向对象分析与设计》一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。
|
||||||
|
|
||||||
|
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
|
||||||
|
>
|
||||||
|
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
|
||||||
|
>
|
||||||
|
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。
|
||||||
|
|
Loading…
Reference in New Issue