本文最后更新于 <span id="expire-date"></span> 天前,文中部分描述可能已经过时。

虽然之前学过不少 python 的知识,但是还是没有系统的学习过一些基础知识,补一下。
参考书 Python 基础教程(第 3 版)_百度百科

只记一下易错点和之前不会的点吧,个人向。

快速上手:基础知识

数和表达式

1
2
3
4
5
6
7
# 取余
10 % 3
# 整除
10 // 3
# 幂运算
2 ** 3

1
2
3
4
5
6
7
8
>>> 10 // 3
3
>>> 10 // -3
-4
>>> -10 // 3
-4
>>> -10 // -3
3

对于整除运算,需要明白的一个重点是它向下圆整结果。因此在结果为负数的情况下,圆整后将离 0 更远。这意味着对于-10 // 3, 将向下圆整到-4,而不是向上圆整到-3。

1
2
3
4
5
6
7
>>> 2 ** 3     # pow(2, 3)
8
>>> -3 ** 2
-9
>>> (-3) ** 2
9

请注意,乘方运算符的优先级比求负(单目减)高,因此-3**2等价于-(3**2)。如果你要计
算的是(-3)**2,必须明确指出。

十六进制、八进制和二进制

1
2
3
0x10 # 十六进制
0o10 # 八进制
0b10 # 二进制

这些表示法都以 0 打头。

获取用户输入

1
2
3
>>> input("The meaning of life: ")
The meaning of life: 42
'42'

这里在交互式解释器中执行了第一行(input(…)),它打印字符串”The meaning of life:”,
提示用户输入相应的信息。我输入 42 并按回车。这个数被 input(以文本或字符串的方式)返回, 并在最后一行被自动打印出来。

cmath 和复数

1
2
3
>>> (1 + 3j) * (9 + 4j)
(-3 + 31j)

保存并执行程序

在有些情况下,你希望能够像执行其他程序(如 Web 浏览器或文本编辑器)一样执行 Python 脚本,而无需显式地使用 Python 解释器。

UNIX 提供了实现这种目标的标准方式:让脚本的第一 行以字符序列#!(称为 pound bang 或 shebang)开始,并在它后面指定用于对脚本进行解释的程序 (这里是 Python)的绝对路径。

即便你对这一点不太明白,只需将下面的代码作为脚本的第一行, 就可在 UNIX 中轻松运行脚本:
#!/usr/bin/env python
不管 Python 库位于什么地方,这都将让你能够像运行普通程序一样运行脚本。
如果你安装了多个版本的 Python,可用更具体的可执行文件名(如 python3)替换 python。
要像普通程序一样运行脚本,还必须将其变成可执行的:
$ chmod a+x hello.py
现在,可以像下面这样来运行它(假定当前目录包含在执行路径中):
$ hello.py
如果这不管用,请尝试使用./hello.py,这在当前目录(.)未包含在执行路径中时也管用(负责的系统管理员会告诉你执行路径是什么)。

如果你愿意,可对文件进行重命名并删除扩展名.py,使其看起来更像普通程序。

如果双击会如何呢 在 Windows 中,扩展名.py是让脚本像普通程序一样的关键所在。请尝试双击前一节保存的文件hello.py。如果正确地安装了Python,这将打开一个 DOS 窗口,其中包含提示信息 What is your name?。然而,这样运行程序存在一个问题:输入名字后,程序窗口将立即关闭,你根本来不及 看清结果。这是因为程序结束后窗口将立即关闭。尝试修改脚本,在末尾添加如下代码行: input("Press <enter>") 现在运行这个程序并输入名字后,DOS 窗口将包含如下内容:

What is your name? Gumby Hello, Gumby! Press <enter>

等你按回车键后,窗口将立即关闭,因为程序结束了。

字符串

1
2
>>> "Hello, world!"
'Hello, world!'

在这个示例中,有一点可能让你颇感意外:Python 在打印字符串时,用单引号将其括起,而 我们使用的是双引号。这有什么差别吗?其实没有任何差别。

1
2
3
4
>>> "Let's go!"
"Let's go!"
>>> '"Hello, world!" she said'
'"Hello, world!" she said'

第二个字符串包含双引号,因此必须使用单引号将整个字符串括起,原因和前面一样。实际上,并非必须这样做(这样做只是出于方便考虑)。可使用反斜杠(\)对引号进行转义,如 下所示

1
2
>>> 'Let\'s go!'
"Let's go!"

Python 打印所有的字符串时,都用引号将其括起。你可能通过前面的示例发现了这一点。

因为 Python 打印值时,保留其在代码中的样子,而不是你希望用户看到的样子。但如果你使用 print,结果将不同。

1
2
3
4
5
6
7

>>> "Hello,\nworld!"
'Hello,\nworld!'
>>> print("Hello,\nworld!")
Hello,
world!

通过两种不同的机制将值转换成了字符串。你可通过使用函数 str 和 repr① 直接使用这两种机制。使用 str 能以合理的方式将值转换为用户能够看懂的字符串。例如,尽可能将特殊字符编码 转换为相应的字符。然而,使用 repr 时,通常会获得值的合法 Python 表达式表示

1
2
3
4
>>> print(repr("Hello,\nworld!"))
'Hello,\nworld!'
>>> print(str("Hello,\nworld!"))
Hello, world!
  1. 长字符串

