Python3 - 基石

1 一般执行方式

有三种执行方式。

  • 一种是交互式。终端或命令行窗口下输入 python3 并回车,即可打开交互式环境。
  • 一种是命令行方式。终端或命令行窗口下,执行 python3 xxx.py
  • 还有一种是直接运行 .py 文件。

若要直接运行 .py 文件。可这样操作:

  • 首先,在要执行的.py文件的第一行加入一些字段: #!/usr/bin/env python3 表示在执行该 .py 文件时,将根据 /usr/bin/env 得到 PATH 环境变量,然后再根据 PATH 中的路径找到 python3 可执行程序。
  • 然后在终端执行以下命令: chmod a+x xxx.py 表示所有用户对 xxx.py 文件均有可执行权限。

2 执行参数

python 解释器还提供了众多参数,用得较多的有两个:

  • -m module名,用于执行这个 module 中的所有代码。比如: python3 -m pip install scipy
  • -X utf8,用于忽略 locale 的编码方式,而显示指定通过 utf-8 来解析文件。

3 符号标记与注释

C 的每条语句以 ; 号为结束标记。

而 Python3 中每条语句以换行符为结束标记,因此可以用 \ 来将一条语句写成多行的形式。

Python3 中一行也可以写多条语句,用 ; 号分开即可。

Python3 中的代码块不用大括号扩起来,而是在代码块前的那个语句的后面加上 : 号,然后引号下的第一句缩进一个 Tab 符。

按照约定俗成的风格,应该始终坚持使用 4 个空格的缩进。

在 Python 中,一般来说有两种注释符号。

  • 一种是 #...,对应 C++ 中的 //,用于对某一行进行注释;
  • 另一种是 """...""",它对应 C++ 中的 /*...*/,用于对连续的某几行进行注释(事实上它是一个含有多行的字符串)。

4 解释器读取文件时的解码

在 python2 中,解释器默认以 ASCII 解码 .py 文件。因而当源码里出现汉字时,解释器在执行时会报错。在这种情况下,需要在该源文件的第一行加上: # -*- coding: utf-8 -*-

如果存在 #!/usr/bin/env python3,则将这个字段加到第一行,将 # -*- coding: utf-8 -*- 加到第二行

python3 中会根据 locale 编码来解析文件。为了能够在任何平台上通过 utf-8 的编码方式解析文件,仍然需要像上面添加相应语句。

如果想使用 utf-8 来编写源码,需要确保文本编辑器正在使用 UTF-8 without BOM编码(去掉额外前部的 UTF-8 编码)。一般编辑器中,如果没有这个编码,就选择 UTF-8 编码。

5 文件规范

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# "写入这个.py文件的注释说明"
__author__ = "yourname"

......

if __name__ == "__main__":
......

其中,

  • 任何模块代码的第一个字符串都被视为模块的文档注释,可以通过 __doc__ 获取。
  • __author__ 变量用于定义作者的名字。
  • 当用命令行执行一个源文件时(源文件名当作命令行参数传递给 python3 可执行程序),Python 解释器会把该文件的一个特殊变量 __name__ 置为 __main__。而如果在其他地方导入该模块时,if 判断将失败。因此,常在每个模块中添加这种 if 语句,从而用来测试这个模块。

6 动态特性

Python 是一门动态语言,主要表现在:

  • 也就是说一个变量没有固定的类型,在运行期间是可以变化的。
  • 定义某个类的对象后,可以根据需要给该类添加属性和方法。
  • 还有就是符号的动态绑定了。

对于 Python 中的方法,只有在调用该方法时,才对该方法中的符号进行绑定。而且在进行绑定时,是从调用点处向前查找。

1
2
def func():
print(a)

执行该程序时不会报错,因为只是定义并未调用该方法。

除此之外,还可以很方便地实现类的多态特性。

7 引用变量与对象

Python 中,一切皆为对象,甚至包括基本数据类型。

Java 和 C++ 中,基础数据类型并非对象。

这些对象都是通过引用变量进行操作的(实质上是指针)。

在 C++ 中:

1
2
3
// 实质上,在内存中有两块区域。一块区域保存 a 的值,一块区域保存 b 的值。
int a = 3;
int b = a;

在 Python 中:

