跳到主要内容

Python Basic

Python 速通,参考:https://docs.python.org/zh-cn/3/tutorial/index.html

基础

交互模式

交互模式下,上次输出的表达式会赋给变量 _。把 Python 当作计算器时,用该变量实现下一步计算更简单,例如:

>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06

字符串

字符串可以使用成对的单引号 ('...') 或双引号 ("...") 来标示,结果完全相同,特殊字符如 \n 在单引号('...' )和双引号("..." )里的意义一样。这两种引号唯一的区别是,不需要在单引号里转义双引号 " (但此时必须把单引号转义成 ' ),反之亦然。

如果不希望前置 \ 的字符转义成特殊字符,可以使用 原始字符串,在引号前添加 r 即可:

print(r'C:\some\name')

原始字符串还有一个微妙的限制:一个原始字符串不能以奇数个 \ 字符结束;请参阅 此 FAQ 条目 了解更多信息及绕过的办法。

字符串字面值可以包含多行。 一种实现方式是使用三重引号:"""...""" 或 '''...'''。 字符串中将自动包括行结束符,但也可以在换行的地方添加一个 \ 来避免此情况。 参见以下示例:

print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")

输出如下(请注意开始的换行符没有被包括在内):

Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to

字符串可以用 + 合并(粘到一起),也可以用 * 重复:

>>> 3 * 'un' + 'ium'
'unununium'

相邻的两个或多个 字符串字面值 (引号标注的字符)会自动合并:

>>> 'Py' 'thon'
'Python'

这项功能只能用于两个字面值,不能用于变量或表达式。

字符串支持 索引 (下标访问),第一个字符的索引是 0。单字符没有专用的类型,就是长度为一的字符串;索引还支持负数,用负数索引时,从右边开始计数:

>>> word[-1]  # last character
'n'
>>> word[-2] # second-last character
'o'
>>> word[-6]
'P'

注意,-0 和 0 一样,因此,负数索引从 -1 开始。

还可以这样理解切片,索引指向的是字符 之间 ,第一个字符的左侧标为 0,最后一个字符的右侧标为 n ,n 是字符串长度。例如:

 +---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1

索引越界会报错,但是,切片会自动处理越界索引。

Python 字符串不能修改,是 immutable 的。因此,为字符串中某个索引位置赋值会报错:

>>> word[0] = 'J'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> word[2:] = 'py'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

控制流

if

if x < 0:
x = 0
print('Negative changed to zero')
elif x == 0:
print('Zero')
elif x == 1:
print('Single')
else:
print('More')

for

# Measure some strings:
words = ['cat', 'window', 'defenestrate']
for w in words:
print(w, len(w))

很难正确地在迭代 collection 的同时修改 collection 的内容。更简单的方法是迭代collection的副本或者创建新的collection

# Create a sample collection
users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}

# Strategy: Iterate over a copy
for user, status in users.copy().items():
if status == 'inactive':
del users[user]

# Strategy: Create a new collection
active_users = {}
for user, status in users.items():
if status == 'active':
active_users[user] = status

range()

>>> list(range(5, 10))
[5, 6, 7, 8, 9]

>>> list(range(0, 10, 3))
[0, 3, 6, 9]

>>> list(range(-10, -100, -30))
[-10, -40, -70]

有些时候使用 enumerate() 更方便:

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

break

break 语句将跳出最近的一层 for 或 while 循环。

for 或 while 循环可以包括 else 子句。

在 for 循环中,else 子句会在循环成功结束最后一次迭代之后执行。

在 while 循环中,它会在循环条件变为假值后执行。

无论哪种循环,如果因为 break 而结束,那么 else 子句就 不会 执行。

下面的搜索质数的 for 循环就是一个例子:

for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'equals', x, '*', n//x)
break
else:
# loop fell through without finding a factor
print(n, 'is a prime number')

# 2 is a prime number
# 3 is a prime number
# 4 equals 2 * 2
# 5 is a prime number
# 6 equals 2 * 3
# 7 is a prime number
# 8 equals 2 * 4
# 9 equals 3 * 3

else 子句用于循环时比起 if 语句的 else 子句,更像 try 语句的。try 语句的 else 子句在未发生异常时执行,循环的 else 子句则在未发生 break 时执行。

pass

pass 语句不执行任何动作。语法上需要一个语句,但程序毋需执行任何动作时,可以使用该语句。例如:

while True:
pass # Busy-wait for keyboard interrupt (Ctrl+C)

class MyEmptyClass:
pass

def initlog(*args):
pass # Remember to implement this!

match

match 像 Rust 或 Haskell 中的模式匹配。只有第一个匹配的模式会被执行,并且它还可以提取值的组成部分(序列的元素或对象的属性)赋给变量。

def http_error(status):
match status:
case 400:
return "Bad request"
case 401 | 403:
return "Not allowed"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"

可被用于绑定变量:

# point is an (x, y) tuple
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")

同时也可以给模式添加 if 字句:

# point is an (x, y) tuple
point = (1,2)

match point:
case (x, y) if x==y:
print(f"point={x,x}")
case (x,y) :
print(f"point={x,y}")
case _:
raise ValueError("Not a point")

使用 as 关键字可以捕获子模式:

case (Point(x1, y1), Point(x2, y2) as p2): ...

更详细的说明和更多示例,可参阅以教程格式撰写的 PEP 636

函数

函数的样例:

def fib(n):    # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()

# Now call the function we just defined:
fib(2000)

函数内的第一条语句是字符串时,该字符串就是文档字符串,也称为 docstring。

第一行应为对象用途的简短摘要。为保持简洁,不要在这里显式说明对象名或类型,因为可通过其他方式获取这些信息(除非该名称碰巧是描述函数操作的动词)。这一行应以大写字母开头,以句点结尾。

文档字符串为多行时,第二行应为空白行,在视觉上将摘要与其余描述分开。后面的行可包含若干段落,描述对象的调用约定、副作用等。

def my_function():
"""Do nothing, but document it.

No, really, it doesn't do anything.
"""
pass

print(my_function.__doc__)

# Output:
"""
Do nothing, but document it.

No, really, it doesn't do anything.
"""

默认参数

python 的默认参数写法和 cpp 类似

def ask_ok(prompt, retries=4, reminder='Please try again!'):

默认值在 定义 作用域里的函数定义中求值,所以:

i = 5

def f(arg=i):
print(arg)

i = 6
f()

上例输出的是 5

注意

重要警告: 默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。例如,下面的函数会累积后续调用时传递的参数:

def f(a, L=[]):
L.append(a)
return L

print(f(1))
print(f(2))
print(f(3))

输出结果如下:

[1]
[1, 2]
[1, 2, 3]

不想在后续调用之间共享默认值时,应以如下方式编写函数:

def f(a, L=None):
if L is None:
L = []
L.append(a)
return L