要表示很长的字符串(跨越多行的字符串),可使用三引号(而不是普通引号)。
print(‘’’This is a very long string. It continues here.
And it’s not over yet.
“Hello, world!” Still here.’’’)

还可使用三个双引号,如”””like this”””。

请注意,这让解释器能够识别表示字符串开始 和结束位置的引号,因此字符串本身可包含单引号和双引号,无需使用反斜杠进行转义

三个引号也是注释的一种写法。

  1. 原始字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> path = 'C:\nowhere'
>>> path
'C:\nowhere'

# 这好像没问题,但如果将其打印出来,就会出现问题。
>>> print(path)
C:
owhere

# 原始字符串用前缀r表示
>>> print(r'C:\nowhere')
C:\nowhere

#另外,原始字符串不能以单个反斜杠结尾。换而言之,原始字符串的最后一个字符不能是反斜杠,除非你对其进行转义(但进行转义时,用于转义的反斜杠也将是字符串的一部分)。
>>> print(r'C:\Program Files\foo\bar' '\\')
C:\Program Files\foo\bar\
  1. Unicode、bytes 和 bytearray

每个 Unicode 字符都用一个码点(code point)表示,而码点是 Unicode 标准给每个字符指定的数字。

“\u00C6”
‘Æ’
“\U0001F60A”
‘☺ ‘
“This is a cat: \N{Cat}”
‘This is a cat: ‘

小结

本章介绍的内容很多,先来看看你都学到了什么,再接着往下讲。

  • 算法:算法犹如菜谱,告诉你如何完成特定的任务。从本质上说,编写计算机程序就是 使用计算机能够理解的语言(如 Python)描述一种算法。这种对机器友好的描述被称为程序,主要由表达式和语句组成。
  • 表达式:表达式为程序的一部分,结果为一个值。例如,2 + 2 就是一个表达式,结果为 4。简单表达式是使用运算符(如+或%)和函数(如 pow)将字面值(如 2 或”Hello”)组 合起来得到的。通过组合简单的表达式,可创建复杂的表达式,如(2 + 2) *(3 - 1)。表 达式还可能包含变量。
  • 变量:变量是表示值的名称。通过赋值,可将新值赋给变量,如 x = 2。赋值是一种语句。
    • 语句:语句是让计算机执行特定操作的指示。这种操作可能是修改变量(通过赋值)、将 信息打印到屏幕上(如 print(“Hello, world!”))、导入模块或执行众多其他任务。
  • 函数:Python 函数类似于数学函数,它们可能接受参数,并返回结果(在第 6 章学习编写 自定义函数时,你将发现函数实际上可以在返回前做很多事情)。
  • 模块:模块是扩展,可通过导入它们来扩展 Python 的功能。例如,模块 math 包含多个很有 用的函数。
  • 程序:你通过练习学习了如何编写、保存和运行 Python 程序。 - 字符串:字符串非常简单。它们其实就是一段文本,其中的字符是用 Unicode 码点表示的。 然而,对于字符串,需要学习的知识有很多。本章介绍了很多表示字符串的方式,第 3 章 将介绍众多字符串用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

abs(number) # 返回指定数的绝对值
bytes(string, encoding[, errors]) # 对指定的字符串进行编码,并以指定的方式处理错误
cmath.sqrt(number) # 返回平方根;可用于负数
float(object) # 将字符串或数字转换为浮点数
help([object]) # 提供交互式帮助
input(prompt) # 以字符串的方式获取用户输入
int(object) # 将字符串或数转换为整数
math.ceil(number) # 以浮点数的方式返回向上圆整的结果
math.floor(number) # 以浮点数的方式返回向下圆整的结果
math.sqrt(number) # 返回平方根;不能用于负数
pow(x, y[, z]) # 返回x的y次方对z求模的结果
print(object, ...) # 将提供的实参打印出来,并用空格分隔
repr(object) # 返回一个对象的字符串表示形式
round(number[, ndigits]) # 四舍五入为指定的精度,正好为5时舍入到偶数
str(object) # 将指定的值转换为字符串。用于转换bytes时,可指定编码和错误处理方式

列表和元组

索引 tag[0]

切片 tag[32:-4]

更大的步长

1
2
3
4
5
6
7
8
9
10
11
12
13
14
在这个示例中,指定了另一个数。你可能猜到了,这显式地指定了步长。如果指定的步长大于1,将跳过一些元素。例如,步长为2时,将从起点和终点之间每隔一个元素

>>> numbers[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

提取一个元素显式地指定步长时,也可使用前述简写。例如,要从序列中每隔3个元素提取1个,只需提供步长4即可

>>> numbers[0:10:2]
[1, 3, 5, 7, 9]
numbers[3:6:3]
[4]

当然,步长不能为0,否则无法向前移动,但可以为负数,即从右向左提取元素。

乘法

将序列与数 x 相乘时,将重复这个序列 x 次来创建一个新序列:

1
2
3
4
>>> 'python' * 5
'pythonpythonpythonpythonpython'
>>> [42] * 10
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]

None、空列表和初始化

空列表是使用不包含任何内容的两个方括号表示的。如果要创建一个可包含 10 个元素的列表,但没有任何有用的内容,可像前面那样使用[42]*10。但更准确的做法是使用[0]*10,这将创建一个包含 10 个零的列表。然而,在有些情况下,你可能想使用表示“什么都没有”的值,如表示还没有在列表中添加任何内容。在这种情况下,可使用 None。在 Python 中, None 表示什么都没有。因此,要将列表的长度初始化为 10,可像下面这样做:

