Karinoya 學習室 證照 Cloud / AI / Python 合格實驗室 例外、類別與標準函式庫
日本語 English Français Bahasa Indonesia 한국어 Română ไทย Tiếng Việt 简体中文 繁體中文
證照 · Cloud / AI / Python 合格實驗室
例外、類別與標準函式庫 可以用繁體中文閱讀題目與解說。講義(解說文章)僅有日文版。
查看日文版(含講義) →
第1題 | try陳述式的順序
執行下列程式碼時,由上而下排列輸出的行是哪一項?
def calc(a, b): try: print("try") r = a / b except ZeroDivisionError: print("except") else: print("else") finally: print("finally") calc(9, 3) try、else、except try、else、finally try、except、else try、except、finally 正確答案 B. try、else、finally 9 / 3 不會產生例外,因此不會進入except。只有在沒有發生例外時才會執行的是else子句,因此會在try之後執行else。finally子句不論有無例外都一定會執行,因此最後才會執行。因此會是try、else、finally這3行。含有except的選項,是誤以為發生了例外時的排列,這個呼叫並不會發生ZeroDivisionError。缺少finally的選項,則是把finally誤解成「發生例外時的收尾」時的排列。
第2題 | else子句
關於try陳述式的else子句被執行的條件,下列何者正確?
不論有無例外,永遠最後執行 只有在try子句發生例外時才會執行 在沒有符合任何except子句時執行 只有在try子句沒有發生例外時才會執行 正確答案 D. 只有在try子句沒有發生例外時才會執行 try陳述式的else子句,只有在try子句一路執行到最後都沒有拋出例外時才會執行。與if陳述式的else是「條件為假時」相對,try陳述式的else則是搭配「順利成功時」的一方,方向相反,這樣記憶比較好。發生例外時執行的是except子句。不論有無例外都一定會執行的則是finally子句。若沒有符合任何except,並不會落入else,而是該例外會傳播到呼叫端。
第3題 | finally優先
執行下列程式碼時的輸出是哪一項?
def f(): try: return "T" finally: print("F") def g(): try: return "T" finally: return "N" print(f(), g()) 輸出F與T T這2行 輸出F與T N這2行 輸出T T與F這2行 輸出T N與F這2行 正確答案 B. 輸出F與T N這2行 f()準備好要return的值之後,在實際回傳之前會先執行finally子句。因此F會先顯示,回傳值仍維持T。g()的finally子句中含有return,這會覆蓋try子句的return,因此回傳值是N。print會先對f()與g()求值,再彙整成1行顯示,因此F那一行在前、T N那一行在後。變成T T的選項,是誤以為finally的return會被忽略;F排在後面的選項,則是誤以為finally會在return之後才執行時的答案。
第4題 | 無法捕捉的例外
以except Exception所寫的except子句無法捕捉的例外是哪一項?
FileNotFoundError ZeroDivisionError KeyboardInterrupt ModuleNotFoundError 正確答案 C. KeyboardInterrupt KeyboardInterrupt直接位於BaseException之下,並未繼承Exception。issubclass(KeyboardInterrupt, Exception)會是False。這是使用者試圖用Ctrl-C中止時所產生的,為了避免被寫得較廣泛的except Exception不小心吞掉,因此把階層分開了。SystemExit也位於相同的位置。其餘3者都是Exception的子孫:ZeroDivisionError在ArithmeticError之下,FileNotFoundError在OSError之下,ModuleNotFoundError在ImportError之下,因此都能被except Exception捕捉。
第5題 | 例外的父類別
IndexError與KeyError共通的最近父類別是哪一項?
ReferenceError ArithmeticError AttributeError LookupError 正確答案 D. LookupError IndexError與KeyError都具有「用索引或鍵去查找卻找不到」這種相同的性質,因此被放在名為LookupError的共通父類別之下。只要寫 except LookupError,就能同時接住列表超出範圍的存取,以及字典中不存在的鍵這2種情況。ArithmeticError是ZeroDivisionError等的父類別,用於計算本身無法成立的場合。AttributeError是找不到屬性時,ReferenceError則是弱參照所指對象已消失時的例外,兩者都直接位於Exception之下,與LookupError是不同的系統。
第6題 | except的順序
執行下列程式碼時的輸出,下列何者正確?
try: x = 8 / 0 except ArithmeticError: print("A") except ZeroDivisionError: print("Z") 什麼都不輸出就停止 只輸出Z 輸出A與Z 只輸出A 正確答案 D. 只輸出A 8 / 0會拋出ZeroDivisionError,而ZeroDivisionError是ArithmeticError的子類別。except子句會由上而下依序比對,在第一個吻合處就中止,因此先寫的except ArithmeticError會先接住,只輸出A。後面的except ZeroDivisionError不會有機會執行。由於吻合的except只會執行1個,因此不會同時輸出A與Z。原則是把範圍窄的(子類別)放在前面、範圍廣的(父類別)放在後面,本題的程式碼正好把這個順序顛倒了。
第7題 | 多個例外
執行下列程式碼時顯示的1行是哪一項?
def conv(s): try: return int(s) * 2 except (ValueError, TypeError) as e: return type(e).__name__ print(conv("21"), conv("abc"), conv(None)) 42 ValueError TypeError 42 TypeError TypeError 42 ValueError ValueError 42 TypeError ValueError 正確答案 A. 42 ValueError TypeError 在except後面寫上用圓括號括起來的元組時,只要吻合其中之一就會執行。conv("21")由於 int("21") 是21,因此回傳42。conv("abc")雖然能作為字串傳入,但無法解讀為數值,因此是ValueError。conv(None)由於型別不符合int()可接受的類型,因此是TypeError。型別正確但值不合適是ValueError、型別本身就不符合則是TypeError,這樣的區分直接對應答案的排列。
第8題 | 重新拋出
使用自訂例外與不帶引數的raise,下列程式碼的輸出是哪一項?
class LoadError(Exception): pass def load(): try: raise LoadError("bad") except LoadError: print("inner") raise try: load() except Exception as e: print("outer", type(e).__name__) 只顯示inner,不顯示outer 顯示inner與outer Exception這2行 顯示inner與outer LoadError這2行 顯示inner後,於LoadError停止 正確答案 C. 顯示inner與outer LoadError這2行 在except內只寫raise而不帶引數,會把目前正在處理的例外原樣重新拋回呼叫端。因此顯示inner之後,LoadError會傳到load()外部,由外層的except Exception接住。由於LoadError繼承自Exception,能被except Exception捕捉,因此不會停止。type(e).__name__回傳的是實際被拋出之例外類別的名稱,因此顯示的不是捕捉端的型別名稱Exception,而是LoadError。只顯示inner的情況,是沒有重新拋出、而是當場吞掉時的輸出。
第9題 | 未捕捉的例外
執行下列程式碼會得到什麼結果?
def get(seq, key): try: return seq[key] except IndexError: return "not found" print(get([1, 2, 3], 1)) print(get({"a": 1}, "z")) 顯示2後,於KeyError停止 顯示2與not found這2行 顯示2與KeyError這2行 顯示2與None這2行 正確答案 A. 顯示2後,於KeyError停止 第1次呼叫是列表的索引1,因此回傳2。第2次是查找字典中不存在的鍵,因此會拋出KeyError,但except中寫的只有IndexError。IndexError與KeyError雖然都是LookupError的子類別,但彼此之間並非父子關係,因此IndexError的except無法捕捉KeyError。未被捕捉的例外會傳播到呼叫端,由於沒有人接住,程式就會停止。若想同時接住兩者,可以寫 except LookupError,或用元組把兩者並列。
第10題 | assert
關於assert陳述式的說明,下列何者正確?
條件為假時拋出AssertionError,在python3 -O下會被停用 條件為假時拋出AssertionError,即使在python3 -O下也一定會執行 條件為真時拋出AssertionError,在python3 -O下會被停用 條件為假時拋出ValueError,即使在python3 -O下也一定會執行 正確答案 A. 條件為假時拋出AssertionError,在python3 -O下會被停用 assert 條件, 訊息 會在條件為假時拋出AssertionError。條件為真時則什麼都不會發生。重要的是,若以像python3 -O這樣的最佳化模式啟動,assert陳述式會整段被移除,1行都不會執行。因此不能把assert用於檢查使用者輸入的目的,那種用途應該用if判斷條件、拋出raise ValueError(...)。最好把assert當作是開發期間用來記下內部前提的工具,把角色區分清楚來記憶。
第11題 | self
關於方法的第1個引數self,下列說明何者正確?
是為了參照父類別屬性而保留的名稱 是呼叫該方法之實例本身會自動傳入的引數 是用來建立實例並回傳給呼叫端的引數 是類別本身會自動傳入的保留名稱 正確答案 B. 是呼叫該方法之實例本身會自動傳入的引數 寫成 d.speak() 時,Python會把它改讀成 Dog.speak(d) 來呼叫。這時候放入第1個引數位置的,就是呼叫端的實例本身。self這個拼寫只是慣例,並非語言保留的名稱。規格只規定第1個引數會接收自身,因此即使自己寫成 Dog.speak(d),也會有相同的動作。建立實例並回傳,是__new__與類別呼叫機制的職責,__init__只是對已經建立好的實例進行初始化。要參照父類別則使用super()。
第12題 | 類別變數
改寫類別變數的下列程式碼,其輸出是哪一項?
class Dog: kind = "canine" def __init__(self, name): self.name = name a = Dog("Rex") b = Dog("Mia") Dog.kind = "wolf" print(a.kind, b.kind) wolf wolf canine wolf canine canine wolf canine 正確答案 A. wolf wolf kind是直接寫在class之下的類別變數,由該類別所產生的所有實例共用同一個。a與b都沒有在自己的__dict__中持有kind,因此讀取屬性時會回溯到類別一方查看相同的值。對Dog.kind的賦值會改寫這個共用的唯一值,因此已建立的a與b兩者看到的都會是wolf。由於實例建立時不會複製該值,因此不會出現保留canine的形式。
第13題 | 屬性的陰影
對實例一方進行賦值的下列程式碼,其輸出是哪一項?
class Dog: kind = "canine" def __init__(self, name): self.name = name a = Dog("Rex") b = Dog("Mia") a.kind = "husky" print(a.kind, b.kind, Dog.kind) print(sorted(a.__dict__)) husky husky husky 與 ['name'] husky canine canine 與 ['kind', 'name'] husky canine canine 與 ['name'] husky husky husky 與 ['kind', 'name'] 正確答案 B. husky canine canine 與 ['kind', 'name'] 對a.kind賦值並不會改寫類別變數,而是在a的實例字典中建立一個名為kind的新項目。之後讀取a.kind時,會優先找到這個新項目,形成遮蔽類別變數的效果。b與Dog.kind仍維持原本的canine。因此a.__dict__中,除了__init__放入的name外,還會並列kind,用sorted排序後會是['kind', 'name']。全部變成husky的選項,是誤以為對實例賦值會改寫類別變數的情況;只剩['name']的選項,則是誤以為不會產生遮蔽效果時的答案。
第14題 | 被共用
把列表設為類別變數的下列程式碼,其輸出是哪一項?
class Basket: items = [] def add(self, x): self.items.append(x) p = Basket() q = Basket() p.add(1) q.add(2) print(p.items, q.items) p.items是[1],q.items是[1, 2] p.items是[1, 2],q.items是[2] p.items是[1, 2],q.items是[1, 2] p.items是[1],q.items是[2] 正確答案 C. p.items是[1, 2],q.items是[1, 2] self.items.append(x) 並不是對self.items賦值,而只是呼叫透過self.items抵達的那個物件。p與q都沒有各自的items,因此抵達的目的地都是類別變數那個唯一的列表。結果p加入的1與q加入的2都會存進同一個列表,不論從哪一方看都會是[1, 2]。若想讓每個實例各自擁有不同的容器,就要在__init__中以 self.items = [] 賦值建立。這樣一來就會分成[1]與[2]。
第15題 | super()
使用繼承與super()的下列程式碼,其輸出是哪一項?
class Animal: def __init__(self, name): self.name = name def cry(self): return self.name + " ?" class Cat(Animal): def __init__(self, name, color): super().__init__(name) self.color = color def cry(self): return self.name + " meow" c = Cat("Tama", "black") print(c.cry(), c.color, isinstance(c, Animal)) Tama meow None True Tama ? black True Tama meow black False Tama meow black True 正確答案 D. Tama meow black True Cat的__init__呼叫了 super().__init__(name),因此父類別Animal會幫忙設定self.name。之後又把black存入self.color,因此兩個屬性都齊備。cry在子類別中重新定義,因此父類別的實作會被覆蓋,呼叫到的是meow那一個。isinstance(c, Animal)由於Cat繼承自Animal,因此會是True。如果忘記寫super(),name就不會被設定,會發生AttributeError,因此不會像變成None的選項那樣悄悄地失敗。
第16題 | MRO
多重繼承的下列程式碼,其輸出是哪一項?
class A: def who(self): return "A" class B(A): def who(self): return "B" class C(A): def who(self): return "C" class D(B, C): pass print(D().who()) print([k.__name__ for k in D.__mro__]) B 與 ['D', 'B', 'C', 'A', 'object'] C 與 ['D', 'C', 'B', 'A', 'object'] B 與 ['D', 'B', 'A', 'C', 'object'] A 與 ['D', 'B', 'C', 'A', 'object'] 正確答案 A. B 與 ['D', 'B', 'C', 'A', 'object'] 方法解析順序是依C3線性化這項規則決定的,並非單純的深度優先。共通的父類別A,會被放在所有繼承A的子類別之後,因此排列會是D、B、C、A、object。若是鑽進B後就直接走到A的深度優先,會是D、B、A、C、object,但實際上並非如此,這是要留意之處。who()會從MRO開頭開始搜尋,使用第一個找到的,因此會回傳B。若寫成 class E(C, B),就會是E、C、B、A、object,先寫的一方優先。
第17題 | MRO的矛盾
在已定義 class B(A) 的情況下,寫下 class F(A, B): pass 會發生什麼事?
能夠定義,F().who() 會呼叫到A的版本 能夠定義,__mro__ 會是 F、A、B、object 能夠定義,F().who() 會呼叫到B的版本 在類別定義的時間點就會發生TypeError 正確答案 D. 在類別定義的時間點就會發生TypeError C3線性化有2項規則:要遵守基底類別排列的順序,以及父類別必須排在子類別之後。F(A, B) 是指定A要排在B之前,但B是A的子類別,因此父類別A必須排在子類別B之後。這2項規則無法同時滿足,因此被判定為無法建立一致的MRO,在對class定義求值的時間點就會發生TypeError。這並不是要執行過才會知道,而是在通過class陳述式的那一刻就會失敗。正確寫法應該是 class F(B, A),把子類別寫在前面。
第18題 | 名稱修飾
持有以底線開頭之屬性的下列程式碼,其輸出是哪一項?
class P: def __init__(self): self._one = 1 self.__two = 2 p = P() print(p._one, p._P__two) print(sorted(p.__dict__)) 1 2 與 ['_one', '_two'] 1 2 與 ['_P__one', '_P__two'] 1 2 與 ['__two', '_one'] 1 2 與 ['_P__two', '_one'] 正確答案 D. 1 2 與 ['_P__two', '_one'] 以1個底線開頭的_one只是慣例上表示內部使用,名稱不會改變,從外部也能正常讀取。以2個底線開頭的__two則會發生名稱修飾,實際的屬性名會被改寫成_P__two,也就是「_類別名__名稱」的形式。因此寫 p.__two 會發生AttributeError,但寫 p._P__two 就能讀取。__dict__中排列的也是修飾後的名稱,因此用sorted排序後會是['_P__two', '_one']。只有以2個底線開頭的才會被修飾,_one不在此列。
第19題 | 特殊方法
定義了特殊方法的下列程式碼,其輸出是哪一項?
class Vec: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "V({}, {})".format(self.x, self.y) def __repr__(self): return "Vec(x={}, y={})".format(self.x, self.y) def __len__(self): return 2 def __add__(self, o): return Vec(self.x + o.x, self.y + o.y) v = Vec(1, 2) print(v) print([v]) print(len(v), v + Vec(3, 4)) Vec(x=1, y=2) 與 [Vec(x=1, y=2)] 與 2 V(4, 6) V(1, 2) 與 [Vec(x=1, y=2)] 與 2 V(4, 6) V(1, 2) 與 [Vec(x=1, y=2)] 與 2 Vec(x=4, y=6) V(1, 2) 與 [V(1, 2)] 與 2 V(4, 6) 正確答案 B. V(1, 2) 與 [Vec(x=1, y=2)] 與 2 V(4, 6) print(v) 與 str(v) 會使用__str__,因此是V(1, 2)。另一方面,放進列表或字典等容器中顯示時,各個元素會分別使用__repr__,因此是 [Vec(x=1, y=2)]。這種用途的區分正是本題的重點。len(v) 是__len__回傳的2,v + Vec(3, 4) 是__add__回傳的新Vec,把它傳給print又會使用__str__,因此顯示為 V(4, 6)。若類別沒有定義__str__,會以__repr__代替,但反過來__repr__不會被__str__取代。
第20題 | __eq__
只定義了__eq__的下列程式碼,其輸出是哪一項?
class Point: def __init__(self, x): self.x = x def __eq__(self, other): return self.x == other.x p = Point(1) q = Point(1) print(p == q, p is q) print(Point.__hash__ is None) try: print(len({p, q})) except TypeError: print("TypeError") True False 與 False 與 2 True False 與 True 與 TypeError True False 與 False 與 1 True True 與 True 與 TypeError 正確答案 B. True False 與 True 與 TypeError 由於定義了__eq__,p == q會比較屬性x而得到True,但p與q是分別建立的不同物件,因此p is q仍是False。這裡的重點在於,定義了__eq__的類別,__hash__會自動被設為None,因此Point.__hash__ is None是True。沒有雜湊值的物件無法用作集合的元素或字典的鍵,因此試圖建立{p, q}時會發生TypeError。若也想放進集合,需要自行定義在相等時回傳相同值的__hash__。
第21題 | math
使用math模組的下列程式碼,其輸出是哪一項?
import math print(math.sqrt(16)) print(math.floor(-1.5), math.ceil(-1.5)) 4.0 與 -2 -1 4.0 與 -1 -2 4 與 -2 -1 4 與 -1 -1 正確答案 A. 4.0 與 -2 -1 math.sqrt即使能整除,也會回傳float,因此16的平方根會顯示為4.0而非4。math.floor會往數線下方捨去,因此-1.5會變成-2;math.ceil則往上方,因此-1.5會變成-1。要注意的是,對負數而言,朝0方向捨去的int(-1.5)會是-1,這與floor的結果不同。若把floor與ceil搞混,就會變成-1 -2的排列;若誤以為sqrt回傳值的型別是int,就會得到4。
第22題 | os.path
os.path.splitext('/tmp/z.txt') 與 os.path.basename('/tmp/z.txt') 回傳值的組合是哪一項?
('/tmp/z', '.txt') 與 'z.txt' ('/tmp', 'z.txt') 與 '/tmp' ('/tmp/z', 'txt') 與 'z.txt' ('/tmp/z.txt', '') 與 'z.txt' 正確答案 A. ('/tmp/z', '.txt') 與 'z.txt' os.path.splitext只會切出副檔名,並在保留句點在副檔名一側的情況下回傳2個元素的元組。因此會是 ('/tmp/z', '.txt')。句點不會被去掉變成'txt'。os.path.basename回傳的是路徑末尾的名稱,因此是'z.txt'。回傳目錄一側'/tmp'的是os.path.dirname,若想同時取得兩者彙整成的元組,要使用os.path.split。splitext是依副檔名而非目錄分隔符來切割,把角色區分清楚來記憶比較好。
第23題 | re的比對
使用re模組的下列程式碼,其輸出是哪一項?
import re print(re.match("b", "abc")) print(re.search("b", "abc").group()) print(re.findall(r"\d+", "a1b22c333")) b 與 None 與 ['1', '22', '333'] None 與 b 與 ['1', '22', '333'] b 與 b 與 ['1', '22', '333'] None 與 b 與 ['a1', 'b22', 'c333'] 正確答案 B. None 與 b 與 ['1', '22', '333'] re.match只會從字串開頭比對,'abc'的開頭是'a',與'b'不吻合,因此回傳None。re.search則會在中途搜尋,因此能吻合'b',用.group()就能取出吻合到的字串b。這個差異是re中最常被考的部分。re.findall會回傳把所有吻合該模式的部分蒐集起來的列表,\d+是連續的數字,因此結果是 ['1', '22', '333']。不會連分隔用的字元都包含在內。若沒有吻合,則回傳空列表。
第24題 | datetime
使用datetime的下列程式碼,其輸出是哪一項?
import datetime d = datetime.date(2026, 8, 22) print(d) print(d.strftime("%Y/%m/%d")) print(d + datetime.timedelta(days=10)) 2026/08/22 與 2026/08/22 與 2026/09/01 2026-08-22 與 2026/08/22 與 2026-09-01 2026-08-22 與 2026/08/22 與 10 days, 0:00:00 2026-08-22 與 2026/08/22 與 2026-08-32 正確答案 B. 2026-08-22 與 2026/08/22 與 2026-09-01 直接把date物件傳給print,會以ISO格式、連字號分隔顯示成2026-08-22。想改變格式時使用的是strftime,傳入'%Y/%m/%d'就會回傳斜線分隔的字串2026/08/22。對date加上timedelta(days=10),回傳的不是timedelta,而是指向10天後的新date,因此print顯示為2026-09-01。跨月的計算由datetime一方處理妥當,因此不會變成像2026-08-32這樣,只是把日期數字加10而得到的不存在日期。若以為print(d)會與strftime同樣的格式,就會排出斜線分隔的形式,但預設顯示是連字號分隔。日期相減時回傳的不是date而是timedelta,其顯示形式會像10 days, 0:00:00這樣。
第25題 | Counter
使用collections.Counter的下列程式碼,其輸出是哪一項?
from collections import Counter c = Counter("abracadabra") print(c.most_common(2)) print(c["a"], c["z"]) [('a', 5), ('b', 2)] 與 5 與 KeyError [('a', 5), ('r', 2)] 與 5 0 [('a', 5), ('b', 2)] 與 5 0 [('a', 5), ('b', 2), ('r', 2)] 與 5 0 正確答案 C. [('a', 5), ('b', 2)] 與 5 0 'abracadabra' 中a有5個,b與r各2個,c與d各1個。most_common(2)會依數量多寡回傳前2名,以元素與個數組成的元組列表,因此是 [('a', 5), ('b', 2)]。數量相同的b與r,先出現者會排在前面,因此採用b。Counter雖是字典的一種,但查詢不存在的元素不會發生KeyError,而是回傳0,這一點與一般字典不同。這樣的設計是為了不必先計數再確認是否存在。
第26題 | namedtuple
使用namedtuple所建立型別的下列程式碼,其輸出是哪一項?
from collections import namedtuple Pt = namedtuple("Pt", "x y") p = Pt(1, 2) print(p) print(p.x, p[0], isinstance(p, tuple)) (1, 2) 與 1 1 True Pt(x=1, y=2) 與 1 1 False Pt(x=1, y=2) 與 1 1 True Pt(1, 2) 與 1 1 False 正確答案 C. Pt(x=1, y=2) 與 1 1 True namedtuple所建立的型別,顯示時會呈現帶有型別名稱與欄位名稱的Pt(x=1, y=2)這種形式。值不論用名稱或索引都能讀取,因此p.x與p[0]都會是1。而且namedtuple是元組的衍生型別,因此isinstance(p, tuple)會是True。也就是說它是元組的一種,無法事後改寫元素。若想擁有可改寫的值,可以使用能建立替換值後新實例的_replace,或另外定義一般的類別。
第27題 | 用完即盡
把同一個map物件傳給list()兩次的下列程式碼,其輸出是哪一項?
m = map(str, [1, 2, 3]) print(list(m)) print(list(m)) 第1行是['1', '2', '3'],第2行是None 第1行是['1', '2', '3'],第2行是[] 第1行是[1, 2, 3],第2行是[] 第1行與第2行都是['1', '2', '3'] 正確答案 B. 第1行是['1', '2', '3'],第2行是[] map回傳的不是列表而是迭代器,每次next()只會傳出下一個值,用完就結束了。第1次的list()會把3個都取出,因此第2次的list()就沒有剩餘內容,結果是空列表。它不會出錯也不會變成None,而是悄悄變空,因此不容易察覺。map(str, ...) 會把各元素轉成字串,因此第1次的內容不是數值,而是['1', '2', '3']。同樣的情況在filter、zip、enumerate與生成器上也會發生,若要跑多次,最好在拿到後立刻用list()固定下來。
第28題 | filter與all
使用filter、all、any的下列程式碼,其輸出是哪一項?
print(list(filter(None, [0, 1, "", 2, None, "a"]))) print(all([]), any([])) [1, 2, 'a'] 與 False False [0, '', None] 與 True False [1, 2, 'a'] 與 True False [1, 2, 'a'] 與 False True 正確答案 C. [1, 2, 'a'] 與 True False 對filter的第1引數傳入None時,會依元素本身的真假來篩選。0、空字串、None會被判定為假因而被剔除,留下的是[1, 2, 'a']。並不是被剔除的那些留下來。all的規格是只要沒有任何一個假的元素就回傳True,因此在1個元素都沒有的空列表中會是True。any則是只要有1個以上真的元素就是True,因此空的話就是False。這2者在傳入空序列時會回傳相反答案的這一點,很容易被考。
第29題 | 生成器
呼叫含有yield之函式的下列程式碼中,輸出各行的順序是哪一項?
def gen(): print("start") yield 1 print("mid") yield 2 g = gen() print("created") print(next(g)) print(next(g)) 依 start mid created 1 2 的順序 依 created start mid 1 2 的順序 依 created start 1 mid 2 的順序 依 start created 1 mid 2 的順序 正確答案 C. 依 created start 1 mid 2 的順序 即使呼叫含有yield的函式,其主體也連1行都不會執行。回傳的只是一個生成器物件,因此created會先顯示。到了第1次的next(g),才終於從開頭開始動作,顯示start之後在yield 1處停下並回傳1。接下來的next(g)會從停下的地方接續,顯示mid之後在yield 2處停下並回傳2。這種延遲執行正是與一般函式決定性的差異,若再呼叫一次next(g),函式就會結束並發生StopIteration。
第30題 | is與==
並列is運算子與==運算子的下列程式碼,其輸出是哪一項?
a = [1, 2] b = [1, 2] c = a print(a == b, a is b) print(a == c, a is c) True False 與 True False True True 與 True True False False 與 True True True False 與 True True 正確答案 D. True False 與 True True ==是詢問值是否相等的運算子,由於a與b內容相同,因此是True。is則是詢問是否為同一個物件的運算子,a與b是分別建立的2個列表,因此是False。另一方面,c = a並沒有建立新列表,只是為同一個物件另取一個別名,因此a is c會是True。也就是說,透過c改寫該列表,從a來看也會看到變化。None是只存在1個的特殊物件,因此寫成 x is None 才是正確做法,但若想比較值,則應一律使用==。
練習:作答本頁的題目 這是隨機出題的練習工具(在啟用 JavaScript 時運作)。即使不使用此工具,也能閱讀上方的所有題目與解說。
※ 解說是供學習用的資訊。考試的出題範圍與制度每年可能變動,請務必確認主辦機構的官方公告。
本頁面譯自日文原文。若譯文與原文內容不一致,以日文版為準。 查看日文原文