The Python Tutorial

执行

运算符优先级

参考

交互模式 _ 变量

在交互模式中,最后一个printed expression会被赋值到 _ 变量中。使用该变量时,应该把它作为一个只读类型的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> _ # 交互模式初始化是 _ 变量不存在
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
_
NameError: name '_' is not defined
>>> a=3
>>> _
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
_
NameError: name '_' is not defined
>>> b=4
>>> a+b
7
>>> _
7
>>> c=5
>>> _
7
>>> c+_
12
>>> _
12
>>>

脚本文件的Shebang行

Unix系统中的 #! 符号称之为 Shebang

在Unix系统中,在python脚本文件的第一行指定如下内容后,python脚本就可以像shell一样直接执行

1
#!/usr/bin/env python3

不使用#!/usr/bin/python3的原因是,为了提高可移植性,比如有些系统的python3没有安装在/usr/bin/目录,那么这种方式就会出错,而#!/usr/bin/env python3的方式,会在系统的PATH中搜索python3的安装路径,然后再调用对应路径下的python解释器执行。

编码

文件编码

默认情况下,python的代码文件采用的是UTF-8的编码方式。可以通过使用

1
# -*- coding: encoding -*-

的方式修改文件的编码格式。

控制流程

for循环

在迭代一个collection的过程中同时修改该集合的内容时,如果想要取得正确的结果,可能需要一些技巧。通常情况下,是迭代一个副本,或者创建一个新的集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> words = ['cat', 'windows', 'linux']
>>> for w in words:
... print(w)
... words.remove(w) # 期望删除所有的元素
...
cat
linux
>>> print(words) # 实际结果并不是期望的结果
['windows']
>>> words = ['cat', 'windows', 'linux']
>>> for w in words[:]: # 迭代时,迭代的时works的一个副本的内容
... words.remove(w)
...
>>> print(words)
[]

循环的else语句

循环语句可以有else子句。它会在循环耗尽了迭代对象(for循环)或循环条件为假(while循环)时被执行,但是不会在循环执行break语句终止时被执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
>>> for i in range(0):
... print(i)
... else:
... print("end")
...
end
>>>
>>> for i in range(3):
... print(i)
... else:
... print("end")
...
0
1
2
end
>>> while False:
... print('aaa')
... else:
... print("else statement")
...
else statement
>>>
>>> for i in range(5):
... print(i)
... if i == 2:
... break
... else:
... print("else statement")
...
0
1
2
>>>

try…except语句中的else子句

try … except 语句有一个可选的 else 子句,在使用时必须放在所有的 except 子句后面。

如果控制流离开 try 子句体时没有引发异常,并且没有执行 return或break/continue(try在for循环中时) 语句,可选的 else 子句将被执行。 else 语句中的异常不会由之前的 except 子句处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
>>> def func(a, b):
... ret = None
... try:
... ret = a / b
... print("ret in try: %s" % ret)
... except Exception as e:
... print("catch exception: %s" % str(e))
... else:
... print("ret in else: %s" % ret)
... finally:
... print("ret in finally: %s" % ret)
...
>>> func(10, 2) # 正常执行时,执行顺序 try -> else -> finally
ret in try: 5.0
ret in else: 5.0
ret in finally: 5.0
>>> func(10, 0) # try中出现异常时, 执行顺序 try -> except -> finally
catch exception: division by zero
ret in finally: None
>>> ### 如果 try 中有 return, 则 else子句不会执行
>>> def func(a, b):
... ret = None
... try:
... ret = a / b
... print("ret in try: %s" % ret)
... return ret
... except Exception as e:
... print("catch exception: %s" % str(e))
... else:
... print("ret in else: %s" % ret)
... finally:
... print("ret in finally: %s" % ret)
...
>>> func(10, 2) # try中没有异常抛出且有return语句时,执行顺序 try -> finally
ret in try: 5.0
ret in finally: 5.0
5.0
>>> for i in [1, 2, 0, 5]:
... print("i: %s" % i)
... try:
... ret = 10 / i
... if i == 2:
... break
... except Exception as e:
... print("catch exception")
... else:
... print("else statement")
... finally:
... print("finally statement")
...
i: 1
else statement
finally statement
i: 2
finally statement
>>>

try…except…finally

  • 即使try/except/else中有return语句,finally子句也总是会被执行,函数的返回值是由最后的return决定的。所以如果finally中有return子句,最终生效的是finally中的return。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    >>> def func(a, b):
    ... try:
    ... ret = a / b
    ... return ret
    ... except:
    ... return -1
    ... finally:
    ... print("finally")
    ...
    >>> func(10, 2)
    finally
    5.0
    >>> func(10, 0)
    finally
    -1
    >>>
    >>> # 如果finally中有return,一定会是finally中的return生效
    >>> def func(a, b):
    ... try:
    ... ret = a / b
    ... return ret
    ... except:
    ... return -1
    ... finally:
    ... return -2
    ...
    >>> func(10, 2)
    -2
    >>> func(10, 0)
    -2
    >>>

数据结构

数值运算

  1. 除运算时总是返回float类型的结果。表达式中整数与浮点数都存在时也是会返回float类型的结果

  2. floor division // 运算会返回整数结果,是直接丢弃小数部分,不会四舍五入