1
2
3
>>> sequence = [None] * 10
>>> sequence
[None, None, None, None, None, None, None, None, None, None]

列表: Python 的主力

1
2
3
4

>>> list('Hello')
['H', 'e', 'l', 'l', 'o']

要将字符列表(如前述代码中的字符列表)转换为字符串,可使用下面的表达式:
''.join(somelist)

  1. 给切片赋值
    切片是一项极其强大的功能,而能够给切片赋值让这项功能显得更加强大。
1
2
3
4
5
6
>>> name = list('Perl')
>>> name
['P', 'e', 'r', 'l']
>>> name[2:] = list('ar')
>>> name
['P', 'e', 'a', 'r']

从上述代码可知,可同时给多个元素赋值。你可能认为,这有什么大不了的,分别给每个元
素赋值不是一样的吗?确实如此,但通过使用切片赋值,可将切片替换为长度与其不同的序列。

1
2
3
4
>>> name = list('Perl')
>>> name[1:] = list('ython')
>>> name
['P', 'y', 't', 'h', 'o', 'n']

使用切片赋值还可在不替换原有元素的情况下插入新元素。

1
2
3
4
>>> numbers = [1, 5]
>>> numbers[1:1] = [2, 3, 4]
>>> numbers
[1, 2, 3, 4, 5]

在这里,我“替换”了一个空切片,相当于插入了一个序列。你可采取相反的措施来删除切片。

1
2
3
4
5
>>> numbers
[1, 2, 3, 4, 5]
>>> numbers[1:4] = []
>>> numbers
[1, 5]

你可能猜到了,上述代码与 del numbers[1:4]等效。现在,你可自己尝试执行步长不为 1(乃至为负)的切片赋值了。

列表方法

1
2
3
4
5
6
7
8
9
10
11
12
append()
clear()
copy()
count()
extend()
index()
insert()
pop() #从列尾删除一个元素,并返回该元素的值
remove() #删除第一个值
reverse() #反转列表中的元素
sort() #排序列表中的元素 就地排序意味着对原来的列表进行修改,而不是创建一个新的列表。

copy()

方法 copy 复制列表。前面说过,常规复制只是将另一个名称关联到列表。

1
2
3
4
5
>>> a = [1, 2, 3]
>>> b = a
>>> b[1] = 4
>>> a
[1, 4, 3]

要让 a 和 b 指向不同的列表,就必须将 b 关联到 a 的副本

1
2
3
4
5
6
7
>>> a = [1, 2, 3]
>>> b = a.copy()
>>> b[1] = 4
>>> a
[1, 2, 3]
>>> b
[1, 4, 3]

Extend()

方法 extend 让你能够同时将多个值附加到列表末尾,为此可将这些值组成的序列作为参数提
供给方法 extend。换而言之,你可使用一个列表来扩展另一个列表。

1
2
3
4
5
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]

这可能看起来类似于拼接,但存在一个重要差别,那就是将修改被扩展的序列(这里是 a)。
在常规拼接中,情况是返回一个全新的序列。

1
2
3
4
5
6
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a + b
[1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3]

sort() 高级排序

方法 sort 接受两个可选参数: key 和 reverse。

方法 sort 接受两个可选参数: key 和 reverse。这两个参数通常是按名称指定的,称为关键字
参数,将在第 6 章详细讨论。参数 key 类似于参数 cmp:你将其设置为一个用于排序的函数。然而,
不会直接使用这个函数来判断一个元素是否比另一个元素小,而是使用它来为每个元素创建一个
键,再根据这些键对元素进行排序。因此,要根据长度对元素进行排序,可将参数 key 设置为函数 len。

1
2
3
4
>>> x = ['aardvark', 'abalone', 'acme', 'add', 'aerate']
>>> x.sort(key=len)
>>> x
['add', 'acme', 'aerate', 'abalone', 'aardvark']

对于另一个关键字参数 reverse,只需将其指定为一个真值( True 或 False,将在第 5 章详细介绍),以指出是否要按相反的顺序对列表进行排序。

元组:不可修改的序列 (元组)

1
2
3
4
5
6
>>> tuple([1, 2, 3])
(1, 2, 3)
>>> tuple('abc')
('a', 'b', 'c')
>>> tuple((1, 2, 3))
(1, 2, 3)

小结

下面来回顾一下本章介绍的一些最重要的概念。

  • 序列:序列是一种数据结构,其中的元素带编号(编号从 0 开始)。列表、字符串和元组
    都属于序列,其中列表是可变的(你可修改其内容),而元组和字符串是不可变的(一旦
    创建,内容就是固定的)。要访问序列的一部分,可使用切片操作:提供两个指定切片起
    始和结束位置的索引。要修改列表,可给其元素赋值,也可使用赋值语句给切片赋值。

  • 成员资格:要确定特定的值是否包含在序列(或其他容器)中,可使用运算符 in。将运
    算符 in 用于字符串时情况比较特殊——这样可查找子串。

  • 方法:一些内置类型(如列表和字符串,但不包括元组)提供了很多有用的方法。方法
    有点像函数,只是与特定的值相关联。方法是面向对象编程的一个重要方面,这将在第 7
    章介绍。

