Python Basics: PTA Problems
PTA Problems of ZJU Python Programming, 2024 Spring & Summer.
基础知识
判断题
Q1-1-7. 在 Python 中,可以用 else 作为变量名。
Answer
F。Python 的保留字不能作为变量名,else 是保留字。通过如下方法可以看到所有 Python 的保留字:
Q1-1-11. 下面程序的输出是 5。
Answer
F。print
是 Python 的内置函数,但是在这里被赋值为 3,因此将被作为一个整数变量看待,而不是函数。
因此会报错 TypeError: 'int' object is not callable
。
Q2-1-1. 当输入是 45,8
时,下面程序的输出结果是 37。
Answer
F。报错 ValueError: invalid literal for int() with base 8: 'a'
,因为 'a' 在八进制下是没有意义的。
需要了解 int(value, base)
函数中 value
和 base
的意义(见 Review - inta
和 'a'
的区别。
Q2-1-2. 表达式 -2**2
等于 4。
Answer
F。**
优先级高于 -
。
Q3-1-3. 希望输入正整数 6 和 5,求和 6+66+666+6666+66666,下面程序正确吗?
Answer
F。再次注意,'a' 是一个字符常量,而 a 是一个变量。a 和 'a' 一般没有关联。
Q3-1-4. 当输入是 10.0 时,下面程序的输出是 f(10.0) = 0.1
。
Answer
F。x=int(input())
会报错 ValueError: invalid literal for int() with base 10: '10.0'
。
注意 int 函数只能将字符串按整数进行解释,如果无法解释,将会报错。
Q5-1-1-6. 已知 x=3, 则执行 x=7
后,id(x)
的返回值与原来没有变化。
Answer
F。id
函数返回对象的内存地址,x=7 与原来的 x=3 不是同一个对象了,内存地址会发生变化。
Q5-1-1-7. int("92",8)
的值是 74。
Answer
F。根据 int(value, base)
函数中 value
和 base
的意义(见 Review - intValueError: invalid literal for int() with base 8: '92'
。
Q6-1-16. 表达式:"34" in "1234"==True
返回值是 True
。
Answer
F。用到了比较运算符的链接。
Q7-2-4. 2 == 2.0
的结果是 False。
Answer
F。比较作为 int 的 2 和 float 的 2.0 时,2 会先被转换为 float 2.0,然后进行比较,即
关于这种混合数值类型计算时的类型转换规则,可以参照 Review - 数值类型混合运算。
Q15-1-10. 变量不需事先声明就可使用。
Answer
T。Python 是一种动态类型语言,变量的类型是在运行时确定的,不需要事先声明。
选择题(不一定单选)
Q1-2-12. 下面程序的输出是什么?
A. 59
B. 5,9
C. 5 9
(5 和 9 之间 1 个空格)
D. 5 9
(5 和 9 之间 2 个空格)
Answer
C。print 的 sep 参数默认为 " "
。
Q2-2-10. 指出错误的说法。
A. 表示复数的语法是 real + imag j
B. 实部和虚部都是 int
C. 虚部必须后缀 j, 且必须是小写
D. 方法 conjugate 返回复数的共轭复数
Answer
BC。实部和虚部都是 float,虚部后缀可以是 j 或者 J。
Q5-1-3-1:2:3:4. 以下是合法标识符的是
A. true
B. print
C. 2age
D. _age
Answer
ABD。
A,Python 中的标识符是区分大小写的,True
是保留字,但 true
不是保留字,是合法标识符。
B,print
是内置函数名,不是保留字,是合法标识符。
C,标识符不能以数字开头。
D,下划线开头的标识符是合法的。
标识符由字母、数字、下划线组成,但不能以数字开头。
Q15-2-1. 下面哪些不是 Python 可以接受的变量名?
A. abc
B. _23ac
C. 23_ac
D. good-name
Answer
CD。Python 变量名可以由字母、数字、下划线组成,但不能以数字开头。
Q15-2-8. 下面语句解释器将抛出什么错误信息?
A. NameError
B. IndexError
C. SyntaxError
D. TypeError
Answer
B。列表越界错误。
填空题
Q2-1-3:4:5. 计算以下表达式。
Answer
对于第一行,True 是 bool 类型,是 int 的 子类型,对应 int 的 1。对于第二行,空列表转 bool 为 False,非空列表转 bool 为 True。特别地,bool([[]]) 也为 True。
对于第三行,bin
, oct
, hex
都要求输入为 int,详见 Review - int。
Q2-2-7:11. 给出以下程序的输出结果。
Answer
先输出 A 和 65。chr 将 ascii 码转化为字符,ord 把字符转化为 ascii 码。
后报错 TypeError: can only concatenate str (not "int") to str
。int 和 str 不能直接相加。
特别地,如果 print(x * y)
,将会输出 dogdogdogdogdogdog
,即字符串乘法的结果。
Q2-4-1:2:5:15. 计算以下四行的输出。
Answer
对于第一行,有对于第四行,两个负号相互抵消了效果,所以又回到了原始的 3。
关于运算符优先级和结合性的内容可以去 Review - 运算符优先级与结合性查漏补缺。
Q3-2-6:8:9. 给出以下程序的输出结果
Answer
对于第一行,0xA
和 0xB
分别是 10 和 11 的十六进制表示,相加为 21。
对于第二行,先计算出大于号左侧为 7.42,然后和 0 比较,返回 True。注意运算顺序上大于号最后计算,最终返回值为 bool 类型。
对于输出的第三行,math
库中的 sqrt
函数的返回值为 float 类型,两个 float 相乘还是 float,因此按照 float 输出为 6.0。
Q3-4-4:7:12:17. 给出以下程序的输出结果
Answer
关于运算符优先级和结合性的内容可以去 Review - 运算符优先级与结合性查漏补缺。对于第一行,计算顺序为
对于第二行,计算顺序为
对于第三行,字符串拼接可以直接写在一起,不需要额外的 +
;由于是拼接而不是作为两个参数输入 print,中间就没有空格。
对于第四行,20//4
的结果是 int 5,但是 43.5//2
的结果是 float 21.0,所以最后结果为 float 类型。
Q5-1-1-45. 当输入为 3 5
时,分别给出如下两段程序的输出。
Answer
int(input().split())
会报错,因为 int
函数不能直接作用于 input().split()
所得到的字符串列表。
对于第二段程序,input().split()
返回的是字符串列表 ['3', '5']
,所以 m+n
是字符串拼接,结果为 35
。
Q5-1-2-123. 给出如下三段程序的输出(输入已经在注释中标出
Answer
对于第一段程序,input()
返回的是字符串,所以 type(a)
是 <class 'str'>
。
对于第二段程序,int(input())->int('123')->123
返回 int 123,所以 type(a)
是 <class 'int'>
。
对于第三段程序,int(input())=int('12.3')
会报错,因为 int
函数不能直接作用于字符串 '12.3'
。
Q5-1-4-123. 给出如下三段程序的输出:
Answer
对于第一段程序,m.pi
是 math
库中的圆周率,{:08.2f}
表示总长度为 8,保留 2 位小数,不足的地方用 0 填充,所以输出为 00003.14
。
对于第二段程序,pi
没有被定义,会报错 NameError: name 'pi' is not defined
。对于这种方式,需要 from math import pi
。
对于第三段程序,尽管 from math import *
导入了 math
库中的所有函数和常量,但没有导入 math
这一名字,因此使用 math.pi
会无法识别 math
。
Q5-2-2-123. 给出以下程序的输出结果:
Answer
对于第一行,1J
是复数(只有虚部的纯虚数),因此得到 complex。
对于第二行,1//2
是两个 int 进行整除,所以还是返回 int。注意只要除数与被除数有一者是 float,结果就会变为 float。
对于第三行,121 + 1.21
是 int 加 float,返回 float。只要有 float 参与运算,结果就会变为 float。
Q5-2-5-1. 以下程序的输出是a
的 ASCII 码为 97)
Answer
a#c#e#g#
。
每隔两个字符输出一个字符,并且由于 print 的 end 从默认的 '\n'
改为了 '#'
,每个字符后面都会跟着一个 #。
Q5-4-1-1:2:3:6 以下程序的输出是?
Answer
对于第一行,有对于第二行,有
对于第三行,有
对于第四行,有
Q9-4-6:5. 以下程序的输出是
Answer
对于第一行,hex
和 bin
分别是将十进制 int 转化为十六进制和二进制表示的 str 的转换函数。
对于第二行,按十六进制和二进制解释输入字符串,输出对应的十进制 int。
可以参考 Review - int。
字符串
判断题
Q6-1-5. 可以通过 []
来访问字符串的某个字符,也可以将它修改成其他字符。
Answer
F。可以通过下标访问,但是不能修改,因为字符串是不可变的。
Q9-1-15. 下面程序的输出结果为 yes
。
Answer
F。
s1
的每个数字后面都有一个空格,s2
仅在各数字之间存在空格,因此 s1
在末尾比 s2
多了一个空格,输出为 no
。
关于 join 可以回顾 Review - join: split 的逆操作。
Q9-1-17*. "12 "*3==" ".join([12, 12, 12])
的输出是 False
选择题
Q4-2-2. 以下哪句打印出 I\love\Python\test
?
A. print("I\love\Python\test")
B. print("I\\love\\Python\\test")
C. print("I\"love\"Python\"txt")
D. print("I"\love"\Python"\txt")
Answer
B。\
是转义字符,如果要输出 \
本身,需要使用 \\
,所以 A 错 B 对。
C 是转义输出 "
的方法,会输出 I"love"Python.txt
。
D 是错误的写法,会报错 SyntaxError: unexpected character after line continuation character
。
Q9-2-14. 能打印输出 I'm python.
的语句是 ?
A. print('I'm python.')
B. print('I\'m python.')
C. print(r'I'm python.')
D. print('I"m python')
Answer
B。通过转义 \
使得 '
失去代码中划定字符串的功能,成为字符串的一部分被输出。
A,三个 '
,使得字符串字面量范围无法被清楚地划定,会报错。
C,raw string 可以免于大部分特殊字符的转义 \
,但在此处 '
是关键的划定字符串字面量范围的字符,因此在这里无法仅用 raw string 解决问题。
D,会输出 I"m python
,不符合要求。但是如果用 print("I'm python")
可以实现功能。
关于 raw string 乃至字符串字面量的更多内容详见官方文档:String and Bytes literals - Python 3.12.3 documentaion
Q4-2-12. 下列说法错误的是:
A. 字符即长度为 1 的字符串
B. 字符串以 \0 标志字符串的结束
C. 既可以用单引号,也可以用双引号创建字符串
D. 在三引号字符串中可以包含换行回车等特殊字符
Answer
B。字符串以 \0
标志字符串的结束是 C 语言的特性,Python 中字符串以长度标志字符串的结束。
三引号字符串是一种特殊的字符串,会保留其中字符串的格式,也就是会包含其中的换行、回车等特殊字符。
填空题
Q3-1-1. 以下程序的输出是:
Answer
f-string 和 format 输出字符串时,如果设定的宽度大于字符串的实际宽度,默认会在字符串右侧填充空格;而 % 这种格式化字符串,默认会在字符串左侧填充空格。详见 Review - 格式化字符串。Q4-4-1:8. 下面程序的输出是:
Answer
对于第一行,字符串乘法'67'*3
是将字符串 '67'
重复 3 次,即 '676767'
。
对于第二行,
bin(31)
是将 int 类型的 31 转换为其二进制表示的字符串'0b11111'
[2:]
去掉了前缀0b
,得到字符串切片'11111'
- 然后
{:>08s}
控制格式为靠右对齐,总长度为 8,不足的地方用0
填充(即在左侧填充) ,所以输出的字符串为'00011111'
Q5-2-1-2. 下面程序的输出是:
Answer
1 2 3
(1、2、3 前面都有 1 个空格a, b, c = c, a, b
后,a=3, b=1, c=2;
"{1:2d}{2:2d}{0:2d}".format(a, b, c)
表示输出的顺序为 b, c, a,且各自占 2 个字符的宽度,不足宽度的部分(默认)在左侧填充空格。
Q6-1-15. 给出以下程序的输出,输入为 c d e a
,每个字母前面都有一个空格,a
后面无空格。
Answer
a.sort()
是没有返回值的一个语句,因此 for i in a.sort()
是不合法的。a.sort()
会直接对 a
进行排序。
Q6-1-15+. 给出以下程序的输出,输入为 c d e a
,每个字母前面都有一个空格,a
后面无空格。
Answer
a = input().split()
后,有 a = ['', 'c', 'd', 'e', 'a']
。
a.sort()
排序后,有 a = ['', 'a', 'c', 'd', 'e']
。因此最后会得到这样的输出。
Q6-4-2:9:12. 给出以下程序的输出。
Answer
对于第一行,'3//11//2018'.split('/') = ['3', '', '11', '', '2018']
,列表长度为 5。
对于第二行,找到第 2 个 "r" 的位置,即下标为 4。
对于第三行,判断 "aABC" 是否每个字符都是英文字母,所以为 True。
对于第四行和第五行输出,s.title()
是返回一个 s 中首字母变成大写之后的字符串,但并不改变 s 本身(字符串不可变
对于第六行输出,统计 s 中子串 'ab' 的数量,那就是 2。
Q9-2-30. 输入:12#11##10
,程序输出为?
Answer
a=['12', '11', '', '10']
。从而有 len(a)=4, a[-1]='10', a[0]='12'
。
0, 2, 1 对应的分别为 len(a), a[0], a[-1]
,因此最后结果为 4:12:10
。
Q9-4-13. 以下程序的输出为
Answer
"{first}-{second}={0}".format(34-23,first=a,second=b)
中的 0
对应的是 34-23
,first
对应的是 a
,second
对应的是 b
。注意这种 format 的用法比较少见但确实是合法的,可见 Review - 格式化字符串。
Q15-2-10. 下面代码的输出结果是
Answer
相当于每行输出的总宽度都是 20,三行格式分别为居中、右对齐、左对齐,输出内容是 666666,用 "T" 字符填充空缺部分。
Q15-4-2. 输入 dbc
时,以下程序的输出是
Answer
dd
。
len(my_str) - 1 = 2
,所以只会进行 index_int
为 0 和 1 的两次循环。
index_int = 0
时,my_str[0] > my_str[1]
,所以 result_str
乘 2,变为 dd
。
Q15-4-12. 以下程序统计字符串中各字符出现次数。
填空,可在下面 9 个选项中选择。
Answer
DHB。
- 可以看出
mdict
是一个字典,所以应该用mdict = {}
来初始化 for e in mlist:
遍历字符串中的每个字符,需要有e
,否则循环中的e
没有意义了mdict.items()
可以遍历字典中的键值对,不能只有键或只有值
程序结构
判断题
Q3-1-2. z 已被赋值,则 x=(y=z+1)
是错误语句。
Answer
T。Python 的赋值语句是没有返回值的,不允许这种写法,在编译时直接会被认为是非法语句。
而 x=y=z+1
是合法的,这是因为 Python 特别规定了这种连等的赋值语句,将会首先计算最右侧的表达式,将其计算结果赋值给左边的每一个对象。
关于赋值语句的更多内容可以参考 Review - 赋值语句。
Q8-1-2. 带有 else
子句的循环如果因为执行了 break
语句而退出的话,会执行 else
子句的代码。
Answer
F。else
子句只有在循环正常结束时才会执行,如果是因为 break
语句退出的,else
子句不会执行。
Q8-1-6. 以下程序的输出是 3
。
Answer
F。
在遍历列表时,不要对列表进行增删操作,容易会导致遍历出错。这里发生的事情大概为:
- 前一轮循环,取出 lst 中的前 3 个元素,不是 0,继续。
- 第四轮循环,取出 lst 中的第 4 个元素 0(下标为 3
) ,删除这个元素,lst 变为[34, 6, 7, 0, 0, 9]
。 - 第五轮循环,取出 lst 中的第 5 个元素 0(下标为 4
) ,删除这个元素,lst 变为[34, 6, 7, 0, 9]
。 - 此时发现 lst 的长度已经是 5 了,没有第 6 个元素,因此不再继续。
所以最后 n
的值就是 2。
Q9-1-17. 下面程序的输出是 [3, 2, 3, 4, 5]
。
选择题
Q5-2-3-2. 输入整数 x,当 x 不为 0 时输出 1/x 的值,否则输出 0。以下代码段正确的是:
A.
B.
C.
D.
Answer
C。由于 int 类型的 x 被强制处理为 bool,仅当 x 为 0 的时候会被认为是 True,非零即为 False。因此,if x
和 if x != 0
是等价的。
A,if x=0
应该为 if x==0
。
B,if x!=0
后面漏了一个冒号。D 同样也是漏了冒号。
Q5-2-4-1. 以下哪段代码可以实现对数列 \(-1/2+2/3-3/4+4/5-5/6\) 的求和?
A. sum([i-1/i if i%2==1 else 1-i/i for i in range(2,7)])
B. sum([for i in range(2,6) (i-1)/i if i%2 else (1-i)/i ])
C. sum([(i-1)/i if i%2 else (1-i)/i for i in range(2,7)])
D. sum([(i-1)/i if i%2 else (1-i)/i for i in range(7)])
Answer
C。对于列表推导式,应将其展开解读。
B 首先应该排除,这是不合法的列表推导式写法,应当将列表中元素的形式放在最前面。
A 应当解读为:
i-1/i=i-(1/i)
,1-i/i=1-1.0=0.0
,完全不符合题目要求的数列形式。
C 应当解读为:
D 的解读与 C 类似,只是 range
的起点不同,第一项会计算 (1-0)/0
,发生除零错误。
Q8-2-5. 下面哪个语句不能完成 1 到 10 的累加功能,total 初值为 0。
A. for i in range(10,0):total+=i
B. for i in range(1,11):total+=i
C. for i in range(10,0,-1):total+=i
D. for i in (10,9,8,7,6,5,4,3,2,1):total+=i
Answer
A。步长默认为正步长 1,初始就有 10<0
,于是没能进入循环。
B 是正确的,range(1, 11)
会生成 1 到 10 的整数序列。
C 是正确的,range(10, 0, -1)
会生成 10 到 1 的整数序列。
D 是正确的,for i in (10,9,8,7,6,5,4,3,2,1)
会遍历元组中的元素。
Q8-2-7. 下面程序输入 1 时,输出是什么?
A. 不是素数
B. 是素数
C. 没有输出
D. 出现异常
Answer
B。当输入 1 时,a
的初始值为 0,不会进入 while
循环,直接输出 是素数
。
填空题
Q7-2-6:3:4. 以下三段程序的输出为
Answer
1
。由于 a
大于 0,所以第一个条件满足,执行完毕后直接跳出,不会执行 elif
语句。
Answer
Grade D
。
由于 score
为 82,满足第一个条件,因此 grade
直接被赋值为 D
,不会再执行后面的 elif。
Answer
Python
。遇到 s == "N"
时,执行 break
语句,直接跳出循环。
Q7-4-1:4. 以下三段程序的输出为
Answer
PythonNCRE
。
当 s 为 "N" 时,会进入 while 循环,然后 break
表示离开最近的一层循环(也就是 while
循环
当 s 不是 "N" 时,不进入 while 循环。因此实际上就是打印了整个 "PythonNCRE"。
Answer
对于第一行,i=1
,j=0
,j<i
,输出 0
。
对于第二行,i=2
,j=0
,j<i
,输出 0 1
。
对于第三行,i=3
,j=0
,j<i
,输出 0 1 2
。
对于第四行,i=4
,j=0
,j<i
,输出 0 1 2 3
。
Answer
45
。对于列表中的每个元素,如果是列表,则将列表中的元素相加,否则直接加到 s 上。
该程序仅针对最多嵌套一层的列表进行求和,而且假定各基础元素都是数值类型可以互相相加。
Q8-2-3. 下面程序中语句 print(i*j)
的执行次数为
Answer
15 次。外层循环 5 次,内层循环 3 次,总共 5*3=15
次。
Q9-4-16:24:27. 以下 3 段程序的输出为
Answer
150
。可以按如下计算
Answer
2
。
对于第二行代码,首先算出等号右侧的 2 和 t+1=2
。随后按顺序赋值,先将 2 赋值给 t,再将算好的 t+1 的值,也就是 2 赋值给 a。
关于赋值语句的计算顺序,可以参考 Review - 赋值语句。
Answer
6
。
尽管我们说lst[:]
是复制了一份原列表,被遍历的是复制的列表、被删除的是原列表,因此不会出错。
在遍历的过程中,删除了所有模 3 不为 1 的 6 个元素。
Q15-4-14. 输入一个十进制正整数,将它对应的二进制数的各位反序,形成新的十进制数输出。如有多组答案可选,则选答案字符序在先的那组答案。
如:13→1101→1011→11 如:10→1010→0101→5
在下面 9 个答案中选择。
Answer
AHI。
其思想是,一开始的 t=x%2
是二进制最低位,反向后是二进制最高位。逐渐将 x//2
,可以得到原来的数中更高维的二进制数位,然后反向后的数位逐渐变低。累加,使用 *2+t
的方法,对应二进制相邻数位之间的关系。
Q15-4-15. 10 进制转 16 进制。
在下面 9 个答案中选择。
Answer
BGE。
value
会逐渐变化,所以不能直接使用原来的decimal
,因为在最后还需要输出decimal
- 模仿前面的,其实就是 single 对应的字符
value
逐渐除以 16,获得十六进制的下一位
列表与元组
判断题
Q6-1-23 [4,5]*3
的结果是 [[4,5],[4,5],[4,5]]
。
Answer
F。其结果为 [4, 5, 4, 5, 4, 5]
,每个元素的内存都是独立的。
而 [[4,5]]*3
的结果是 [[4, 5], [4, 5], [4, 5]]
,但是这个二维列表(矩阵)中的每个一维列表共享内存,即该矩阵的每一行都是同一行。例如会有:
可以参考 Review - 列表。
Q9-1-22. [1,2,[3]]+[4,5]
的结果是 [1,2,3,4,5]
。
Answer
F。其结果为 [1, 2, [3], 4, 5]
,两个列表直接相加,会将第二个列表整体加到第一个列表的末尾。
Q6-1-14 以下程序的运行结果是运行错误。
Answer
T。列表越界错误。
Q9-1-1. 字符串、列表、元组都是序列类型。
Answer
T。参考 Review - 数据类型。
Q9-1-2. 列表可以用 find()
函数来搜索数据是否在列表中。
Answer
F。find()
是字符串的方法,用于查找子串的位置,列表没有这个方法。
Q9-1-3. 字符串对象和元组对象是不可变对象,列表对象为可变对象。
Answer
T。参考 Review - 可变类型与不可变类型。
选择题
Q9-2-15. 如果 list1 = [1, 2, 3, 4, 5, 4, 3, 2, 1]
,那么以下哪个是 list1[:-1]
?
A. 0
B. [1, 2, 3, 4, 5, 4, 3, 2, 1]
C. [1, 2, 3, 4, 5, 4, 3, 2]
D. [0, 1, 2, 3, 4, 3, 2, 1, 0]
Answer
C。舍去最后一个元素后的列表,注意是 list1[:-1]
而不是 list1[::-1]
。
Q15-2-12. 下面程序的运行结果是什么?
A. 9
B. 10
C. 8
D. 其他
Answer
D。报错在第 4 行:TypeError: unsupported operand type(s) for +=: 'int' and 'list'
。
这是一个循环引用的例子,b[2]
指向了 b
这个列表,是一种特殊的用法,这种用法本身并不会报错。
实际执行中,row
取 1 和 2 不会发生问题;接下来 row
取 b[2]
也就是 b
,也不会发生问题。
接下来由于 b 是 list 类型,就会执行 for elem in b
。elem
取 1 和 2 也不会发生问题,但是接下来 elem
还是会取到 b
,此时的 s
是 int 类型,但是 b
是 list 类型,会试图将 s
与 b
相加,于是会报错。
填空题
Q6-2-1:3. 给出如下三个表达式的结果:
Q6-4-3:14. 给出以下两段程序的输出。
Answer
Answer
对于第一行输出,直接赋值b=a
是一个引用赋值,b 和 a 对应的内存空间是相同的。
对于第二行输出,copy
会将整个一维列表进行拷贝,内存空间会不一样。
对于第三行输出,切片操作会进行类似 copy
的操作,而不是引用赋值。
可以参考 Review - 列表。
Q7-4-7:8:9:10. 给出以下四段程序的输出。
Answer
首先把 a
构造为 [0, 0, 0]
,每个 0 都是一行的占位符。随后循环为 a
补上每一行,每行都是长度为 m 的全零列表。利用了一维列表的乘法。由此前三行输出就很自然了。
对于最后一行输出,修改 a[2][2]
为 7 并不会影响其他元素,因为 a
的每一行都是单独构造 [0] * m
后赋值的,没有共享内存空间。
Answer
7
。
data
中的每一行都是同一个 row
,所以修改 data[0][2]
实际上是在修改 row[2]
,于是 data
的每一行都改变了
Answer
7
。
用这种方式构造出来的 data
矩阵的每一行也都是同一行。一维列表的乘法是拷贝值后拼接,二维列表的乘法就是拷贝引用后拼接了。
Answer
0
。
这种方式构造的 data
矩阵的每一行都是独立构造的 [0]*3
,因此修改 data[2][2]
不会影响其他元素。
对于列表的困惑,可以参考 Review - 列表。
Q9-1-5:6:7:8:9:10:11:12. 给出以下程序的输出。
Answer
列表切片 [start:stop:step]
的意义是从 start
开始,到 stop
结束,每隔步长 step
取一个元素,与 range
是类似的。
step
默认为 1,start
默认为 0,stop
默认为列表的长度。值得注意的是,stop
可以取大于列表的长度,会被自动截断。
Q15-4-6. 给出如下两段程序的输出。
Answer
22
列表直接赋值给另一个变量是引用赋值,因此list1
和 list2
都指向同一个列表,修改 list1
的元素也会影响 list2
。
Answer
7
发生了列表的拷贝,d1
和 d2
是两个不同的列表,d1[0]=6
不会影响 d2
,因此输出是 6+1=7
。
排序与矩阵计算
判断题
Q8-1-5. 下列程序在输入 36
时输出为 10
。
Answer
F。这个二分查找是有问题的,while
的条件应该改为 left <= right
。对于 36
这一输入,最后会进入 left == right
,然后直接退出循环(本应先令 found = mid
的
填空题
Q9-4-25. 给出以下程序的输出。
Answer
11
。
mat
是一个 5 行 3 列的矩阵,即
构造 mat
的语句可以展开解读为
同理,mattrans
的构造可以解读为
可以看出,mattrans
逐渐将 mat
的第 0, 1, ... 列加入到第 0, 1, ... 行,因此是 mat
的转置矩阵。
因此,mattrans[1][3]
就是 mat[3][1]
,即 11
。
Q13-4-12. 给出如下程序的输出
Answer
12
这个程序实现了框架像插入排序、实现像冒泡排序的一种排序算法的递归版本,ins_sort_rec
函数的作用是将 seq
中前 i
个元素排序。因此 ins_sort_rec(seq, len(seq)-1)
就是对 seq
进行排序。
其逻辑为,如果 i==0
说明无需排序,否则就首先先将前 i-1
个元素进行排序。此时,前 i-1
个元素已经是有序的,只需让第 i
个元素插入到前 i-1
个元素中,使得前 i
个元素有序,接下来的 while
循环就是将第 i
个元素插入到前 i-1
个元素中的过程。
由于排序后 seq
的第 5 个元素是 12,因此输出就是 12。
Q14-4-14. 请填空如下程序,实现冒泡排序。
Answer
len(List)-1
冒泡排序的基本思想是,每次比较相邻的两个元素,如果顺序不对就交换。第一轮比较后,最大的元素就会被交换到最后一个位置;第二轮比较后,第二大的元素就会被交换到倒数第二个位置;以此类推,第 j
轮比较后,第 j
大的元素就会被交换到倒数第 j
个位置。
Q14-4-15. 请填空如下程序,实现选择排序。
Answer
bottom
或 bottom+1
或 mi
或 mi+1
选择排序的基本思想是,每次从未排序的元素中选择最小的元素,放到已排序的元素的末尾。第 bottom
轮比较后,最小的元素就会被放到第 bottom
个位置。
Q15-4-1. 执行下列语句后 v
的显示结果是什么 ?
Answer
33
这段程序的作用是找出二维列表 values
中的最大值。首先将 v
初始化为 values[0][0]
,然后遍历整个二维列表,如果发现更大的值就更新 v
。最终 v
的值就是整个二维列表的最大值。
Q15-4-13. 下面程序随机生成 10 个整数,将它们从大到小排序后输出。
在下面 9 个选项中选择。
Answer
D, A 或 H, I。
其实就是实现选择排序。
- 作为函数的形参列表,只有 D 是合法的
- A 和 H 都对,其实就是找到 k 之后的最小值,包含不包含 k 都对,当然包含 k 的话会多一次比较
- F 中 c[]
是不合法写法,E 中少输入了一个参数,I 是正确的方法
集合与字典
判断题
Q11-1-1. 集合的元素可以是任意数据类型。
Answer
F。集合的元素具有可哈希性,必须是不可变类型。
Q11-1-1+. 字典的值可以是任意数据类型。
Answer
T。字典的值可以是任意数据类型,包括列表、元组、集合、字典等。
Q11-1-1++ 字典的键可以是任意数据类型。
Answer
F。类似于集合的元素,字典的键也必须是不可变类型。
Q11-1-2. len(set([0,4,5,6,0,7,8]))
的结果是 7
。
Answer
F。集合中的元素具有唯一性,因此列表转换为集合后,只有 [0, 4, 5, 6, 7, 8]
这 6 个元素。
Q11-1-3. a={}
, type(a)
结果是 <class 'set'>
。
Answer
F。{}
默认是空字典,type(a)
的结果是 <class 'dict'>
。如果希望创建空集合,应该使用 set()
。
Q11-1-5. 列表可以作为字典的键。
Answer
F。列表是可变类型,不能作为字典的键。
Q11-1-13. 下面程序的输出是 5
。
Answer
F。
set2
是一个集合,包含了 1 到 15 中所有能被 3 整除的数,即 {3, 6, 9, 12}
,因此输出应该是 4。
选择题
Q11-2-3. 对于两个集合 s1
和 s2
,s1 < s2
的意思是?
A. s1
的大小小于 s2
的大小
B. s1
的元素比 s2
的小
C. s1
是 s2
的真子集
D. s2
是 s1
的真子集
Answer
C。
Q11-2-4. 对于集合 s
,以下哪个操作是不存在的?
A. len(s)
B. s.append(1)
C. max(s)
D. s - {1}
Answer
B。append
是列表的方法,不是集合的方法。
len(s)
是求集合中元素的个数,max(s)
是求集合中元素的最大值,s - {1}
是从集合中删除元素 1。
Q11-2-5. 对于正确的表达式 a[2]
,a
不可能是以下哪个类型?
A. 集合
B. 列表
C. 元组
D. 字典
Answer
A。集合具有无序性,不支持索引操作。
对于列表和元组,a[2]
是获取索引为 2 的元素;对于字典,a[2]
是获取键为 2 的值。
Q11-2-7. 你可以使用什么方法从字典中删除元素?
A. remove
B. rease
C. delete
D. del
Answer
D。remove
是列表和集合删除元素的方法。
Q11-2-8. 返回集合中元素个数的函数是
A. size()
B. len()
C. elements()
D. count()
Answer
B。
Q15-2-6 下面定义字典的语句哪个是正确的?
A. momthdays = dict(Jan=31, Feb=28, Mar=31, Apr=30)
B. momthdays = dict("Jan"=31, "Feb"=28, "Mar"=31, "Apr"=30)
C. momthdays = {Jan:31, Feb:28, Mar:31, Apr:30}
D. momthdays = {Jan=31, Feb=28, Mar=31, Apr=30}
填空题
Q12-4-1:2:3:4:5. 给出以下五段程序的输出。
Answer
144
。构造了一个字典,键为 0 到 19,值为键的平方,因此查询得到 12 的平方。
Answer
5
。
text.split()
会将字符串按空格分割为字符串列表,得到
然后构造子字符串(单词)到其长度的映射,键为单词,值为单词的长度
因此 lenwords["score"]
就是 5。
Answer
30
。
d.items()
是字典的键值对视图,for k,v in d.items()
就是遍历字典的键值对。[dic1, dic2]
是一个列表,遍历列表中的字典,将字典的键值对加入到新字典中,后面的键值对会覆盖前面的。相当于
Answer
75
。
cells
是一个字典,只有 values
这一个键,其值是一个二维列表(2 行 4 列的矩阵cells["values"][1][2]
就是取出这个矩阵第 2 行第 3 列的元素。
Answer
'red'
。
将构造 myth
的过程展开:
因此构造得到的 myth
为
所以 myth[1]["label"]
就是第 2 个字典的 label
值,即 'red'
。
Q15-4-8. 给出如下程序的输出。
Answer
3
。集合的元素具有唯一性,因此只剩下 [1, 2, 3]
这 3 个元素。
函数
判断题
Q13-1-1. 函数也是对象,下面程序可以正常运行吗?
Answer
T。
- 函数也是对象,所以打印
func
是合法的 - 并且函数具有内存地址和类型,所以
id(func)
和type(func)
也是合法的
选择题
Q13-2-2. 在 Python 中,对于函数定义代码的理解,正确的理解是
A. 必须存在形参
B. 必须存在 return
语句
C. 形参和 return
语句都是可有可无的
D. 形参和 return
语句要么都存在,要么都不存在
Answer
C。
函数可以没有形参,也没有 return
语句。如果没有形参,函数就不需要传入参数;如果没有 return
语句,函数就没有返回值。
Q13-2-5. 函数可以改变哪种数据类型的实参?
A. int
B. string
C. list
D. float
Answer
C。函数可以改变列表等可变对象的实参。
Q13-2-3. 在一个函数中如局部变量和全局变量同名,则:
A. 局部变量屏蔽全局变量
B. 全局变量屏蔽局部变量
C. 全局变量和局部变量都不可用
D. 程序错误
Answer
A。即在函数中,同名变量优先指代局部变量。
填空题
Q13-2-7. 下面程序的运行结果是什么?
Answer
**name
形式的形参的作用,**name
会将多余的关键字参数收集到字典 name 中。此处的关键字传参中,x1
, x2
, x4
已经有专门的形参接收,从而 x5
会被收集到 x3
中。
Q13-4-1:8:9:10. 给出以下四段程序的输出
Answer
Answer
1 6
。
此处未构造局部变量,因此函数向外部寻找 l
,并最后找到全局变量 l
进行使用,所以到 print 时的 l
就是 [1, 6]
。
*l
意为对列表 l
进行解包 (unpack) 后获得 print 函数的参数列表,即让 1 和 6 称为 print 的参数,实际上相当于调用了 print(1, 6)
。
关于函数的解包参数列表,可以参考 Review - 解包参数列表。
Answer
20 20
。
global
关键字用于声明全局变量,即声称函数内的 a
就是全局变量 a
,因此在函数内部修改 a
就是修改全局的 a
。
Answer
8
。
相比于上一段程序,这里的函数实现了对全局变量 a
的创建。
Q15-2-15. 给出如下程序的输出
Answer
4 4 2 4
g_func
中的局部的 b
屏蔽了全局的 b
,而不存在局部的 c
,因此 g_func
中的 c
是全局的 c
。
因此 g_func
中的 b
是 1*c=4
,d=b
,所以输出是 4 4
;回到全局,全局的 b
由于被局部屏蔽而没有被修改,而 c
还是 4,所以输出是 2 4
。
Q13-4-3:6. 给出如下两段程序的输出
Answer
lst
进行排序,得到
此处注意,字符串排序规则是首先根据第一个字符的 ascii 码,如果相同则再看第二个字符,以此类推。如果前 n 个字符都相同,一个字符串没有第 n+1 个字符,另一个存在第 n+1 个字符,那么认为长度就是 n 的字符串更小(相当于第 n+1 个字符的 ascii 码为 0
关于 Lambda 表达式的简单例子,可以参考 Review - Lambda 表达式。
Answer
41
根据 Lambda 表达式,f
的作用是输入 p
,返回 p+5
;t
的作用是输入 p
,返回 p*3
。
因此最终的 x
就是 ((x+5)*3) + 5
,即 41
。
Q13-4-5. 给出如下程序的输出
Answer
11 22 33
在 Python 中,函数是对象,可以像其他数据对象一样使用。funclist
中存储了三个函数,遍历 funclist
,依次调用三个函数。
递归与动态规划
填空题
Q13-4-4. 给出如下程序的输出
Answer
这个程序的作用是按照字符顺序输出 1, 2, 3 的全排列,使用了递归函数树形搜索。choice
表示可选的排列项,selected
表示前几位已经选择了的项。每次 perm
执行时,会遍历 choice
中的每个元素,即遍历每种可能的下一步的选择,然后把这一项从 choice
中去除,加入到 selected
。为了对下一种可能的选择进行尝试时,不被上一步的尝试影响,需要 insert
和 pop
这两行恢复上一步尝试产生的影响(把加入到 selected
的元素从 selected
删掉,重新加回到 choice
)
从顺序上,初始的 choice
中的顺序就是 1, 2, 3,因此遍历时的顺序也就是这样的字符顺序,所以输出全排列的顺序也就是字符顺序。
为了方便理解,给出 perm
函数的部分调用顺序:
Q13-4-7. 给出如下程序的输出
Answer
120
。
match
语句是 Python 3.10 新引入的模式匹配语法,case 0 | 1:
表示匹配 0 或 1,case _:
表示匹配其他情况。因此可以理解为
所以这个函数在计算 \(n!\),于是结果就是 \(5!\)。
更多关于 match
语句的内容,可以参考官方文档 match Statements - Python 3.12.3 documentaion。
Q13-4-11. 给出如下程序的输出
Answer
19
这个递归程序实际上 i
只能取到 2,一轮循环之后要么通过 break
退出循环结束函数,要么通过 return
结束函数。
因此对于 factors(n)
,
- 如果
n
不是 2 的倍数,那就会输出n
,然后结束函数 - 如果
n
是 2 的倍数,那就会执行factors(n//2)
,再判定n//2
是不是 2 的倍数 - 以此类推,直到执行
factors(n//(2 ** k))
,使得n//(2 ** k)
不是 2 的倍数,而且factors(n//(2 ** (k-1)))
是 2 的倍数时,就会输出n//(2**k)
,然后返回。由于前面每次调用的后面都紧跟着break
,因此都既不会再print
也不会再调用,最后一层层返回结束函数
于是递归函数 factors(38)
的执行过程可以展开为
Q15-2-11. 给出如下程序的输出
Answer
2 9 3
类似上题进行分析。递归函数 factors(18)
的执行过程可以展开为
Q13-4-13. 给出如下程序的输出
Answer
7
这个程序实现了最长递增子序列 (Longest Increasing Subsequence, LIS) 问题的动态规划算法。l
是一个列表,l[i]
表示以 seq[i]
结尾的最长递增子序列的长度。
算法的基本思想是,对于每个元素 seq[cur]
,l[cur]
的基本值是 1,对于所有比 cur
小的 pre
,如果 seq[pre] < seq[cur]
,那么到 pre
为止的递增子序列就可以在后面接上一个 seq[cur]
,于是出现新的递增子序列长度 1+l[pre]
。遍历之前的元素 seq[pre]
,找到最大的满足 seq[pre] < seq[cur]
的 1+l[pre]
,就是 l[cur]
的值。
对于输入 L
,最长递增子序列是 [49, 64, 66, 68, 87, 96, 99]
,长度为 7。
Q15-4-5. 下面程序用动态规划法快速计算斐波那契数,在下划线处填上正确的表达式。
Answer
memo[n]
这个递归程序的思想就是存储中间结果。计算 fib(n)
,利用递归首先需要计算 fib(n-1)
,此时它会需要算出 fib(n-2)
和 fib(n-3)
,但是算完 fib(n-1)
之后还需要去算 fib(n-2)
,实际上已经算过它了。
因此,为了避免重复计算,第一次算出 fib(n-2)
的时候就将它存进 memo
,这样第二次再遇到就可以直接查字典 memo
获得 fib(n-2)
的值。
具体而言,用能否查找成功判断是否是第一次计算。如果在字典中能查到,就说明已经被算过了,直接使用查找到的数值;如果发生 KeyError,就说明还没被算过,需要先把它算出来。
文件
选择题
Q15-2-3. 下面哪种方法读文件 input.txt
是正确的
A. in_file = open('input.txt', 'w')
B. in_file = open('input.txt', r)
C. in_file = open('input.txt', 'r')
D. 都不正确
Answer
C。
A 是写文件,B 的 'r'
缺少引号,mode 要求输入一个字符串。
填空题
Q15-4-11. 文件 populationdata.txt
是部分国家的人口数据。每行一个国家人口数据。统计人口数中以 "1"/"2"/"3"/"4"/"5"/"6"/"7"/"8"/"9" 开头的百分比数,输出样例如下所示:
这表示 "1" 开头的百分比数为 27.586206896551722
,"2" 开头的百分比数为 '19.396551724137932',以此类推。请填写下面程序中的空格,使得程序能够正确统计人口数据。
在下面 9 个可选项中选择。
Answer
HIG。
- 只用读取数据,所以
r
就可以了,a
和w
都不具有读的功能 - 要从文件中读每一行,只能使用
populationfile
- 只接收数字开头,字符开头不合法,因此应当使用
isdigit()
方法