Karinoya 学习室 资格考试 Cloud / AI / Python 合格实验室 控制结构与数据结构
日本語 English Français Bahasa Indonesia 한국어 Română ไทย Tiếng Việt 简体中文 繁體中文
资格考试 · Cloud / AI / Python 合格实验室
控制结构与数据结构 可以用简体中文阅读题目和解说。讲义(解说文章)仅有日文版。
查看日文版(含讲义) →
第1题 | for/else
给for语句加上else子句的以下代码,执行后输出的内容是哪一项?
for n in range(4): if n == 9: break else: print("done") print(n) 只输出 3,不输出 done 只输出 done,不输出 3 依次输出 3 和 done 依次输出 done 和 3 正确答案 D. 依次输出 done 和 3 附加在for上的else子句,会在循环没有被break而正常结束时执行。range(4)中没有9,因此break一次也不会发生,循环跑到最后后else中的print就会执行,输出done。之后的print(n)会输出跳出循环时n所保留的最后一个值3。如果搞错输出顺序,就会变成3先出现的形式;如果误以为else在循环结束时一定会被跳过,就会变成不输出done的形式;如果忽略了n在跳出循环后仍会保留,就会变成不输出3的形式。
第2题 | break与else
确认用break跳出循环时else子句会如何处理。以下代码的输出是哪一项?
for c in "abc": if c == "b": break print(c) else: print("no break") a b c 和 no break 全部输出 依次输出 a 和 no break 依次输出 a 和 b 两者 输出 a,不输出 no break 正确答案 D. 输出 a,不输出 no break 第1轮c是a,因此print(c)执行,输出a。第2轮c变为b,用break中断循环。for的else子句只有在没有被break、正常结束时才会执行,因此这里会被跳过,不会输出no break。如果误以为else在循环结束时一定会执行,就会连no break也输出;如果误读为print(c)在break之前,就会连b也输出;如果忽略break本身,就会a b c全部输出。
第3题 | 空对象也会执行else
问在遍历对象为空时for的else子句会怎样。以下代码的执行结果是哪一项?
items = [] for it in items: print(it) else: print("finished") else子句被忽略,发生 TypeError 因为迭代0次,发生 StopIteration 什么都不输出,直接跳出循环结束 只输出一次 finished 正确答案 D. 只输出一次 finished for的else子句被执行的条件是『循环没有被break地结束』,而不是『至少迭代过一次』。由于items为空,主体一次也不会运行,但也没有break,因此else会照常执行,输出finished。如果认为『为空的话else也会被跳过』,就会得出什么都不输出的结论。把空列表传给for本身是合法的写法,不会引发异常,也不会抛出TypeError或StopIteration。
第4题 | while/else
给while语句加上else子句,并考虑中途break的情况。以下代码的输出是哪一项?
n = 5 while n > 0: n -= 1 if n == 2: break else: print("loop ended") print(n) 输出 0,不输出 loop ended 输出 2,不输出 loop ended 依次输出 loop ended 和 2 依次输出 loop ended 和 0 正确答案 B. 输出 2,不输出 loop ended n从5开始每次减1,经过4、3后到达2时break。while的else子句与for一样,只有在没有被break地结束时才会执行,因此这里会被跳过,不会输出loop ended。剩下的只有print(n)输出的2。如果认为else一定会执行,就会连loop ended也输出;如果忽略break、误以为会一直循环到条件为假为止,就会误读成n变为0的形式。
第5题 | continue
在一个循环中混用continue和break的以下代码,执行后最终输出的列表是哪一项?
out = [] for i in range(6): if i == 3: continue if i == 5: break out.append(i) print(out) [0, 1, 2, 4, 5] [0, 1, 2, 3] [0, 1, 2, 4] [0, 1, 2, 3, 4] 正确答案 C. [0, 1, 2, 4] 当i为0、1、2时,会依次通过两个if,被append。当i为3时continue生效,跳过该轮剩余部分,也就是跳过append。当i为4时又会被append,当i为5时用break中断循环,因此不会append。所以结果是[0, 1, 2, 4]。如果认为break那一轮也会被添加,就会得到一直排到5的形式;如果把continue当作pass来处理,就会得到保留3的形式。
第6题 | range的逆序
问给range传入负步长时的排列。以下代码的输出是哪一项?
print(list(range(10, 0, -3))) [9, 6, 3, 0] [7, 4, 1, -2] [10, 7, 4, 1, 0] [10, 7, 4, 1] 正确答案 D. [10, 7, 4, 1] range(start, stop, step)会从start开始,每次前进step,在到达stop之前停止。这里从10每次减3,得到10、7、4、1,下一个-2由于小于等于0而不被采用。由于不包含stop的0,所以不会是末尾排着0的形式。如果误以为不包含start,就会得到从7开始的形式;如果认为要从start往前数一个开始,就会得到从9开始的形式。不包含stop这一点与步长为正时相同。
第7题 | range的类型
关于调用内置函数range所得对象的说明,恰当的是哪一项?
是generator类型的对象,迭代一次后就会变空 是range类型的对象,传给list()后会变成列表 是tuple类型的对象,元素不能被替换 是list类型的对象,会直接以方括号形式显示 正确答案 B. 是range类型的对象,传给list()后会变成列表 range返回的是range类型的对象,会在需要时逐个计算所需的整数。它不像列表那样预先持有全部元素,因此即使范围很大也不会占用大量内存。想要排列出内容确认时,可以传给list()。type(range(3))得到的是range,既不是list也不是tuple,直接显示时也不会是元素排列的形式,而是range(0, 3)。此外它并非一次性用完,可以反复多次迭代,因此也不是generator。不过下标可读、元素不能替换这一点与元组相同,仅凭这一性质无法把它与tuple区分开。
第8题 | 短路求值
确认逻辑运算符or和and分别返回什么。以下代码的输出是哪一项?
print([] or 0 or "z") print(1 and 0 and 2) 依次输出 True 和 False 依次输出 False 和 0 依次输出 z 和 0 依次输出 z 和 2 正确答案 C. 依次输出 z 和 0 or会从左开始求值,原样返回第一个为真的值。空列表和0都为假,因此最后的"z"会被返回。and则相反,会返回第一个为假的值,因此1为真,接下来的0确定为假,于是返回0,最右边的2不会被求值。返回的不是真假值本身,而是求值停止那一刻的值,因此不会出现True或False。and返回最右边的2,只发生在中途全部为真的情况下。
第9题 | 链式比较
把链式比较和三元表达式组合起来的以下代码,执行后输出的内容是哪一项?
x = 3 print(1 < x < 5) print("yes" if x % 2 else "no") 依次输出 True 和 yes 依次输出 True 和 no 依次输出 False 和 no 依次输出 False 和 yes 正确答案 A. 依次输出 True 和 yes 1 < x < 5 与 (1 < x) and (x < 5) 含义相同,若x为3,两者都成立,因此为True。三元表达式的形式是『为真时的值 if 条件 else 为假时的值』,条件是x % 2,即1。Python中非0的整数会被当作真值,因此选中yes。如果把链式比较误读成从后往前结合,即 1 < (x < 5),则x < 5为True即1,于是1 < 1为False,得到错误答案。此外如果把1当作假,就会选中no。
第10题 | pass的作用
关于Python的pass语句的说明,恰当的是哪一项?
表示直接中断循环本身,跳出循环 在语法上需要代码块的位置,表示什么都不做 表示跳过循环剩余部分,进入下一次迭代 表示结束函数的执行,向调用方返回值 正确答案 B. 在语法上需要代码块的位置,表示什么都不做 Python用缩进来表示代码块,因此无法写出空的代码块。当打算以后再补写类或函数的内容,或在符合某条件时故意什么都不做时,就用pass来填补那个位置。它没有改变处理流程的作用。进入下一次迭代的是continue,中断循环的是break,向调用方返回值的是return,它们的作用都与pass不同。
第11题 | enumerate
给enumerate传入第2个参数的以下代码,执行后屏幕上出现的是哪一项?
for i, name in enumerate(["gu", "choki", "pa"], 1): print(i, name) 输出3行:1 gu / 2 choki / 3 pa 输出3行:0 gu / 1 choki / 2 pa 输出3行:gu 1 / choki 2 / pa 3 只输出2行:1 gu / 2 choki 正确答案 A. 输出3行:1 gu / 2 choki / 3 pa enumerate会依次返回(编号, 元素)这样的元组,可以用第2个参数start指定从几开始计数。这里传入了1,因此编号是1、2、3。若与省略start时默认从0开始的情况混淆,就会得到从0开始的形式。返回的元组是编号在前、元素在后,因此print(i, name)的排列顺序也是这样,名称不会排在前面。3个元素都会被取出,因此不会只输出2行就中断。
第12题 | zip的长度
把两个长度不同的列表传给zip。以下代码的执行结果是哪一项?
print(list(zip([1, 2, 3], [10, 20]))) [(1, 10), (2, 20)] [(1, 10), (2, 20), (3,)] [(1, 10), (2, 20), (3, 0)] [(10, 1), (20, 2)] 正确答案 A. [(1, 10), (2, 20)] zip会从传入的各个可迭代对象中依次各取一个组成一组,一旦最短的那个耗尽就结束。这里第2个列表只有2个元素,因此只会组成2组,多出的3会被悄悄丢弃。不会报错,也不会用0补齐剩余部分,也不会生成只有一个元素的元组。组内的内容会按传入的顺序排列,因此不会出现像10和1那样调换的情况。
第13题 | 用zip拆解
把已配好对的数据加上星号重新传给zip。以下代码的输出是哪一项?
pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, chars = zip(*pairs) print(nums) print(chars) 先输出 [1, 2, 3],再输出 ['a', 'b', 'c'] 先输出 (1, 2, 3),再输出 ('a', 'b', 'c') 先输出 ((1, 'a'),),再输出 ((2, 'b'),) 先输出 (1, 'a'),再输出 (2, 'b') 正确答案 B. 先输出 (1, 2, 3),再输出 ('a', 'b', 'c') 加上星号后,列表中的每一组会分别作为独立的参数传给zip。也就是相当于调用了zip((1, 'a'), (2, 'b'), (3, 'c')),各组的第1个元素汇总在一起、第2个元素汇总在一起,分成(1, 2, 3)和('a', 'b', 'c')这两组。这是把配好对的数据还原成原来两组数据的常用手法,把zip用两次就能还原。返回的是元组而不是列表,因此不会是方括号的形式。如果忘记加星号写成zip(pairs),配对本身会作为一个参数传入,就会变成((1, 'a'),)这样只有1个元素的元组排列的形式。
第14题 | dict与zip
从键的排列和值的排列构造字典。以下代码的执行结果是哪一项?
keys = ["a", "b", "c"] vals = [10, 20, 30] print(dict(zip(keys, vals))) [('a', 10), ('b', 20), ('c', 30)] {10: 'a', 20: 'b', 30: 'c'} {'a', 'b', 'c', 10, 20, 30} {'a': 10, 'b': 20, 'c': 30} 正确答案 D. {'a': 10, 'b': 20, 'c': 30} zip(keys, vals)会依次返回(键, 值)这样的元组,dict()接收这一系列的组来构造字典。组的第1个元素是键,第2个元素是值,因此不会出现数值作为键的形式。因为经过了dict()处理,所以也不会保持元组列表的原样。虽然都是用花括号显示,但用冒号配对的是字典,只并列值的则是集合。
第15题 | 列表推导式
使用列表推导式的以下代码执行后,输出的列表是哪一项?
print([n * n for n in range(1, 5)]) [0, 1, 4, 9] [2, 4, 6, 8] [1, 4, 9, 16] [1, 4, 9, 16, 25] 正确答案 C. [1, 4, 9, 16] range(1, 5)返回的是1、2、3、4,不包含指定为stop的5。把它们各自平方,得到1、4、9、16。若误以为range从0开始,就会得到从0排起的形式;若误解为包含stop,就会排到25。若把n * n误读成n * 2,就会变成每次增加2的形式。应牢记推导式的读法:对每个元素求出左端表达式的值,把这些结果排列成一个新列表。
第16题 | 字典推导式
在花括号内写上冒号的推导式被执行。以下代码的输出是哪一项?
words = ["sun", "moon"] print({w: len(w) for w in words}) {'sun': 3, 'moon': 4} [('sun', 3), ('moon', 4)] {3: 'sun', 4: 'moon'} {'sun', 'moon', 3, 4} 正确答案 A. {'sun': 3, 'moon': 4} 花括号内带冒号的推导式是字典推导式,冒号左边是键,右边是值。这里得到的是以单词为键、以其字符数为值的字典。若把键和值读反,就会变成字符数作为键的形式。用方括号括起来会变成元组列表,但这里是花括号,所以不会是那样。没有冒号的话会是集合推导式,显示为只并列值,但既然有冒号,得到的就是字典。
第17题 | 圆括号的类型
把类似推导式的表达式用圆括号括起来。执行以下代码时显示的类型是哪一项?
g = (n for n in range(3)) print(type(g)) <class 'range'> <class 'list'> <class 'generator'> <class 'tuple'> 正确答案 C. <class 'generator'> Python中没有『元组推导式』这种写法,用圆括号括起来的这种形式会变成生成器表达式。其类型是generator,不会预先生成全部的值,而是在需要时才逐个计算,因此省内存,但由于是迭代器,用过一次就会耗尽。想要元组时需要用tuple()包起来。用方括号书写会变成列表推导式,得到list;若直接把range(3)赋值,则会得到range。用这种写法无法得到tuple。
第18题 | 集合推导式
统计用集合推导式创建的容器的元素个数。以下代码的输出是哪一项?
print(len({n % 4 for n in range(10)})) 输出 3 输出 0 输出 10 输出 4 正确答案 D. 输出 4 range(10)的每个值除以4的余数依次是0、1、2、3、0、1、2、3、0、1。花括号内没有冒号的推导式是集合推导式,重复的值会被合并为一个,剩下的是0、1、2、3这4种。如果忽略重复会被消除、直接数值的个数,就会得到10。如果忽略余数中含有0、只数1、2、3这3种,就会得到3。0是把推导式误以为什么都不生成时的值,但只要遍历range(10),内容就不会为空。由于集合的显示顺序不固定,用元素个数来确认才是可靠的方法。
第19题 | 双重推导式
问并列写两个for的推导式的排列顺序。以下代码的执行结果是哪一项?
print([(x, y) for x in [1, 2] for y in "ab"]) [(1, 'a'), (2, 'b'), (1, 'b'), (2, 'a')] [('a', 1), ('b', 1), ('a', 2), ('b', 2)] [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')] [(1, 'a'), (2, 'a'), (1, 'b'), (2, 'b')] 正确答案 C. [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')] 在推导式中并列写两个for时,写在左边的for是外层循环。这与把普通for语句嵌套书写时的顺序完全相同:先把x固定为1,让y遍历a、b,然后再把x变为2,重复同样的过程。如果把右边的for读成外层,就会得到x先变化的顺序。组内的内容按表达式中写的(x, y)的顺序排列,因此字母不会排在前面。
第20题 | start参数
关于内置函数enumerate的第2个参数start,恰当的说明是哪一项?
指定计数从哪个数字开始。省略时从0开始计数 指定从哪个元素开始取出。省略时从开头取 指定每次跳过几个。省略时每次前进1个 指定数到第几个为止。省略时数到最后 正确答案 A. 指定计数从哪个数字开始。省略时从0开始计数 enumerate的第2个参数start,只决定所附加的编号从哪个数字开始。默认是0,如果传入1,就会得到面向人的连续编号。变化的只是编号的赋予方式,被取出的元素范围和个数不会改变,这一点很关键。它没有限制个数或跳跃的作用,也不是用来错开取出的起始位置的。这些说明分别对应的是切片等其他工具。
第21题 | sort的返回值
用变量接收列表 sort 方法的返回值。以下代码的输出是哪一项?
nums = [5, 3, 9] result = nums.sort() print(result) print(nums) 依次输出 [3, 5, 9] 和 [3, 5, 9] 依次输出 None 和 [5, 3, 9] 依次输出 [3, 5, 9] 和 [5, 3, 9] 依次输出 None 和 [3, 5, 9] 正确答案 D. 依次输出 None 和 [3, 5, 9] sort 是就地对列表排序的方法,返回值是 None。因此 result 中存入的是 None,排序结果留在 nums 一侧。如果误以为会返回一个排好序的新列表,就会得到 result 中存有列表的形式。如果忽略了 sort 会改变原列表,就会得到 nums 保持原顺序不变的形式。想要在保留原列表的同时得到排好序的新列表,应使用内置函数 sorted。
第22题 | sorted的区别
关于列表的 sort 方法与内置函数 sorted 的区别,恰当的是哪一项?
sort 返回新列表,sorted 就地排序并返回 None sort 就地排序并返回 None,sorted 返回新列表 两者都返回新列表,原列表都不会改变 两者都会就地排序,并返回排好序的列表 正确答案 B. sort 就地排序并返回 None,sorted 返回新列表 sort 是列表的方法,会对该列表本身进行排序,返回值为 None。sorted 是内置函数,完全不改变原顺序,返回排好序的新列表。是否想保留原列表,决定了该用哪一个。如果把两者的角色对调来记忆,就会得出 sort 返回新列表这样的说法。如果把是否具有破坏性都归到一方,就会得出两者都就地排序或两者都不改变原列表这样的说法。此外 sorted 还能接收列表以外的可迭代对象,结果总是列表。
第23题 | append的差异
比较把另一个列表添加到列表中的两种方法。以下代码的输出是哪一项?
a = [1, 2] a.append([3, 4]) b = [1, 2] b.extend([3, 4]) print(a, b) [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, 3, 4] [1, 2, [3, 4]] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, [3, 4]] [1, 2, 3, 4] 正确答案 D. [1, 2, [3, 4]] [1, 2, 3, 4] append 会把参数整体作为一个元素添加到末尾,因此传入列表就会变成嵌套形式,长度只增加1。extend 会把参数迭代取出的值逐个添加,因此内容会被拆开,长度增加2。如果把两者的作用对调,a 和 b 的结果就会相反。如果认为两者作用相同,就会得到两者都嵌套或两者都拆开的形式。这两个方法的返回值都是 None,因此也要记住不能用变量接收其结果。
第24题 | 浅拷贝
用切片复制嵌套列表后,改写内层。以下代码的执行结果是哪一项?
orig = [[1, 2], [3, 4]] copy1 = orig[:] copy1[0].append(9) print(orig) [[1, 2, 9], [3, 4, 9]] [[1, 2, 9], [3, 4]] [[1, 2], [3, 4]] [[1, 2], [3, 4], 9] 正确答案 B. [[1, 2, 9], [3, 4]] 通过切片复制得到的是浅拷贝,外层列表是新建的,但内部的元素与原来的共用同一个对象。copy1[0] 与 orig[0] 指向同一个列表,因此对它 append 时,原来一侧也会看到变化。如果误以为能完全切断联系,就会得到原列表不变的形式。由于改写的只是最前面的内层列表,不会波及到后面的元素,也没有对外层做添加,所以 9 不会排在外层。想连内层也切断,需要使用 copy.deepcopy。
第25题 | 深拷贝
在一段代码里比较深拷贝和浅拷贝。执行后 base 会变成怎样?
import copy base = [[1, 2], [3, 4]] d = copy.deepcopy(base) s = base[:] d[0].append(8) s[1].append(7) print(base) [[1, 2], [3, 4]] [[1, 2, 8], [3, 4, 7]] [[1, 2, 8], [3, 4]] [[1, 2], [3, 4, 7]] 正确答案 D. [[1, 2], [3, 4, 7]] copy.deepcopy 会连嵌套的内容一并复制,因此 d[0] 与 base[0] 是不同的列表,对它 append 不会影响到 base。而 s 是浅拷贝,s[1] 与 base[1] 是同一个列表,对它 append 也会反映到 base。因此只有后面的元素会变长。如果认为两者都会影响到 base,就会得到内层两个都变长的形式;如果认为两者都不会影响,就会得到保持原样的形式。如果把深拷贝和浅拷贝搞反,就会得到只有前面的元素变长的形式。
第26题 | 乘法的陷阱
试图用列表乘法构造二维表格。以下代码的执行结果是哪一项?
grid = [[0] * 3] * 2 grid[0][1] = 5 print(grid) [[0, 0, 0], [0, 5, 0]] [[5, 0, 0], [5, 0, 0]] [[0, 5, 0], [0, 0, 0]] [[0, 5, 0], [0, 5, 0]] 正确答案 D. [[0, 5, 0], [0, 5, 0]] 外层的乘法并不会创建新的行,只是把对同一个列表的引用并排放置两份。grid[0] 与 grid[1] 是同一个实体,因此改写其中一个下标1处的值,另一个看起来也会在同一位置发生变化。如果认为各行是独立的,就会得到只有一行发生变化的形式。改写的是下标1处的位置,因此也不会变成开头是5的形式。想让各行相互独立,需要写成 [[0] * 3 for _ in range(2)]。
第27题 | 单元素元组
比较只用圆括号括起来的值,与末尾加了逗号的值的类型。以下代码的输出是哪一项?
x = (7) y = (7,) print(type(x).__name__, type(y).__name__) 依次输出 int 和 int 依次输出 tuple 和 tuple 依次输出 tuple 和 int 依次输出 int 和 tuple 正确答案 D. 依次输出 int 和 tuple 决定元组的不是圆括号而是逗号。(7) 只是用表示运算优先级的括号括起来的整数,因此类型是 int;只有像 (7,) 那样在末尾加上逗号,才会成为只有1个元素的元组。如果误以为用括号括起来就会变成元组,就会得到两者都是 tuple 的形式;如果把两者弄反,就会得到顺序相反或两者都是 int 的形式。此外空元组是例外,要写成不带逗号的 ()。
第28题 | 元组的内容
试图给放在元组里的列表添加元素。以下代码的执行结果是哪一项?
t = (1, [2, 3], 4) t[1].append(5) print(t) 会抛出 TypeError (1, [2, 3], 4, 5) (1, [2, 3, 5], 4) (1, [2, 3], 4) 正确答案 C. (1, [2, 3, 5], 4) 元组冻结的是『指向哪个元素』这一对应关系,而不是被指向对象的内容。t[1] 是一个列表,该列表本身是可变的,因此可以对它 append。像 t[1] = [] 这样对元组的元素本身赋值才会引发 TypeError,但这里并没有替换元素。添加的是列表内部的内容,因此元组的长度既不会增加,也不会完全不受影响。
第29题 | 切片赋值
把长度不同的列表赋值给列表的切片。以下代码的输出是哪一项?
x = [1, 2, 3, 4, 5] x[1:3] = [9] print(x) [1, 9, 4, 5] [1, 9, 3, 4, 5] [1, 9, 9, 4, 5] [1, 2, 9, 4, 5] 正确答案 A. [1, 9, 4, 5] 对切片赋值是把指定范围整体替换为右边内容的操作。x[1:3] 指的是2和3这2个元素,它们会被替换为9这1个元素,整体长度从5减为4。如果认为只替换1个元素,就会得到长度仍为5的形式;如果认为右边会被拉伸以适应宽度,就会得到并排两个9的形式。如果把范围起点错读成偏移了一位,就会得到保留2的形式。左边的宽度与右边的长度可以不同,正是切片赋值的特点。
第30题 | 插入与删除
连续对宽度为0的切片赋值并执行 del。以下代码的执行结果是哪一项?
y = [1, 2, 3] y[1:1] = [7, 8] del y[0] print(y) [7, 8, 3] [1, 7, 8, 3] [7, 8, 2, 3] [2, 3, 7, 8] 正确答案 C. [7, 8, 2, 3] y[1:1] 是宽度为0的范围,因此对它赋值是不伴随删除的插入,列表变为 [1, 7, 8, 2, 3]。接下来的 del y[0] 会去掉开头的1,剩下 [7, 8, 2, 3]。如果认为插入时原有元素也会消失一个,就会得到 7 8 3 的形式;如果认为 del 删的是别的位置,就会得到保留开头1的形式;如果误读为添加到末尾,就会得到2和3排在前面的形式。del 是语句,没有返回值,只是删除而不取出值,这一点也应掌握。
第31题 | get的默认值
用 get 查找字典中不存在的键。执行以下代码时输出的内容是哪一项?
d = {"a": 1, "b": 2} print(d.get("z"), d.get("z", 0)) 依次输出 None 和 0 第1处会抛出 KeyError 依次输出 None 和 None 依次输出 0 和 0 正确答案 A. 依次输出 None 和 0 get 在键不存在时不会抛出异常,若省略第2个参数则返回 None,若传了该参数则返回该值。因此第1处是 None,第2处是 0。如果认为没有第2参数时也会返回0,就会得到两者都是0的形式;如果认为第2参数会被忽略,就会得到两者都是None的形式。用方括号写成 d["z"] 会引发 KeyError,get 正是用来避免这一点的工具。
第32题 | setdefault
对已存在的键和不存在的键都调用 setdefault。以下代码的输出是哪一项?
d = {"a": 1} print(d.setdefault("a", 99)) print(d.setdefault("b", 99)) print(d) 依次输出 99 和 99,之后输出 {'a': 99, 'b': 99} 依次输出 1 和 99,之后输出 {'a': 1, 'b': 99} 依次输出 1 和 None,之后输出 {'a': 1, 'b': None} 依次输出 1 和 99,之后输出 {'a': 1} 正确答案 B. 依次输出 1 和 99,之后输出 {'a': 1, 'b': 99} setdefault 在键存在时只会返回已有的值,不会改变字典。键不存在时会把第2个参数作为值插入,并返回该值。因此第1次返回已有的1,字典保持不变;第2次插入99并返回99。如果认为连已有的值也会被覆盖,就会得到两者都是99的形式;如果认为不会发生插入,就会得到字典没有增加的形式。省略第2参数时插入的值会是None,因此得到None这一结果,对应的是没有写第2参数的情况。
第33题 | in所查看的对象
确认字典的 in 运算符查的是什么。以下代码的输出是哪一项?
d = {"x": 1, "y": 2} print("x" in d, 1 in d, 1 in d.values()) 依次输出 True False True 依次输出 True True True 依次输出 True False False 依次输出 False True True 正确答案 A. 依次输出 True False True 对字典使用 in 只会检查键。"x" 在键中存在,因此为True;1虽然作为值存在,但不在键中,因此为False。想检查值时应针对 d.values(),这样会得到True。如果认为 in 也会查看值,就会全部得到True;如果认为即使针对 values() 也不查看值,就会最后一项得到False。如果把键和值的作用对调来读,第一项就会得到False。先确认键是否存在、再用方括号取值,是常见的用法。
第34题 | 键的重复
在字典字面量中把同一个键写了两次。以下代码的执行结果是哪一项?
d = {"a": 1, "b": 2, "a": 3} print(d) {'a': 3, 'b': 2} {'a': 1, 'b': 2} {'b': 2, 'a': 3} {'a': 3, 'b': 3} 正确答案 A. {'a': 3, 'b': 2} 字典字面量会按从左到右的顺序依次建立条目,因此同一个键出现两次时,后面的值会覆盖前面的值。这不会导致报错或警告。如果认为先写的会保留,就会得出 a 的值仍是1。此外字典会保留插入的顺序,覆盖并不会移动位置,因此顺序仍是 a 在前。所以键的排列不会改变,b 的值也不会被牵连改变。
第35题 | 字典的构造方式
比较用关键字参数构造的字典与用组的排列构造的字典。以下代码的输出是哪一项?
d1 = dict(x=1, y=2) d2 = dict([("x", 1), ("y", 2)]) print(d1 == d2) print(d1) 依次输出 False,之后是 {'x': 1, 'y': 2} 依次输出 True,之后是 {1: 'x', 2: 'y'} 依次输出 True,之后是 {'x': 1, 'y': 2} 依次输出 True,之后是 [('x', 1), ('y', 2)] 正确答案 C. 依次输出 True,之后是 {'x': 1, 'y': 2} dict 既能从关键字参数构造字典,也能从(键, 值)组的排列构造字典。无论哪种写法,得到的字典内容相同,因此比较结果为True。如果认为构造方式不同就会变成不同的东西,比较就会得到False。关键字参数的名字会直接成为键的字符串,因此键和值不会调换。经过 dict 处理后就已经是字典了,因此也不会保持组的排列原样。
第36题 | 空花括号
比较空花括号与 set() 的类型。执行以下代码时,显示的两个类型名是哪一项?
a = {} b = set() print(type(a).__name__, type(b).__name__) 依次输出 dict 和 dict 依次输出 set 和 set 依次输出 dict 和 set 依次输出 set 和 dict 正确答案 C. 依次输出 dict 和 set 有内容的 {1, 2} 会成为集合,但内容为空时,无法判断是字典还是集合。Python 在这种情况下把它当作字典处理,因此 {} 是空字典。想要空集合,只能写成 set()。如果认为花括号总是表示集合,两者都会得到set;如果把两者弄反,顺序就会相反。如果认为连 set() 也会变成字典,两者都会得到dict。由于集合和字典都使用花括号,这个区分很容易搞混。
第37题 | 集合的运算
对两个集合进行交集和对称差运算。以下代码的输出是哪一项?
s1 = {1, 2, 3, 4} s2 = {3, 4, 5} print(sorted(s1 & s2), sorted(s1 ^ s2)) 依次输出 [3, 4] 和 [1, 2, 3, 4, 5] 依次输出 [1, 2, 5] 和 [3, 4] 依次输出 [3, 4] 和 [1, 2] 依次输出 [3, 4] 和 [1, 2, 5] 正确答案 D. 依次输出 [3, 4] 和 [1, 2, 5] &是交集,两者都有的3和4会保留下来。^是对称差,会收集只属于其中一方的元素,因此只属于 s1 的1和2、只属于 s2 的5会保留,共同的3和4会被排除。如果把对称差与差集混淆,就会得到缺少5的形式;如果把两个运算调换,输出顺序就会相反。如果把对称差与并集混淆,就会连3和4也包含进去。集合的显示顺序不固定,因此这里用 sorted 排列后确认。
第38题 | 去除重复
把带有重复的列表传给集合。执行以下代码时的输出是哪一项?
data = [3, 1, 3, 2, 1, 1] print(len(set(data)), sorted(set(data))) 依次输出 6 和 [3, 1, 3, 2, 1, 1] 依次输出 6 和 [1, 2, 3] 依次输出 3 和 [3, 1, 2] 依次输出 3 和 [1, 2, 3] 正确答案 D. 依次输出 3 和 [1, 2, 3] 把列表传给 set 会去除重复,剩下1、2、3这3种值,因此长度是3。把集合传给 sorted 会返回按升序排列的新列表。如果认为重复会保留,个数就会得到6。sorted 是按大小而非原出现顺序排列的,因此也不会按最先出现的顺序排列。集合本身的显示顺序没有意义,想要排列时应通过 sorted。
第39题 | 元素的条件
试图依次把元组和列表添加到集合中。执行以下代码会怎样?
s = set() s.add((1, 2)) s.add([3, 4]) print(len(s)) 输出 1,列表被转换为元组 发生 TypeError,列表不能放入集合 发生 ValueError,元素类型不能混合 输出 2,两个元素都进入了集合 正确答案 B. 发生 TypeError,列表不能放入集合 集合的元素和字典的键必须是可哈希的。元组内容不可更改,因此可哈希,可以添加;而列表之后内容可能改变,因此不可哈希,会得到带有 unhashable type 提示的 TypeError。如果认为两者都能加入,就会输出2;如果认为会被隐式转换为元组,就会输出1。类型混合本身并不是问题,因此认为会发生 ValueError 的理由也是错误的。
第40题 | 三种取出方式
关于字典的 keys、values、items 这三个方法各自返回什么,恰当的组合是哪一项?
keys 返回值的组,values 返回键的组,items 返回条目数 keys 返回键与值的组,values 返回键,items 返回值 keys 返回值,values 返回键,items 返回值与值的组 keys 返回键,values 返回值,items 返回键与值的组 正确答案 D. keys 返回键,values 返回值,items 返回键与值的组 keys 只返回键,values 只返回值,items 依次返回 (键, 值) 这样的元组。遍历字典时,用 for k, v in d.items() 这样以两个变量接收是常见写法。如果把三者的作用对调来记,就会得出诸如 keys 返回值这样的说法。items 返回的是条目的排列,而不是个数,因此说它返回条目数也是错误的,想知道个数应使用 len。此外,直接把字典传给 for 会取出键。
练习:做本页的题目 这是随机出题的练习工具(在启用 JavaScript 时运行)。即使不使用此工具,也可以阅读上方的全部题目和解说。
※ 解说是供学习用的信息。考试的出题范围和制度每年可能变化,请务必确认主办机构的官方公告。
本页面译自日文原文。如译文与原文内容不一致,以日文版为准。 查看日文原文