字符串

设置字符串的格式 精简版

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
# from c
>>> format = "Hello, s. s enough for ya?" % %
>>> values = ('world', 'Hot')
>>> format values %
'Hello, world. Hot enough for ya?'

# from shell

>>> from string import Template
>>> tmpl = Template("Hello, $who! $what enough for ya?")
>>> tmpl.substitute(who="Mars", what="Dusty")
'Hello, Mars! Dusty enough for ya?'

# new and improved
>>> "{}, {} and {}".format("first", "second", "third")
'first, second and third'
>>> "{0}, {1} and {2}".format("first", "second", "third")
'first, second and third'

>>> "{3} {0} {2} {1} {3} {0}".format("be", "not", "or", "to")
'to be or not to be'

>>> from math import pi
>>> "{name} is approximately {value:.2f}.".format(value=pi, name="π ")
'π is approximately 3.14.'

# 最后,在Python 3.6中,如果变量与替换字段同名,还可使用一种简写。在这种情况下,可使用f字符串——在字符串前面加上f。

>>> from math import e
>>> f"Euler's constant is roughly {e}."
"Euler's constant is roughly 2.718281828459045."

>>> "Euler's constant is roughly {e}.".format(e=e)
"Euler's constant is roughly 2.718281828459045."


设置字符串的格式 完整版

1
2
3

>>> "{{ceci n'est pas une replacement field}}".format()
"{ceci n'est pas une replacement field}"

在格式字符串中,最激动人心的部分为替换字段。替换字段由如下部分组成,其中每个部分
都是可选的。

  • 字段名:索引或标识符,指出要设置哪个值的格式并使用结果来替换该字段。除指定值
    外,还可指定值的特定部分,如列表的元素。
  • 转换标志:跟在叹号后面的单个字符。当前支持的字符包括 r(表示 repr)、 s(表示 str)
    和 a(表示 ascii)。如果你指定了转换标志,将不使用对象本身的格式设置机制,而是使
    用指定的函数将对象转换为字符串,再做进一步的格式设置。
  • 格式说明符:跟在冒号后面的表达式(这种表达式是使用微型格式指定语言表示的)。格
    式说明符让我们能够详细地指定最终的格式,包括格式类型(如字符串、浮点数或十六
    进制数),字段宽度和数的精度,如何显示符号和千位分隔符,以及各种对齐和填充方式。
    下面详细介绍其中的一些要素。

替换字段名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> "{foo} {} {bar} {}".format(1, 2, bar=4, foo=3)
'3 1 4 2'

>>> "{foo} {1} {bar} {0}".format(1, 2, bar=4, foo=3)
'3 2 4 1'

>>> fullname = ["Alfred", "Smoketoomuch"]
>>> "Mr {name[1]}".format(name=fullname)
'Mr Smoketoomuch'
>>> import math
>>> tmpl = "The {mod.__name__} module defines the value {mod.pi} for π "
>>> tmpl.format(mod=math)
'The math module defines the value 3.141592653589793 for π '

基本转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> print("{pi!s} {pi!r} {pi!a}".format(pi="π "))
π 'π ' '\u03c0'

# 上述三个标志( s、 r和a)指定分别使用str、 repr和ascii进行转换。
# 你还可指定要转换的值是哪种类型,更准确地说,是要将其视为哪种类型。例如,你可能提供一个整数,但将其作为小数进行处理。为此可在格式说明(即冒号后面)使用字符f(表示定点数)。

>>> "The number is {num}".format(num=42)
'The number is 42'
>>> "The number is {num:f}".format(num=42)
'The number is 42.000000'

>>> "The number is {num:b}".format(num=42)
'The number is 101010'

表 3-1 字符串格式设置中的类型说明符

类型含义
b将整数表示为二进制数
c将整数解读为 Unicode 码点
d将整数视为十进制数进行处理,这是整数默认使用的说明符
e使用科学表示法来表示小数(用 e 来表示指数)
E与 e 相同,但使用 E 来表示指数
f将小数表示为定点数
F与 f 相同,但对于特殊值( nan 和 inf),使用大写表示
g自动在定点表示法和科学表示法之间做出选择。这是默认用于小数的说明符,但在默认情况下至少有 1 位小数
G与 g 相同,但使用大写来表示指数和特殊值
n与 g 相同,但插入随区域而异的数字分隔符
o将整数表示为八进制数
s保持字符串的格式不变,这是默认用于字符串的说明符
x将整数表示为十六进制数并使用小写字母
X与 x 相同,但使用大写字母
%将数表示为百分比值(乘以 100,按说明符 f 设置格式,再在后面加上%)
宽度、精度和千位分隔符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#宽度是使用整数指定的,如下所示:
>>> "{num:10}".format(num=3)
' 3'
>>> "{name:10}".format(name="Bob")
'Bob '

#精度是使用小数指定的,如下所示:
>>> "Pi day is {pi:.2f}".format(pi=pi)
'Pi day is 3.14'

>>> "{pi:10.2f}".format(pi=pi)
' 3.14'

# 字符串
>>> "{:.5}".format("Guido van Rossum")
'Guido'


# 千位分隔符  可使用逗号来指出你要添加千位分隔符
>>> 'One googol is {:,}'.format(10**100)
'One googol is 10,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000'

