概述

Python 是一个非常友好的高级语言,Python 的特点比如:面向对象,动态类型,交互式执行,万金油,胶水语言。 Python 类似于 Java,不允许直接操作内存,底层实现了垃圾收集机制(GC)。

Python 在轻量级的使用上无疑是非常香的,并且现在在数据科学领域也达到了称霸的地位。 虽然我同时也在主要使用 C++,但是 C++ 语法的复杂程度让我从来没有写完整 C++ 学习笔记的打算,Python 倒是可以尝试一下。

正所谓:人生苦短,我用 Python

接下来的笔记并不是具有顺序性的,内容会相互交叉,因为如果非要对笔记进行先后排序,就必须将函数、类等重要内容拆成基础和进阶部分来写,但作为整理性质的笔记,并没有这个必要。

关于 Python 绘图的部分,我计划专门写一个系列关于 Python 数据可视化的笔记。

主要参考官方教程官方文档,前者适合入门,而后者在概念理解上更加详细。

Python 常识

解释器

和 c/c++这种编译型语言不同,Python 作为解释型语言,需要 Python 解释器才能运行,Python 解释器有很多不同的实现:

  • CPython 是默认使用的 Python 解释器,基于 c 语言开发,输入提示符是 >>>
  • IPython 是基于 CPython 的一个交互式解释器,在交互方式上进行了增强和优化,输入提示符是 In[]=,参考了 Mathematica 的 notebook 的设计风格,Jupyter 也是基于 IPython 的。
  • PyPy 是另一个基于 Python 语言的 Python 解释器,输入提示符是 >>>>。PyPy 采用 JIT 技术,对 Python 代码进行动态编译,可以显著提高 Python 代码的执行速度。但是 PyPy 和 CPython 的实现不完全相同,并且在调用 c 实现的模块时比 CPython更差。
  • Jython 是运行在 Java 平台上的 Python 解释器,可以把 Python 代码编译成 Java 字节码执行。

注意:CPython是Python的标准实现,有一个与之相似的概念是Cython,这是一个可以将Python程序转换为c语言实现,用于程序加速的工具。

执行方式

基本的执行方式:

  1. 通过 Windows 平台的 powershell/cmd,输入 Python 打开解释器,逐行输入 Python 语句然后执行;
  2. 执行 xxx.py 脚本,例如 Python xxx.py,注意在 Linux/MAC 系统中,Python 可能会指代系统内部的 2.x 版本 Python,Python 3 才是 3.x 版本;
  3. 在 Linux 的 shell 中,还可以直接输入 xxx.py 来执行,但是需要在 Python 脚本第一行指定例如 #!/usr/bin/env python3,并且给脚本赋予执行权限。

常见的 Python 的 IDE:

  1. IDLE,最朴素的 IDE,下载 CPython 时自带的。(除了学习 Python 的教程,其它时候几乎没人用)
  2. PyCharm,专业的 IDE,但是我不喜欢专门下载一个用来写 Python。

还可以通过通用编辑器例如 VSCode 加上相关插件来编写执行,也可以使用 Jupyter notebook 交互式执行(在浏览器或者 VScode 中)。

Python2.x 和 3.x 的区别

从 Python 2.x 到 Python 3.x 进行了一次不向下兼容的更新,两个大版本之间具有巨大的差异,2.x 已经是被废弃的版本,但是在很多 Linux 系统中还会存在基于 Python 2 的程序,3.x 版本甩掉了 2.x 版本的很多历史包袱,主要包括:

  1. 编码问题:2.x 的编码在处理中文等非 ASCII 码时比较麻烦,3.x 默认采用 unicode 编码 (UTF-8),更加方便
  2. Print 函数:2.x 把 print 作为一个特殊语句,3.x 则把 print 的使用调整为函数的语法
1
2
3
4
5
# 2.x
print "hello,world"

# 3.x
print("hello,world")
  1. 除法:2.x 默认的 / 除法有类似于 c 语言的自动整除规则,整数相除只能得到整数;而 3.x 默认的 / 除法对于两个整数也会返回一个浮点数。在两个版本中 // 都表示取整除法
  2. 不等号:2.x 允许使用的不等号包括 <>!=,3.x 只允许使用 != 表示不等号

