上次教程中,我们简要介绍了 Python 安装与快速入门,本次教程将对 Python 数据类型、面向对象编程技术(OOP)初步、Python 模块与包进行简要介绍,并向大家推荐 Python 后续学习资料。
本教程假定读者已经了解并学会使用 Python 的基本数据类型,运算符,输入输出,字符串,流程控制,函数。如果对这些基础知识尚感迷茫,可以阅读“Python 教程Ⅰ丨环境安装与快速入门”,并认真练习。
Python 数据类型
上次介绍到 Python 内置数据类型有 bool
, int
, float
, complex
, str
,另外还有 list
, tuple
, set
, dict
四类。其中,bool
, int
, float
及 complex
与 C 语言中对应类型非常相似,所以本教程不再详述,而是将重点放在介绍 str
, list
, tuple
, set
, dict
五种数据类型上。由于操作函数方法较多,本篇教程无法完全涉及,大家可以参考教程后的参考资料继续深入学习。
str
类型
str
类型即字符串类型,较 C 语言,Python 中字符串支持许多编码格式,并且也有许多便利的运算方法。其中较常用的方法有 len
, ==
, +
, *
, in
, find
。
1 | s1 = 'hello, world' |
list
类型
list
类型即列表类型,与 C 中的动态数组类似,但使用更为方便。常用的方法有 len
, []
, append
, insert
, clear
, pop
, remove
, sort
, +
, *
。
1 | items = ['Python', 'Java', 'Go', 'Kotlin'] |
在使用列表重复(*
)运算时,要注意可能出现的问题,例如:
1 | scores = [[0] * 3] * 5 |
正确的做法应该是:
1 | scores = [[0] * 3 for _ in range(5)] |
tuple
类型
tuple
类型即元组类型,类似一个不能改变元素的列表。元组常用于函数多变量返回,变量打包、解包中。
1 | a = (1, 10, 100) # 打包 |
同时,我们可以借助 *
,完成不定长元素的推测解包。需要注意,一个解包语句中只能出现一个 *
,否则会产生歧义,编译器将不能理解如何解包。
1 | a = 1, 10, 100, 1000 |
set
类型
set
类型即集合类型,集合具有确定性、无序性和互异性,常用的有交并差及对称差。注意集合的运算使用的是 Python 中的位运算符。
1 | set1 = {1, 2, 3, 3, 3, 2} |
dict
类型
dict
类型即字典类型,通过键值对存储和访问数据。常用的有 items
, keys
, values
, pop
等方法,类似列表生成式,也有字典生成式。
1 | person = { |
小结
以上几种数据类型构成了 Python 编程的基础,大家从这些数据类型的方法也能感受到 Python 语言的简洁与易理解。相比于 C 语言,Python 更希望程序员写出容易阅读的代码。
面向对象编程技术初步
面向对象是一种目前比较流行的编程方法,是一种程序设计的方法论。相对于面向过程的编程方法,面向对象更契合人类正常的思维方式,更适用于开发、维护复杂系统。在这种编程方法下,程序中的数据和数据操作函数是一个逻辑上的整体,这个整体被称为对象。引用一段对面向对象编程的精辟描述:
把一组数据和处理数据的方法组成对象,把行为相同的对象归纳为类,通过封装隐藏对象的内部细节,通过继承实现类的特化和泛化,通过多态实现基于对象类型的动态分派。
这句话并不那么好理解,接下来我们将进行一些解释。
在 Python 中,我们使用 class
关键字声明一个类,其语法结构为 class 类名:
,调用时,可以使用 .
运算符进行调用,具体参见下例:
1 | class Student: |
Python 魔术方法
提到类,就不得不先提一下 Python 的魔术方法。在 Python 中,所有以双下划线 __
包裹起来的方法,统称为魔术方法(Magic Method, 由于是双下划线,也可称 dunder),它是一种特殊的方法,往往不会显式地调用。魔术方法在类或对象的某些事件触发后会自动运行,让类具有神奇的“魔力”。Python 中的魔术方法很多,例如控制算术运算符的 __add__
, __mul__
等,控制比较运算符的 __eq__
等,还有控制类型转换、属性操作、构造析构的魔术方法。这里对常用的 __init__
, __repr__
稍作介绍。
__init__
初始化方法
__init__
方法类似 C++类中的构造函数。需要注意的是,__init__
函数的第一个参数为实例本身,通常名字为 self
,通过 self
可以访问实例的属性。
1 | class Student: |
__repr__
方法
__repr__
方法可以改变 print
函数的行为。
1 | class Student: |
封装
封装是为了便利代码的使用者,即程序员在编写类的过程中,隐藏一切可以隐藏的实现细节,只向外界暴露简单的调用接口。例如对于钟表类,可以定义 run
函数处理小时、分钟、秒的进位,使用者只需调用 run
即可。
1 | class Clock(object): |
在本例中,将时钟的进位与显示封装起来,外部调用时,只需要调用相应函数即可。
继承
面向对象的编程语言支持在已有类的基础上创建新类,从而减少重复代码的编写。提供继承信息的类叫做父类(超类、基类),得到继承信息的类叫做子类(派生类、衍生类)。由于 Python2.x 版本的遗留问题,虽然 Python3.x 已经不必显式继承 object
类,但依然建议大家显式继承。继承的语法为 class 类名(父类名):
1 | class Person(object): # 此处显式继承了 object 类 |
注意在本例中,重写了子类的 __init__
方法,如果不重写,将自动调用父类构造方法进行构造,如果重写,则默认不会调用,需要自己通过 super().__init__
调用父类构造方法。
Python 模块
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。Python 中每个文件就代表了一个模块(module)。使用模块可以大大提升代码可维护性,同时,也让编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其它模块,包括 Python 内置的模块和来自第三方的模块。
当然,使用模块还可以避免函数名和变量名冲突。相同名字的函数、变量可以分别存在不同的模块中。在使用模块时,可以使用 import
关键字导入。
例如在同一文件夹下,分别有 module1.py
, module2.py
, test.py
三个文件。
1 | def foo(): |
1 | def foo(): |
1 | import module1 |
除了自己编写的模块外,Python 本身还内置了许多模块,例如处理时间的 time
模块,处理文件系统的 os
模块等等。我们还可以自己安装第三方模块来进一步简化代码编写。例如 numpy
, pandas
等就属于非常出名的第三方模块。
限于篇幅,此处不再详述如何使用 conda,pip 管理模块,大家可以参考
安装模块的常用命令:
1 | conda install <package-name> |
1 | pip install numpy |
后续学习
以上是 Python 非常基础的语法,但 Python 核心语法不仅限于此。后续大家还可以学习 Python 标准库,文件读写,字符编码,正则表达式,面向对象进阶,函数式编程,各类包的使用(如 numpy,pandas)以至机器学习……
在这里,笔者再推荐几个网站。