# 同时指定其他格式设置元素时,这个逗号应放在宽度和表示精度的句点之间①。
符号、对齐和用 0 填充

在一栏中同时包含字符串和数时,你可能想修改默认对齐方式。在指定宽
度和精度的数前面,可添加一个标志。
这个标志可以是零、加号、减号或空格,其中零表示使用 0 来填充数字。

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

>>> '{:010.2f}'.format(pi)
'0000003.14'
要指定左对齐、右对齐和居中,可分别使用<、 >和^。
>>> print('{0:<10.2f}\n{0:^10.2f}\n{0:>10.2f}'.format(pi))
3.14
3.14
3.14

#可以使用填充字符来扩充对齐说明符,这样将使用指定的字符而不是默认的空格来填充。
>>> "{:$^15}".format(" WIN BIG ")
'$$$ WIN BIG $$$'

# 还有更具体的说明符=,它指定将填充字符放在符号和数字之间。

>>> print('{0:10.2f}\n{1:10.2f}'.format(pi, -pi))
3.14
-3.14
>>> print('{0:10.2f}\n{1:=10.2f}'.format(pi, -pi))
3.14
- 3.14

# 如果要给正数加上符号,可使用说明符+(将其放在对齐说明符后面),而不是默认的-。如果将符号说明符指定为空格,会在正数前面加上空格而不是+。

>>> print('{0:-.2}\n{1:-.2}'.format(pi, -pi)) #默认设置
3.1
-3.1
>>> print('{0:+.2}\n{1:+.2}'.format(pi, -pi))
+3.1
-3.1
>>> print('{0: .2}\n{1: .2}'.format(pi, -pi))
3.1
-3.1

# 需要介绍的最后一个要素是井号( #)选项,你可将其放在符号说明符和宽度之间(如果指定了这两种设置)。这个选项将触发另一种转换方式,转换细节随类型而异。例如,对于二进制、八进制和十六进制转换,将加上一个前缀。

>>> "{:b}".format(42)
'101010'
>>> "{:#b}".format(42)
'0b101010'

>>> "{:g}".format(42)
'42'
>>> "{:#g}".format(42)
'42.0000'

# 根据指定的宽度打印格式良好的价格列表
width = int(input('Please enter width: '))
price_width = 10
item_width = width - price_width
header_fmt = '{{:{}}}{{:>{}}}'.format(item_width, price_width)
fmt = '{{:{}}}{{:>{}.2f}}'.format(item_width, price_width)
print('=' * width)
print(header_fmt.format('Item', 'Price'))
print('-' * width)
print(fmt.format('Apples', 0.4))
print(fmt.format('Pears', 0.5))
print(fmt.format('Cantaloupes', 1.92))
print(fmt.format('Dried Apricots (16 oz.)', 8))
print(fmt.format('Prunes (4 lbs.)', 12))
print('=' * width)


# result
# 这个程序的运行情况类似于下面这样:
Please enter width: 35
===================================
Item Price
-----------------------------------
Apples 0.40
Pears 0.50
Cantaloupes 1.92
Dried Apricots (16 oz.) 8.00
Prunes (4 lbs.) 12.00
===================================

套娃哇!!666

字符串方法

字符串的方法太多了,这里只介绍一些最有用的。完整的字符串方法清单请参阅附录 B。这
里描述字符串的方法时,将列出其他相关的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 字符串的方法
str.center(width[, fillchar]) # 方法center通过在两边添加填充字符(默认为空格)让字符串居中。
str.find(sub[, start[, end]]) # 方法find返回子字符串sub在字符串中第一次出现的索引,如果没有找到,则返回-1。
str.join(seq) # 方法join将序列seq中的元素用字符串str连接起来,返回连接后的字符串。 所合并序列的元素必须都是字符串
str.lower() # 方法lower将字符串转换为小写。
str.upper() # 方法upper将字符串转换为大写。
str.split(sep[, maxsplit]) # 方法split将字符串按照分隔符sep分割,返回分割后的字符串列表。
str.strip([chars]) # 方法strip删除字符串左右两边的空格。
str.replace(old, new[, max]) # 方法replace将字符串中的old子字符串替换为new子字符串,返回替换后的字符串。
str.splitlines([keepends]) # 方法splitlines将字符串按照行分割,返回分割后的字符串列表。
str.translate(table[, deletechars]) # 方法translate将字符串中的字符用表table中的对应字符替换,返回替换后的字符串。 方法translate与replace一样替换字符串的特定部分,但不同的是它只能进行单字符替换。这个方法的优势在于能够同时替换多个字符,因此效率比replace高。
str.isdigit() # 方法isdigit判断字符串是否只包含数字字符。
str.isalpha() # 方法isalpha判断字符串是否只包含字母字符。
str.isalnum() # 方法isalnum判断字符串是否只包含字母和数字字符。
str.islower() # 方法islower判断字符串是否只包含小写字母。
str.isupper() # 方法isupper判断字符串是否只包含大写字母。 isalnum、 isalpha、 isdecimal、 isdigit、 isidentifier、 islower、 isnumeric、isprintable、 isspace、 istitle、 isupper。


trnaslate

