ห้องเรียนรู้ Karinoya คุณวุฒิ แล็บสอบผ่าน Cloud / AI / Python โครงสร้างควบคุมและโครงสร้างข้อมูล
日本語 English Français Bahasa Indonesia 한국어 Română ไทย Tiếng Việt 简体中文 繁體中文
คุณวุฒิ · แล็บสอบผ่าน Cloud / AI / Python
โครงสร้างควบคุมและโครงสร้างข้อมูล อ่านโจทย์และคำอธิบายเป็นไทยได้ ส่วนบทบรรยาย (บทความอธิบาย) มีเฉพาะฉบับภาษาญี่ปุ่นเท่านั้น
ดูฉบับภาษาญี่ปุ่น (มีบทบรรยาย) →
ข้อ 1 | for/else
เมื่อรันโค้ดต่อไปนี้ที่ใส่ else ให้กับคำสั่ง for สิ่งที่แสดงผลคือข้อใด
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 ตามลำดับนี้ ส่วน else ที่ใส่ให้กับ for จะทำงานเมื่อลูปจบลงโดยไม่ถูก break เนื่องจากใน range(4) ไม่มี 9 อยู่ จึงไม่เกิด break เลย เมื่อวนลูปจนจบแล้ว print ของ else จะทำงานและแสดง done จากนั้น print(n) จะแสดงค่าสุดท้ายที่ยังเหลืออยู่ใน n ตอนที่ออกจากลูปคือ 3 หากสับสนลำดับการแสดงผลจะกลายเป็น 3 มาก่อน หากเข้าใจผิดว่า else จะถูกข้ามเสมอเมื่อลูปจบ จะกลายเป็นรูปแบบที่ไม่มี done หากมองข้ามว่า n ยังคงค้างอยู่แม้ออกจากลูปแล้ว จะกลายเป็นรูปแบบที่ไม่มี 3
ข้อ 2 | break และ else
ยืนยันว่า else จะถูกจัดการอย่างไรเมื่อออกจากลูปด้วย break โค้ดต่อไปนี้แสดงผลอย่างไร
for c in "abc": if c == "b": break print(c) else: print("no break") แสดง a b c และ no break ทั้งหมด แสดง a แล้วตามด้วย no break ตามลำดับนี้ แสดง a และ b รวม 2 รายการตามลำดับนี้ แสดง a และไม่แสดง no break คำตอบ D. แสดง a และไม่แสดง no break รอบที่ 1 c เป็น a ดังนั้น print(c) จึงทำงานและแสดง a รอบที่ 2 c เป็น b แล้ว break ตัดลูปทิ้ง ตามกฎที่ว่าส่วน else ของ for จะทำงานเฉพาะเมื่อจบลูปโดยไม่ถูก break จึงถูกข้ามในที่นี้ และไม่แสดง no break หากเข้าใจผิดว่า else จะทำงานเสมอเมื่อลูปจบ จะกลายเป็นรูปแบบที่แสดง no break ด้วย หากอ่านผิดว่า print(c) อยู่ก่อน break จะกลายเป็นรูปแบบที่แสดง b ด้วย หากมองข้าม break เอง จะกลายเป็นรูปแบบที่แสดง a b c ทั้งหมด
ข้อ 3 | แม้ว่าง else ก็ทำงาน
ตรวจสอบว่าส่วน else ของ for จะเป็นอย่างไรเมื่อสิ่งที่วนซ้ำว่างเปล่า ผลการรันโค้ดต่อไปนี้คือข้อใด
items = [] for it in items: print(it) else: print("finished") ส่วน else ถูกละเว้นและเกิด TypeError เนื่องจากวนซ้ำ 0 ครั้ง จึงเกิด StopIteration ไม่แสดงอะไรเลยแล้วออกจากลูปจบการทำงาน แสดง finished เพียง 1 ครั้ง คำตอบ D. แสดง finished เพียง 1 ครั้ง เงื่อนไขที่ส่วน else ของ for จะทำงานคือ “ลูปจบลงโดยไม่ถูก break” ไม่ใช่ “วนซ้ำอย่างน้อย 1 ครั้ง” เนื่องจาก items ว่างเปล่า ตัวเนื้อหาของลูปจึงไม่ทำงานเลยแม้แต่ครั้งเดียว แต่เนื่องจากไม่ได้ break เช่นกัน else จึงทำงานตามปกติและแสดง finished หากคิดว่าถ้าว่างเปล่าแล้ว else จะถูกข้ามด้วย จะกลายเป็นรูปแบบที่ไม่แสดงอะไรเลย การส่งลิสต์ว่างให้กับ for เองเป็นวิธีเขียนที่ถูกต้อง จึงไม่เกิดข้อยกเว้น ทั้ง TypeError และ StopIteration จะไม่ถูกส่งออกมา
ข้อ 4 | while/else
พิจารณากรณีที่ใส่ else ให้กับคำสั่ง while แล้ว 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 จะลดลงทีละ 1 จาก 5 ไปเป็น 4, 3 แล้วเมื่อถึง 2 จะ break ส่วน else ของ while ก็เช่นเดียวกับ for คือจะทำงานเฉพาะเมื่อจบลงโดยไม่ถูก break เท่านั้น ในที่นี้จึงถูกข้าม และไม่แสดง loop ended สิ่งที่เหลืออยู่มีเพียง 2 จาก print(n) หากคิดว่า 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 ทั้ง 2 อันไปได้แล้วถูก 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 ในที่นี้จะลบทีละ 3 จาก 10 ได้ 10, 7, 4, 1 ตามลำดับ และค่าถัดไปคือ -2 ซึ่งต่ำกว่าหรือเท่ากับ 0 จึงไม่ถูกนำมาใช้ เนื่องจากไม่รวม stop คือ 0 จึงไม่กลายเป็นรูปแบบที่มี 0 อยู่ท้ายสุด หากเข้าใจผิดว่าไม่รวม start จะกลายเป็นรูปแบบที่เริ่มจาก 7 หากคิดว่าเริ่มนับจากก่อน start 1 ค่า จะกลายเป็นรูปแบบที่เริ่มจาก 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
ข้อใดอธิบายคำสั่ง pass ของ Python ได้อย่างเหมาะสม
แสดงว่าตัดลูปทิ้งแล้วออกไปด้านนอก แสดงว่าไม่ทำอะไรเลยในจุดที่ไวยากรณ์กำหนดให้ต้องมีบล็อก แสดงว่าข้ามส่วนที่เหลือของลูปแล้วไปยังการวนซ้ำครั้งถัดไป แสดงว่าจบการทำงานของฟังก์ชันแล้วคืนค่ากลับไปยังผู้เรียก คำตอบ B. แสดงว่าไม่ทำอะไรเลยในจุดที่ไวยากรณ์กำหนดให้ต้องมีบล็อก เนื่องจาก Python แสดงบล็อกด้วยการเว้นวรรค จึงไม่สามารถเขียนบล็อกว่างเปล่าได้ pass ใช้เติมเต็มตำแหน่งนั้นในกรณีที่ตั้งใจจะเขียนเนื้อหาของคลาสหรือฟังก์ชันในภายหลัง หรือในกรณีที่ตรงตามเงื่อนไขแล้วตั้งใจไม่ทำอะไรเลย ไม่มีผลต่อการเปลี่ยนทิศทางการทำงาน การไปยังการวนซ้ำครั้งถัดไปคือ continue การตัดลูปทิ้งคือ break และการคืนค่ากลับไปยังผู้เรียกคือ return ซึ่งทั้งหมดนี้มีบทบาทต่างจาก pass
ข้อ 11 | enumerate
เมื่อรันโค้ดต่อไปนี้ที่ส่งอาร์กิวเมนต์ตัวที่ 2 ให้กับ enumerate สิ่งที่ปรากฏบนหน้าจอคือข้อใด
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
ส่ง 2 ลิสต์ที่มีความยาวต่างกันให้กับ 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 ของแต่ละคู่จะถูกรวมกัน แยกออกเป็น 2 ชุดคือ (1, 2, 3) และ ('a', 'b', 'c') นี่เป็นวิธีมาตรฐานในการแยกข้อมูลที่จับคู่แล้วกลับไปเป็น 2 ชุดเดิม หากส่งผ่าน zip 2 ครั้งจะกลับไปเป็นรูปเดิม สิ่งที่คืนค่าไม่ใช่ลิสต์แต่เป็นทูเพิล จึงไม่ได้อยู่ในรูปวงเล็บเหลี่ยม หากลืมใส่เครื่องหมายดอกจันแล้วเขียนเป็น zip(pairs) คู่นั้นเองจะถูกส่งเป็นอาร์กิวเมนต์เดียว กลายเป็นทูเพิลที่มี 1 องค์ประกอบเรียงกันแบบ ((1, 'a'),)
ข้อ 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 | List Comprehension
เมื่อรันโค้ดต่อไปนี้ที่ใช้ List Comprehension ลิสต์ที่แสดงผลคือข้อใด
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 ไม่รวม 5 ที่ระบุไว้เป็น stop เมื่อยกกำลังสองแต่ละค่าจะได้ 1, 4, 9, 16 หากเข้าใจผิดว่า range เริ่มจาก 0 จะกลายเป็นรูปแบบที่เรียงเริ่มจาก 0 หากเข้าใจผิดว่ารวม stop จะกลายเป็นรูปแบบที่เรียงไปจนถึง 25 หากอ่าน n * n ผิดเป็น n * 2 จะกลายเป็นรูปแบบที่เพิ่มทีละ 2 ควรฝึกอ่าน Comprehension ว่าเป็นการประเมินนิพจน์ทางซ้ายสุดกับแต่ละองค์ประกอบ แล้วสร้างลิสต์ใหม่จากผลลัพธ์ที่เรียงกัน
ข้อ 16 | Dict Comprehension
รันการเขียนแบบ Comprehension ที่ใส่โคลอนไว้ในวงเล็บปีกกา โค้ดต่อไปนี้ให้ผลลัพธ์ใด
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} การเขียนแบบ Comprehension ที่มีโคลอนอยู่ในวงเล็บปีกกาคือ Dict Comprehension ด้านซ้ายของโคลอนจะเป็นคีย์ ด้านขวาจะเป็นค่า ในที่นี้จะได้พจนานุกรมที่มีคำเป็นคีย์และจำนวนตัวอักษรของคำนั้นเป็นค่า หากอ่านคีย์กับค่าสลับกัน จะกลายเป็นรูปแบบที่จำนวนตัวอักษรเป็นคีย์ หากล้อมด้วยวงเล็บเหลี่ยมจะกลายเป็นลิสต์ของทูเพิล แต่ในที่นี้ใช้วงเล็บปีกกาจึงไม่เป็นเช่นนั้น หากไม่มีโคลอนจะกลายเป็น Set Comprehension ซึ่งแสดงผลเป็นเพียงค่าเรียงกัน แต่เมื่อมีโคลอนอยู่ สิ่งที่ได้จึงต้องเป็นพจนานุกรม
ข้อ 17 | ชนิดของวงเล็บกลม
ล้อมนิพจน์ที่คล้าย Comprehension ไว้ด้วยวงเล็บกลม เมื่อรันโค้ดต่อไปนี้ ชนิดที่แสดงผลคือข้อใด
g = (n for n in range(3)) print(type(g)) <class 'range'> <class 'list'> <class 'generator'> <class 'tuple'> คำตอบ C. <class 'generator'> Python ไม่มีวิธีเขียนที่เรียกว่า Tuple Comprehension รูปแบบที่ล้อมด้วยวงเล็บกลมนี้จะกลายเป็น Generator Expression ชนิดคือ generator ซึ่งจะไม่สร้างค่าทั้งหมดไว้ล่วงหน้า แต่จะคำนวณทีละค่าเมื่อถูกเรียกใช้ จึงประหยัดหน่วยความจำ แต่เนื่องจากเป็น Iterator เมื่อใช้ครั้งเดียวแล้วจะหมดไป หากต้องการทูเพิลต้องห่อด้วย tuple() หากเขียนด้วยวงเล็บเหลี่ยมจะกลายเป็น List Comprehension ได้ชนิด list หากกำหนดค่า range(3) ตรง ๆ จะได้ range ชนิด tuple ไม่สามารถได้จากวิธีเขียนนี้
ข้อ 18 | Set Comprehension
นับจำนวนองค์ประกอบของภาชนะที่สร้างด้วย Set Comprehension โค้ดต่อไปนี้ให้ผลลัพธ์ใด
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 การเขียนแบบ Comprehension ที่มีวงเล็บปีกกาแต่ไม่มีโคลอนคือ Set Comprehension ค่าที่ซ้ำกันจะถูกรวมเป็นค่าเดียว เหลือเพียง 4 ชนิดคือ 0, 1, 2, 3 หากมองข้ามว่าค่าที่ซ้ำกันจะหายไป แล้วนับจำนวนค่าตามเดิมจะได้ 10 หากมองข้ามว่ามี 0 รวมอยู่ในเศษด้วย แล้วนับเป็น 3 ชนิดคือ 1, 2, 3 จะได้ 3 ค่า 0 คือค่าที่ได้เมื่อเข้าใจผิดว่า Comprehension ไม่สร้างอะไรขึ้นมาเลย แต่ตราบใดที่วนซ้ำ range(10) เนื้อหาจะไม่ว่างเปล่าอย่างแน่นอน เนื่องจากลำดับการแสดงผลของเซตไม่แน่นอน การยืนยันด้วยจำนวนองค์ประกอบจึงเป็นวิธีที่แน่นอนกว่า
ข้อ 19 | Comprehension ซ้อนสองชั้น
ตรวจสอบลำดับการเรียงของ Comprehension ที่มี for วางเรียงกัน 2 อัน ผลการรันโค้ดต่อไปนี้คือข้อใด
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 2 อันเรียงกันใน Comprehension for ที่เขียนไว้ทางซ้ายจะเป็นลูปวงนอก ลำดับจะเหมือนกับการเขียน for ปกติซ้อนกันทุกประการ คือตรึง x เป็น 1 แล้ววน y เป็น a, b จากนั้นเปลี่ยน x เป็น 2 แล้วทำซ้ำแบบเดียวกัน หากอ่านผิดว่า for ทางขวาเป็นวงนอก จะกลายเป็นลำดับที่ x วนก่อน เนื้อหาของคู่จะเรียงตามที่เขียนไว้ในนิพจน์ (x, y) จึงไม่มีทางที่ตัวอักษรจะมาก่อน
ข้อ 20 | อาร์กิวเมนต์ start
ข้อใดอธิบายอาร์กิวเมนต์ตัวที่ 2 คือ start ของฟังก์ชันในตัว enumerate ได้อย่างเหมาะสม
ระบุหมายเลขที่จะเริ่มนับ หากละไว้จะนับจาก 0 ระบุว่าจะดึงองค์ประกอบจากตัวไหน หากละไว้จะดึงจากตัวแรก ระบุว่าจะข้ามไปกี่ตัว หากละไว้จะเดินหน้าทีละ 1 ตัว ระบุว่านับไปจนถึงตัวที่เท่าไร หากละไว้จะนับจนถึงตัวสุดท้าย คำตอบ A. ระบุหมายเลขที่จะเริ่มนับ หากละไว้จะนับจาก 0 อาร์กิวเมนต์ตัวที่ 2 ของ enumerate คือ start จะกำหนดเพียงว่าจะเริ่มใส่หมายเลขจากค่าใดเท่านั้น ค่าเริ่มต้นคือ 0 หากส่งค่า 1 เข้าไปจะได้หมายเลขลำดับแบบที่มนุษย์คุ้นเคย จุดสำคัญคือมีเพียงวิธีใส่หมายเลขที่เปลี่ยนไปเท่านั้น ขอบเขตหรือจำนวนขององค์ประกอบที่ถูกดึงออกมาจะไม่เปลี่ยนแปลง ไม่มีหน้าที่จำกัดจำนวนหรือข้ามตัว และไม่ได้เลื่อนตำแหน่งเริ่มต้นของการดึงออกมา ทั้งหมดนี้เป็นคำอธิบายของเครื่องมืออื่น เช่นการแบ่งส่วน (slice)
ข้อ 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
เปรียบเทียบ 2 วิธีในการเพิ่มลิสต์อีกตัวเข้าไปในลิสต์ โปรแกรมต่อไปนี้ให้ผลลัพธ์ใด
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 | การคัดลอกแบบตื้น
คัดลอกลิสต์ที่ซ้อนกันด้วยการแบ่งส่วน (slice) แล้วเขียนทับข้างใน ผลการรันโปรแกรมต่อไปนี้คือข้อใด
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]] การคัดลอกด้วยการแบ่งส่วน (slice) เป็นการคัดลอกแบบตื้น ลิสต์ชั้นนอกจะถูกสร้างขึ้นใหม่ แต่องค์ประกอบที่อยู่ข้างในจะใช้ร่วมกับต้นฉบับ 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 ด้วย ดังนั้นจึงมีเพียงองค์ประกอบตัวหลังเท่านั้นที่ยืดออก หากคิดว่าทั้งสองส่งผลถึงกัน จะกลายเป็นรูปแบบที่องค์ประกอบด้านในทั้งสองยืดออก หากคิดว่าทั้งสองไม่ส่งผลถึงกันเลย จะกลายเป็นรูปแบบเดิม หากสลับการคัดลอกแบบลึกกับแบบตื้น จะกลายเป็นรูปแบบที่มีเพียงองค์ประกอบตัวหน้ายืดออก
ข้อ 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]] การคูณชั้นนอกไม่ได้สร้างแถวใหม่ แต่เพียงเรียงการอ้างอิงไปยังลิสต์เดียวกันซ้ำ 2 ครั้ง 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] เป็นลิสต์ ตัวลิสต์เองเปลี่ยนแปลงได้ (Mutable) จึงสามารถ append ได้ หากเขียนแทนที่ตัวองค์ประกอบของทูเพิลโดยตรงอย่าง t[1] = [] จะเกิด TypeError แต่ในที่นี้ไม่ได้แทนที่องค์ประกอบ เนื่องจากสิ่งที่เพิ่มเข้าไปอยู่ข้างในลิสต์ จึงไม่มีทางที่ความยาวของทูเพิลจะเพิ่มขึ้น และก็ไม่มีทางที่จะไม่เปลี่ยนแปลงเลยเช่นกัน
ข้อ 29 | การกำหนดค่าให้ Slice
กำหนดลิสต์ที่มีความยาวต่างกันให้กับการแบ่งส่วน (slice) ของลิสต์ โปรแกรมต่อไปนี้ให้ผลลัพธ์ใด
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] การกำหนดค่าให้กับ slice คือการดำเนินการที่แทนที่ช่วงที่ระบุทั้งหมดด้วยเนื้อหาของฝั่งขวา x[1:3] ชี้ไปที่องค์ประกอบ 2 ตัวคือ 2 กับ 3 จึงถูกแทนที่ด้วยองค์ประกอบ 1 ตัวคือ 9 ความยาวทั้งหมดจึงลดจาก 5 เหลือ 4 หากคิดว่ามีเพียง 1 องค์ประกอบถูกแทนที่ จะกลายเป็นรูปแบบที่ความยาวยังคงเป็น 5 หากคิดว่าฝั่งขวาจะถูกยืดให้พอดีกับความกว้าง จะกลายเป็นรูปแบบที่มี 9 เรียงกัน 2 ตัว หากอ่านจุดเริ่มต้นของช่วงเลื่อนไป 1 ตำแหน่ง จะกลายเป็นรูปแบบที่ 2 ยังคงเหลืออยู่ ลักษณะเฉพาะของการกำหนดค่าให้ slice คือความกว้างของฝั่งซ้ายกับความยาวของฝั่งขวาไม่จำเป็นต้องเท่ากัน
ข้อ 30 | การแทรกและการลบ
ทำการกำหนดค่าให้กับ slice ที่มีความกว้าง 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] หากอ่านผิดว่าตอนแทรกองค์ประกอบเดิมจะหายไป 1 ตัวด้วย จะกลายเป็นรูปแบบ 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 ตามลำดับนี้ จุดแรกเกิด KeyError แสดง None แล้วตามด้วย None ตามลำดับนี้ แสดง 0 แล้วตามด้วย 0 ตามลำดับนี้ คำตอบ A. แสดง None แล้วตามด้วย 0 ตามลำดับนี้ get จะไม่ส่งข้อยกเว้นเมื่อไม่มีคีย์ หากละอาร์กิวเมนต์ตัวที่ 2 ไว้จะคืนค่า None หากส่งเข้าไปจะคืนค่านั้น ดังนั้นจุดแรกจึงเป็น None จุดที่สองจึงเป็น 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 ที่มีอยู่เดิมและพจนานุกรมยังคงเดิม ครั้งที่สองจะแทรก 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 | คีย์ที่ซ้ำกัน
เขียนคีย์เดียวกันซ้ำ 2 ครั้งใน literal ของพจนานุกรม ผลการรันโปรแกรมต่อไปนี้คือข้อใด
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} literal ของพจนานุกรมจะสร้างรายการเรียงจากซ้ายไปขวาตามลำดับ ดังนั้นเมื่อคีย์เดียวกันปรากฏ 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() เมื่อรันโปรแกรมต่อไปนี้ ชื่อชนิดทั้ง 2 ที่แสดงคือข้อใด
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 | การดำเนินการของเซต
ทำการดำเนินการอินเตอร์เซกชันและผลต่างสมมาตรกับ 2 เซต โปรแกรมต่อไปนี้ให้ผลลัพธ์ใด
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 ที่มีอยู่ในทั้งสองฝั่ง เครื่องหมายแฮตคือผลต่างสมมาตร จะรวบรวมองค์ประกอบที่มีอยู่ในฝั่งใดฝั่งหนึ่งเท่านั้น ดังนั้นจะเหลือ 1 กับ 2 ที่มีเฉพาะใน s1 และ 5 ที่มีเฉพาะใน s2 ส่วน 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 ค่าที่ซ้ำจะถูกกำจัดออก เหลือค่าที่แตกต่างกัน 3 ชนิดคือ 1, 2, 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 เนื่องจากลิสต์ใส่เข้าไปในเซตไม่ได้ องค์ประกอบของเซตและคีย์ของพจนานุกรมต้องเป็นชนิดที่แฮชได้ ทูเพิลไม่สามารถเปลี่ยนเนื้อหาได้จึงแฮชได้และเพิ่มเข้าไปได้ แต่ลิสต์เปลี่ยนเนื้อหาได้ในภายหลังจึงแฮชไม่ได้ จะเกิด TypeError พร้อมข้อความ unhashable type หากคิดว่าทั้งคู่เพิ่มเข้าไปได้ จะกลายเป็นแสดง 2 หากคิดว่าถูกแปลงเป็นทูเพิลโดยอัตโนมัติ จะกลายเป็นแสดง 1 การที่ชนิดปะปนกันเองไม่ใช่ปัญหา ดังนั้นเหตุผลที่ว่าจะเกิด ValueError ก็ผิดเช่นกัน
ข้อ 40 | การดึง 3 แบบ
ข้อใดคือชุดค่าผสมที่เหมาะสมว่าเมธอด 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() ที่รับด้วยตัวแปร 2 ตัว หากจำสลับบทบาทของทั้ง 3 อย่าง จะกลายเป็นคำอธิบายที่ keys คืนค่า สิ่งที่ items คืนคือลำดับของรายการ ไม่ใช่จำนวน ดังนั้นคำอธิบายที่ว่าคืนจำนวนรายการก็ผิดเช่นกัน หากต้องการทราบจำนวนให้ใช้ len นอกจากนี้ หากส่งพจนานุกรมให้ for โดยตรงจะดึงคีย์ออกมา
ฝึกทำ: ทำโจทย์ในหน้านี้ เครื่องมือฝึกทำโจทย์แบบสุ่มคำถาม (ทำงานเมื่อเปิดใช้ JavaScript) โจทย์และคำอธิบายด้านบนสามารถอ่านได้ทั้งหมดตามปกติ
※ คำอธิบายเป็นข้อมูลเพื่อการเรียนรู้ ขอบเขตข้อสอบและระบบการสอบอาจเปลี่ยนแปลงในแต่ละปี โปรดตรวจสอบประกาศอย่างเป็นทางการของหน่วยงานผู้จัดสอบเสมอ
หน้านี้แปลจากต้นฉบับภาษาญี่ปุ่น หากเนื้อหาของคำแปลและต้นฉบับไม่ตรงกัน ให้ถือฉบับภาษาญี่ปุ่นเป็นหลัก ดูต้นฉบับภาษาญี่ปุ่น