字符串显示

  1. 通常情况下,交互模式中显示字符串时会将字符串的内容用单引号'包裹起来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    >>> str1 = '"isn\'t," they said'
    >>> str1
    '"isn\'t," they said'
    >>> print(str1)
    "isn't," they said
    >>> str2="no, it is not"
    >>> str2
    'no, it is not'
    >>> print(str2)
    no, it is not
    >>> str3="first line\nsecond line"
    >>> str3
    'first line\nsecond line'
    # 使用print语句打印时,不会显示字符串回显时使用的包裹字符,同时会生效转义字符
    >>> print(str3)
    first line
    second line
    >>> str4="doesn\'t"
    # 当字符串中包含单引号同时没有包含双引号时,字符串的回显使用双引号包裹
    >>> str4
    "doesn't"
    >>> print(str4)
    doesn't
  2. 字符串中有反斜杠\时,会默认将后面的字符理解为转义字符,如果不想让字符转义时,可以使用\\或在字符串前添加r标记

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> print("c:\name1\name2")
    c:
    ame1
    ame2
    >>> print("c:\\name1\\name2")
    c:\name1\name2
    >>> print(r"c:\name1\name2")
    c:\name1\name2
    >>>

列表

  1. 列表中可以包含不同类型的元素,但是通常情况下都是同类型的。

  2. 列表的所有切片操作都会返回一个新的列表(shallow copy, 浅拷贝)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    >>> list1=[1,2,3,4,5]
    >>> id(list1)
    2012936495808
    >>> list2=list1[:]
    >>> id(list2)
    2012929059648
    >>> list3=list1[2:]
    >>> id(list3)
    2012936912256
    >>>
    >>> str1="abcdefg"
    >>> str2=str1[:]
    >>> id(str1)
    2012936632368
    >>> id(str2)
    2012936632368
    >>> id(str1)==id(str2)
    True
    >>> id(list1)==id(list2)
    False
    >>> str3=str1[2:]
    >>> id(str3)
    2012936535024
    >>>
  3. list.sort()会修改list的内容,返回值为None

    1
    2
    3
    4
    5
    6
    >>> print(tmp_list)
    [3, 1, 7, 6, 5]
    >>> tmp_list.sort()
    >>> print(tmp_list)
    [1, 3, 5, 6, 7]
    >>>

函数

函数中的默认值是在 定义过程 中在函数定义处计算的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> i = 5
>>> def func(arg=i):
print(arg)

>>> i = 6
>>> func()
5
>>> func(i)
6
>>> del i
>>> def func(arg=i):
print(arg)


Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
def func(arg=i):
NameError: name 'i' is not defined
>>>

函数中的默认值赋值只会执行一次

如果函数的默认是可变对象(列表/字典等)时,所有采用默认值的函数调用,共享该可变对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> def func(a, L=[]):
L.append(a)
return L

>>> func(1)
[1]
>>> func(2)
[1, 2]
>>> tmp_list = [1, 4, 5]
>>> func(3, tmp_list)
[1, 4, 5, 3]
>>> func(4)
[1, 2, 4]
>>>

函数中形参格式

如果 参数中既有 *args 类型,又有**keywords类型,那么*args必须在**keywords前面

*args 类型的参数,在函数内的类型时元组类型
**keywords 类型的参数,在函数内的类型时字典类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
>>> def func(kind, *args, **keywords):
print(kind)
print(type(args))
print(args)
print(type(keywords))
print(keywords)

>>> func(1, "a", "b", "c", name="abc", age="12")
1
<class 'tuple'>
('a', 'b', 'c')
<class 'dict'>
{'name': 'abc', 'age': '12'}
>>> func(1, *("a", "b", "c"), **{"name":"abc", "age":"12"})
1
<class 'tuple'>
('a', 'b', 'c')
<class 'dict'>
{'name': 'abc', 'age': '12'}
>>> args=["arg1", "arg2"]
>>> tmp_dict={"name1": "value1", "name2": "value2"}
>>> func(2, args, tmp_dict)
2
<class 'tuple'>
(['arg1', 'arg2'], {'name1': 'value1', 'name2': 'value2'})
<class 'dict'>
{}
>>> ### 函数调用时,如果之前有定义好的列表/元组或字典类型的变量,需要给*args 或 **keywords格式的形参传递时,可以使用 * 或 ** 对之前定义好的变量进行解包操作
>>> func(2, *args, **tmp_dict)
2
<class 'tuple'>
('arg1', 'arg2')
<class 'dict'>
{'name1': 'value1', 'name2': 'value2'}
>>>

如果存在 / 或 *, / 之前的所有参数都只能通过位置方式传参,* 之后的所有参数只能通过key=value方式传参,其他参数可以使用两种的任意一种方式传参

1
def func(pos1, pos2, /, p_or_kwd1, p_or_kwd2, *, kwd1, kwd2)

模块

模块初始化

模块中可以包含可执行的语句以及函数定义。这些语句用于初始化模块。它们仅在模块第一次被import时执行一次

每个模块在每个解释器会话中只被导入一次。如果更改了模块的内容,必须重启解释器或者使用 importlib.reload(module_name)

被导入的模块名存放在调入模块的全局符号表中,可以通过dir()查看

模块导入

模块的搜索方式: 当导入一个模块时,先查找是否为内置模块;如果没有找到,则在sys.path定义的列表中查找

sys.path中默认包含以下内容

  • 当前脚本所在路径
  • 系统环境变量PYTHONPATH
  • python安装路径相关目录