1
2
3
4
5
6
7
>>> table = str.maketrans('cs', 'kz')
如果愿意,可查看转换表的内容,但你看到的只是Unicode码点之间的映射。
>>> table
{115: 122, 99: 107}
创建转换表后,就可将其用作方法translate的参数。
>>> 'this is an incredible test'.translate(table)
'thiz iz an inkredible tezt'

小结

本章介绍了字符串的两个重要方面。

  • 字符串格式设置:求模运算符( %)可用于将值合并为包含转换标志(如%s)的字符串,
    这让你能够以众多方式设置值的格式,如左对齐或右对齐,指定字段宽度和精度,添加
    符号(正号或负号)以及在左边填充 0 等。
  • 字符串方法:字符串有很多方法, 有些很有用(如 split 和 join),有些很少用到(如 istitle
    和 capitalize)。

字典 当索引行不通时

phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}

他的定义有点像结构体

1
2
3
4
5
6
7
8
9
10
>>> items = [('name', 'Gumby'), ('age', 42)]
>>> d = dict(items)
>>> d
{'age': 42, 'name': 'Gumby'}
>>> d['name']
'Gumby'
# 还可使用关键字实参来调用这个函数,如下所示:
>>> d = dict(name='Gumby', age=42)
>>> d
{'age': 42, 'name': 'Gumby'}

特性

  • 键的类型:字典中的键可以是整数,但并非必须是整数。字典中的键可以是任何不可变
    的类型,如浮点数(实数)、字符串或元组。
  • 自动添加:即便是字典中原本没有的键,也可以给它赋值,这将在字典中创建一个新项。
    然而,如果不使用 append 或其他类似的方法,就不能给列表中没有的元素赋值。
  • 成员资格:表达式 k in d(其中 d 是一个字典)查找的是键而不是值,而表达式 v in l(其
    中 l 是一个列表)查找的是值而不是索引。这看似不太一致,但你习惯后就会觉得相当自
    然。毕竟如果字典包含指定的键,检查相应的值就很容易。

将字符串格式设置功能用于字典

1
2
3
4
>>> phonebook
{'Beth': '9102', 'Alice': '2341', 'Cecil': '3258'}
>>> "Cecil's phone number is {Cecil}.".format_map(phonebook)
"Cecil's phone number is 3258."

字典方法

clear:清空字典中的所有项。
copy:返回一个字典的浅复制,而不是深复制。deepcopy:返回一个字典的深复制。
fromkeys:从指定的键值对创建一个新的字典。
get:返回指定键的值,如果值不在字典中返回默认值。方法 get 为访问字典项提供了宽松的环境。通常,如果你试图访问字典中没有的项,将引发错误。使用 get 来访问不存在的键时,没有引发异常,而是返回 None。你可指定“默认”值,这样将返回你指定的值而不是 None。

items:返回一个包含字典中的所有项的列表。

1
2
3
>>> d = {'title': 'Python Web Site', 'url': 'http://www.python.org', 'spam': 0}
>>> d.items()
dict_items([('url', 'http://www.python.org'), ('spam', 0), ('title', 'Python Web Site')])

返回值属于一种名为字典视图的特殊类型。字典视图可用于迭代(迭代将在第 5 章详细介绍)。
另外,你还可确定其长度以及对其执行成员资格检查。

视图的一个优点是不复制,它们始终是底层字典的反映,即便你修改了底层字典亦如此。

keys:返回一个包含字典中的所有键的列表。视图
pop:删除并返回字典中的一个项。d.pop('x')
popitem:随机删除并返回字典中的一个项。
setdefault:如果键不存在于字典中,则为它设置默认值。
update:将另一个字典的项添加到字典中。
values:返回一个包含字典中的所有值的列表。视图

小结

本章介绍了如下内容。

  • 映射:映射让你能够使用任何不可变的对象(最常用的是字符串和元组)来标识其元素。
    Python 只有一种内置的映射类型,那就是字典。
  • 将字符串格式设置功能用于字典:要对字典执行字符串格式设置操作,不能使用 format
    和命名参数,而必须使用 format_map。
  • 字典方法:字典有很多方法,这些方法的调用方式与列表和字符串的方法相同。

条件、循环及其他语句

赋值魔法

  1. 序列解包
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
>>> x, y, z = 1, 2, 3
>>> print(x, y, z)
1 2 3

>>> x, y = y, x
>>> print(x, y)
2 1

>>> values = 1, 2, 3
>>> values
(1, 2, 3)
>>> x, y, z = values
>>> x
1


# 可使用星号运算符( *)来收集多余的值,这样无需确保值和变量的个数相同,如下例所示:

>>> a, b, *rest = [1, 2, 3, 4]
>>> rest
[3, 4]

# 还可将带星号的变量放在其他位置。
>>> name = "Albus Percival Wulfric Brian Dumbledore"
>>> first, *middle, last = name.split()
>>> middle
['Percival', 'Wulfric', 'Brian']


赋值语句的右边可以是任何类型的序列,但带星号的变量最终包含的总是一个列表。在变量和值的个数相同时亦如此。
>>> a, *b, c = "abc"
>>> a, b, c
('a', ['b'], 'c')

  1. 链式赋值
1
2
3
4
5
6
7
8
9
10
11