1
2
3
# 实质上,在内存中只有一块区域保存 3。而 a 和 b 只是两个引用变量,指向保存 3 的这块区域。
a = 3
b = a

8 可变对象与不可变对象

就是指对象本身是否可以通过提供的操作被改变。

内置的可变对象一般包括:

  • list
  • set
  • dict
  • bytearray

内置的不可变对象一般包括:

  • int
  • float
  • bool
  • tuple
  • str
  • bytes

9 全局变量与 global 关键字

虽然在方法内部可以读取所在该文件中任意位置的全局变量,但是一旦想修改这个引用变量,使其引用另外一个对象时,则该对象变量就不再是那个全局变量了,而是另外一个局部变量。

1
2
3
4
5
6
7
8
def func():
print(a)
# 这里会报错。
# UnboundLocalError: local variable 'a' referenced before assignment
a = 5

a = 3
func()

如果要解决这个问题,可以在使用该对象变量前用 global 关键字对其进行声明,显示地表示引用的是一个全局变量。

1
2
3
4
5
6
7
8
9
10
11
def func():
# 一定要在使用 a 之前对 a 进行 global 声明。
global a
# 3
print(a)
a = 4
# 4
print(a)

a = 3
func()

对某个对象变量的 global 声明一定要在使用这个对象变量之前进行。

10 type() 与 isinstance()

可以用 type() 方法来返回某个数据的类型,比如:

1
2
# 返回<class 'int'>
print(type(1))

可以用 isinstance 方法来确定某个数据是否是指定的数据类型,比如:

1
2
# 返回True
isinstance(1, int)

11 表达式和语句

表达式是语句的一部分,它与其他语句不一样的地方是有返回值。

1
2
3
a = print(2)
# None
print(a)

python2 中,print 是一般的语句,而非表达式语句;python3 中则是一个表达式语句。

非表达式语句比如:return、if...else...等。

12 赋值语句及链式赋值

python 中,= 连接起来的语句是个一般的赋值语句,而非表达式语句。

1
2
# 报错
print(a = 3)

python 中的链式赋值也与一般语言中不同。

1
a = b = c = 3

事实上等同于:

1
2
3
a = 3
b = a
c = a

这点可通过 dis module 查看汇编指令得到印证: python3 -m dis xxx.py

1
2
3
4
5
6
7
8
1             0 LOAD_CONST               0 (3)
2 DUP_TOP
4 STORE_NAME 0 (a)
6 DUP_TOP
8 STORE_NAME 1 (b)
10 STORE_NAME 2 (c)
12 LOAD_CONST 1 (None)
14 RETURN_VALUE

其中,

  • 首先,根据 LOAD_CONST 从常量表中读取 3 并压到栈中,同时对 3 的引用计数加 1(操作后为 1);
  • 根据 DUP_TOP 拷贝栈顶引用,也即对栈顶元素的引用计数加 1(操作后为 2);
  • 根据 STORE_NAME 将栈顶元素与 a 进行绑定;
  • 根据 DUP_TOP 拷贝栈顶引用,也即对栈顶元素的引用计数加 1(操作后为 3);
  • 根据 STORE_NAME 将栈顶元素与 b 进行绑定;
  • 根据 STORE_NAME 将栈顶元素与 c 进行绑定。

再比如:

1
2
3
4
5
a = [1, 2, 3]
i = 0
i = a[i] = 2
# 2 [1, 2, 2]
print(i, a)

13 其他

  • pydoc 命令类似于 Linux 中的 man,专门用以查看 Python 中一些方法的声明。
  • 对于某个可迭代的可变对象,当用它的迭代器遍历该对象时,不能对这个对象执行添加或删除操作,否则会导致迭代器实效。
  • Python 中,= 号可以用来进行多个变量的赋值。例如:
    1
    2
    3
    4
    a = 1
    b = 2
    # 先计算 = 号右边的每个表达式的值,这里 b 为 1,a + b 为 3,然后再将表达式的值赋值给左边相应的变量。因此 a 为 2,b 为 3。
    a, b = b, a + b

如果写成以下的形式,则会得到不一样的结果:

1
2
3
4
5
a = 1
b = 2
a = b
# a 为 2,b 为 4,因为 a 已经变化了
b = a + b

Reference