此外还有一些细小的差异。总之,现在不要学习、尽量不要使用 2.x 版本的 Python。 截止到目前(2023 年 4 月),Python 最新的版本为 3.11.3,目前我使用的是 3.9 左右的版本。

Linux系统在默认情况下如果自带python命令,那么通常是2.7版本的Python。如果使用conda虚拟环境,此时python通常是3.x版本的Python。只有python2命令或python3命令对应的版本才是语义较为明确的。

Python 准备知识

一些关于 Python 语句的准备知识。

注释

# 开头代表单行注释,连续三个单引号 ''' 或连续三个双引号 """ 包裹的部分,代表多行注释(也是字符串)

1
2
3
4
5
6
7
8
9
10
11
12
# hi hello
print("I'm fine") # hi hello

'''
hi
hello
'''

"""
hi
hello
"""

标识符

标识符可以使用字母,下划线或数字组成,数字不能在开头。实际上在 Python 3 中,可以使用任何 Unicode 字符作为标识符,不需要局限于英文字母,但是仍然不建议使用英文和数字下划线之外的标识符。

标识符严格区分大小写。

对于下划线开头的标识符,通常有如下几种含义

  • _ABC,不会被 from XXX import * 导入的标识符,表示较弱的私有标识符
  • _,在交互式模式中,上一次执行的结果会默认赋值给 _,可以把一个不需要的变量赋值给 _
  • __ABC,在类当中,被用作私有方法,表示较强的私有标识符
  • __ABC__,Python 保留的特殊标识符,不要自行定义,否则会产生无法预期的错误。

关于常见的特殊字符:

  • # " ' \ 对于 Python 语法解析有重要含义
  • $ ? 还有esc下面的字符都是非法的 Python 字符,只允许在字符串中出现

保留关键字

Python 有若干保留关键字,这些词承担着重要的语法作用,不可以作为标识符。关于 Python 的保留关键字,可以使用 keyword 模块查看

1
2
3
4
5
6
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', '__peg_parser__', 'and', 'as', 'assert', 'async', 'await',
'break', 'class', 'continue','def', 'del', 'elif', 'else', 'except', 'finally',
'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda','nonlocal', 'not',
'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

层次结构

Python 既不像 c/c++/Java 一样使用大括号 {} 代表层次结构,也不像 MATLAB/Fortran 一样需要使用 end 标记,而是完全依靠缩进代表层次结构。 通常统一使用 4 个空格进行缩进,但这并不是必须的,也可以统一使用tab,或者统一使用2个空格等。注意缩进不能混用 tab 和空格。

Python 不允许任意地创建层次结构,只有在 if 语句、for 循环、函数定义等才可以使用统一的缩进创建一个子层次结构,并且这个子层次结构不能是空的。

如果存在缩进问题,报错如下

1
IndentationError: unexpected indent

因为缩进的检查非常困难,Python 经常被嘲笑为使用游标卡尺的语言。

语句

Python 语句不需要以 ; 结束,但是加了在执行时也不会报错,可以利用分号分隔可以把多个语句写在同一行,如果在末尾加了可能会被建议删除

1
2
print("hi")
print("hello"); print("I'm fine.")

跨行的语句(不包括注释),可以在上一行的结尾加上 \,这代表和接下来的一行拼接;注意 []{}() 括号内包含的语句不需要使用行继续符 (\),默认支持换行。

1
2
3
4
5
total = item_one + \
item_two + \
item_three
days = ['Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday']

Python作为动态语言有两个体现动态特点的命令,这两个命令可以直接将字符串视作任意语句来解释执行

  • eval:执行一个表达式,返回表达式的结果
  • exec:执行一段语句,即一个代码块,没有返回值

这两个操作是非常危险的,因为无法保证被执行的字符串是安全的,尤其是执行的字符串来源于用户时,执行的结果是不可控的。

例如

1
2
3
4
5
6
7
8
9
x = 10
result = eval('x * 2') # 返回 20


code = '''
for i in range(5):
print(i)
'''
exec(code)