# 链式赋值是一种快捷方式,用于将多个变量关联到同一个值。这有点像前一节介绍的并行赋值,但只涉及一个值:
x = y = somefunction()
# 上述代码与下面的代码等价:
y = somefunction()
x = y
# 请注意,这两条语句可能与下面的语句不等价:
x = somefunction()
y = somefunction()
# 有关这方面的详细信息,请参阅5.4.6节介绍相同运算符( is)的部分。

  1. 关键字 assert
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

>>> age = 10
>>> assert 0 < age < 100
>>> age = -1
>>> assert 0 < age < 100
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError
#如果知道必须满足特定条件,程序才能正确地运行,可在程序中添加assert语句充当检查点,这很有帮助。还可在条件后面添加一个字符串,对断言做出说明。
>>> age = -1
>>> assert 0 < age < 100, 'The age must be realistic'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError: The age must be realistic

  1. 迭代字典
1
2
3
4
5
6
7
8
# 要遍历字典的所有关键字,可像遍历序列那样使用普通的for语句。
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
# 也可使用keys等字典方法来获取所有的键。如果只对值感兴趣,可使用d.values。你可能还
# 记得, d.items以元组的方式返回键值对。 for循环的优点之一是,可在其中使用序列解包。
for key, value in d.items():
print(key, 'corresponds to', value)
  1. 并行迭代

有时候,你可能想同时迭代两个序列。假设有下面两个列表:

1
2
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]

如果要打印名字和对应的年龄,可以像下面这样做:

1
2
for i in range(len(names)):
print(names[i], 'is', ages[i], 'years old')

i 是用作循环索引的变量的标准名称。一个很有用的并行迭代工具是内置函数 zip,它将两个
序列“缝合”起来,并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内
容,可使用 list 将其转换为列表。

1
2
>>> list(zip(names, ages))
[('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]

“缝合”后,可在循环中将元组解包。

1
2
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')

函数 zip 可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,函数 zip 将
在最短的序列用完后停止“缝合”。

1
2
>>> list(zip(range(5), range(100000000)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
  1. 迭代时获取索引
1
2
3
4
5
index = 0
for string in strings:
if 'xxx' in string:
strings[index] = '[censored]'
index += 1

这个解决方案虽然可以接受,但看起来也有点笨拙。另一种解决方案是使用内置函数
enumerate。

1
2
3
for index, string in enumerate(strings):
if 'xxx' in string:
strings[index] = '[censored]'

这个函数让你能够迭代索引 值对,其中的索引是自动提供的。

  1. 循环中的 else 子句
    1
    2
    3
    4
    5
    6
    7
    8
    from math import sqrt
    for n in range(99, 81, -1):
    root = sqrt(n)
    if root == int(root):
    print(n)
    break
    else:
    print("Didn't find it!")

在循环中使用 else 子句,可以在循环正常结束时执行,也可以在循环异常结束时执行。

列表推导式

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
# 列表推导式是列表创建的另一种方式。
squares = [n ** 2 for n in range(10)]
print(squares)

# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> [x*x for x in range(10) if x 3 == 0] %
[0, 9, 36, 81]

>>> [(x, y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

>>> girls = ['alice', 'bernice', 'clarice']
>>> boys = ['chris', 'arnold', 'bob']
>>> [b+'+'+g for b in boys for g in girls if b[0] == g[0]]
['chris+clarice', 'arnold+alice', 'bob+bernice']
# 这些代码将名字的首字母相同的男孩和女孩配对。

# 字典推导。

>>> squares = {i:"{} squared is {}".format(i, i**2) for i in range(10)}
>>> squares
{0: '0 squared is 0', 1: '1 squared is 1', 2: '2 squared is 4', 3: '3 squared is 9', 4: '4 squared is 16', 5: '5 squared is 25', 6: '6 squared is 36', 7: '7 squared is 49', 8: '8 squared is 64', 9: '9 squared is 81'}
# 在列表推导中, for前面只有一个表达式,而在字典推导中, for前面有两个用冒号分隔的表
# 达式。这两个表达式分别为键及其对应的值。

三人行

pass、 del 和 exec

pass 可以用来作为占位符,用于空语句块。

1
>>> pass

del 可以用来删除一个对象的引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> del var

# 这看似简单,但有时不太好理解。例如,在下面的示例中, x和y指向同一个列表:
>>> x = ["Hello", "world"]
>>> y = x
>>> y[1] = "Python"
>>> x
['Hello', 'Python']
# 你可能认为通过删除x,也将删除y,但情况并非如此。
>>> del x
>>> y
['Hello', 'Python']
#这是为什么呢? x和y指向同一个列表,但删除x对y没有任何影响,因为你只删除名称x,而没有删除列表本身(值)。事实上,在Python中,根本就没有办法删除值,而且你也不需要这样
# 做,因为对于你不再使用的值, Python解释器会立即将其删除。

exec 可以用来执行一段代码。

1
2
3
4
5
6
7
8
9
10
11
>>> exec("print('Hello, world!')")
Hello, world!

# eval

# exec执行一系列Python语句,而eval计算用字符串表示
# 的Python表达式的值,并返回结果( exec什么都不返回,因为它本身是条语句)。

>>> eval(input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 6 + 18 * 2
42

小结

本章介绍了多种语句。

  • 打印语句:你可使用 print 语句来打印多个用逗号分隔的值。如果 print 语句以逗号结尾,
    后续 print 语句将在当前行接着打印。
  • 导入语句:有时候,你不喜欢要导入的函数的名称——可能是因为你已将这个名称用作
    他用。在这种情况下,可使用 import … as …语句在本地重命名函数。
  • 赋值语句:通过使用奇妙的序列解包和链式赋值,可同时给多个变量赋值;而通过使用
    增强赋值,可就地修改变量。
  • 代码块:代码块用于通过缩进将语句编组。代码块可用于条件语句和循环中,还可用于
    函数和类定义中(这将在本书后面介绍)。
  • 条件语句:条件语句根据条件(布尔表达式)决定是否执行后续代码块。通过使用 if/elif/
    else,可将多个条件语句组合起来。条件语句的一个变种是条件表达式,如 a if b else c。
  • 断言:断言断定某件事(一个布尔表达式)为真,可包含说明为何必须如此的字符串。
    如果指定的表达式为假,断言将导致程序停止执行(或引发第 8 章将介绍的异常)。最好
    尽早将错误揪出来,免得它潜藏在程序中,直到带来麻烦。
  • 循环:你可针对序列中的每个元素(如特定范围内的每个数)执行代码块,也可在条件
    为真时反复执行代码块。要跳过代码块中余下的代码,直接进入下一次迭代,可使用
    continue 语句;要跳出循环,可使用 break 语句。另外,你还可在循环末尾添加一个 else
    子句,它将在没有执行循环中的任何 break 语句时执行。
  • 推导:推导并不是语句,而是表达式。它们看起来很像循环,因此我将它们放在循环中
    讨论。通过列表推导,可从既有列表创建出新列表,这是通过对列表元素调用函数、剔
    除不想要的函数等实现的。推导功能强大,但在很多情况下,使用普通循环和条件语句
    也可完成任务,且代码的可读性可能更高。使用类似于列表推导的表达式可创建出字典。
  • pass、 del、 exec 和 eval: pass 语句什么都不做,但适合用作占位符。 del 语句用于删除变
    量或数据结构的成员,但不能用于删除值。函数 exec 用于将字符串作为 Python 程序执行。
    函数 eval 计算用字符串表示的表达式并返回结果。

抽象

懒惰是一种美德

这里说的懒不是贬义词,而是说不做无谓的工作。

在有些语言(如C++、 Pascal和Ada)中,经常需要给参数赋值并让这种修改影响函数外部的变
量。在Python中,没法直接这样做,只能修改参数对象本身。

收集参数

参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。这样的行为
我们在5.2.1节见过:赋值时带星号的变量收集多余的值。它收集的是列表而不是元组中多余的值,
但除此之外,这两种用法很像。

1
2
3
4
5
6
7
8
9
10
11
12
13
def print_params(*params):
print(params)
>>> print_params(1, 2, 3)
(1, 2, 3)

def print_params_2(title, *params):
print(title)
print(params)

>>> print_params_2('Params:', 1, 2, 3)
Params:
(1, 2, 3)

与赋值时一样,带星号的参数也可放在其他位置(而不是最后),但不同的是,在这种情况
下你需要做些额外的工作:使用名称来指定后续参数。

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
>>> def in_the_middle(x, *y, z):
... print(x, y, z)
...
>>> in_the_middle(1, 2, 3, 4, 5, z=7)
1 (2, 3, 4, 5) 7
>>> in_the_middle(1, 2, 3, 4, 5, 7)
Traceback (most recent call last):

File "<stdin>", line 1, in <module>
TypeError: in_the_middle() missing 1 required keyword-only argument: 'z'

# 星号不会收集关键字参数。
>>> print_params_2('Hmm...', something=42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print_params_2() got an unexpected keyword argument 'something'

# 要收集关键字参数,可使用两个星号。
>>> def print_params_3(**params):
... print(params)
...
>>> print_params_3(x=1, y=2, z=3)
{'z': 3, 'x': 1, 'y': 2}

如你所见,这样得到的是一个字典而不是元组。可结合使用这些技术。

def print_params_4(x, y, z=3, *pospar, **keypar):
print(x, y, z)
print(pospar)
print(keypar)

# 其效果与预期的相同。

>>> print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2)
1 2 3
(5, 6, 7)
{'foo': 1, 'bar': 2}
>>> print_params_4(1, 2)
1 2 3
()
{}

小结

本章介绍了抽象的基本知识以及函数。

  • 抽象:抽象是隐藏不必要细节的艺术。通过定义处理细节的函数,可让程序更抽象。
  • 函数定义:函数是使用def语句定义的。函数由语句块组成,它们从外部接受值(参数),
    并可能返回一个或多个值(计算结果)。
  • 参数:函数通过参数(调用函数时被设置的变量)接收所需的信息。在Python中,参数有
    两类:位置参数和关键字参数。通过给参数指定默认值,可使其变成可选的。
  • 作用域:变量存储在作用域(也叫命名空间)中。在Python中,作用域分两大类:全局作
    用域和局部作用域。作用域可以嵌套。
  • 递归:函数可调用自身,这称为递归。可使用递归完成的任何任务都可使用循环来完成,
    但有时使用递归函数的可读性更高。
  • 函数式编程: Python提供了一些函数式编程工具,其中包括lambda表达式以及函数map、
    filter和reduce。

再谈抽象

本文作者:wxy

本文链接: https://c.undf.top/posts/3ahvaci/

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。

评论,秒回。

评论

如评论失效,请点击最下方的邮件图标联系作者。