Phòng học Karinoya

Chứng chỉ · Lab luyện thi Cloud / AI / Python

Cấu trúc điều khiển và cấu trúc dữ liệu

Bạn có thể đọc câu hỏi và lời giải bằng Tiếng Việt. Bài giảng (bài viết giải thích) chỉ có bản tiếng Nhật.

Xem bản tiếng Nhật (có bài giảng) →

Câu 1 | for/else

Khi thực thi đoạn mã sau, gắn mệnh đề else vào câu lệnh for, nội dung nào được hiển thị?

for n in range(4):    if n == 9:        breakelse:    print("done")print(n)
  1. Chỉ hiển thị 3, không hiển thị done
  2. Chỉ hiển thị done, không hiển thị 3
  3. Hiển thị 3 rồi done theo thứ tự đó
  4. Hiển thị done rồi 3 theo thứ tự đó
Đáp ánD. Hiển thị done rồi 3 theo thứ tự đó

Mệnh đề else gắn vào for sẽ được thực thi khi vòng lặp kết thúc mà không bị break. Vì range(4) không chứa 9 nên break không bao giờ xảy ra, vòng lặp chạy hết rồi mệnh đề else mới chạy, hiển thị done. Sau đó print(n) hiển thị giá trị cuối cùng còn lại trong n tại thời điểm thoát khỏi vòng lặp, tức là 3. Nếu hiểu nhầm thứ tự hiển thị thì sẽ ra dạng 3 hiển thị trước; nếu hiểu nhầm rằng else luôn bị bỏ qua khi vòng lặp kết thúc thì sẽ ra dạng không hiển thị done; nếu bỏ sót việc n vẫn còn giá trị sau khi thoát vòng lặp thì sẽ ra dạng không hiển thị 3.

Câu 2 | break và else

Xác nhận cách xử lý mệnh đề else khi thoát vòng lặp bằng break. Kết quả hiển thị của đoạn mã sau là gì?

for c in "abc":    if c == "b":        break    print(c)else:    print("no break")
  1. Hiển thị đủ a b c rồi no break
  2. Hiển thị a rồi no break theo thứ tự đó
  3. Hiển thị 2 giá trị a và b theo thứ tự đó
  4. Hiển thị a, không hiển thị no break
Đáp ánD. Hiển thị a, không hiển thị no break

Ở vòng lặp thứ 1, c là a nên print(c) chạy và hiển thị a. Ở vòng lặp thứ 2, c trở thành b và break cắt đứt vòng lặp. Mệnh đề else của for chỉ được thực thi khi vòng lặp kết thúc mà không bị break, nên ở đây bị bỏ qua và no break không được hiển thị. Nếu nghĩ rằng else luôn chạy khi vòng lặp kết thúc thì sẽ ra dạng hiển thị cả no break; nếu hiểu nhầm rằng print(c) nằm trước break thì sẽ ra dạng hiển thị cả b. Nếu bỏ sót bản thân break thì sẽ ra dạng hiển thị đủ a b c.

Câu 3 | else dù rỗng

Xét trường hợp đối tượng lặp là rỗng, hỏi mệnh đề else của for sẽ ra sao. Kết quả thực thi của đoạn mã sau là gì?

items = []for it in items:    print(it)else:    print("finished")
  1. Mệnh đề else bị bỏ qua và xảy ra TypeError
  2. Vì lặp 0 lần nên xảy ra StopIteration
  3. Không hiển thị gì và thoát khỏi vòng lặp
  4. finished được hiển thị đúng 1 lần
Đáp ánD. finished được hiển thị đúng 1 lần

Điều kiện để mệnh đề else của for được thực thi là "vòng lặp kết thúc mà không bị break", chứ không phải "đã lặp ít nhất 1 lần". Vì items rỗng nên phần thân không chạy lần nào, nhưng cũng không có break, nên else vẫn được thực thi bình thường và finished được hiển thị. Nếu nghĩ rằng khi rỗng thì else cũng bị bỏ qua sẽ ra dạng không hiển thị gì. Việc truyền một danh sách rỗng cho for tự nó là cách viết hợp lệ nên không gây ra ngoại lệ, cũng không phát sinh TypeError hay StopIteration.

Câu 4 | while/else

Gắn mệnh đề else vào câu lệnh while, xét trường hợp thoát vòng lặp giữa chừng bằng break. Kết quả hiển thị của đoạn mã sau là gì?

n = 5while n > 0:    n -= 1    if n == 2:        breakelse:    print("loop ended")print(n)
  1. Hiển thị 0, không hiển thị loop ended
  2. Hiển thị 2, không hiển thị loop ended
  3. Hiển thị loop ended rồi 2 theo thứ tự đó
  4. Hiển thị loop ended rồi 0 theo thứ tự đó
Đáp ánB. Hiển thị 2, không hiển thị loop ended

n giảm dần 1 đơn vị từ 5, qua 4, 3 rồi đến khi thành 2 thì break. Mệnh đề else của while cũng giống như for, chỉ được thực thi khi vòng lặp kết thúc mà không bị break, nên ở đây bị bỏ qua và loop ended không được hiển thị. Còn lại chỉ có 2 từ print(n). Nếu nghĩ rằng else luôn chạy sẽ ra dạng hiển thị cả loop ended; nếu bỏ sót break và hiểu nhầm rằng vòng lặp chạy đến khi điều kiện trở thành sai thì n sẽ ra dạng bằng 0.

Câu 5 | continue

Khi thực thi đoạn mã sau, trộn continue và break vào cùng một vòng lặp, danh sách nào được hiển thị cuối cùng?

out = []for i in range(6):    if i == 3:        continue    if i == 5:        break    out.append(i)print(out)
  1. [0, 1, 2, 4, 5]
  2. [0, 1, 2, 3]
  3. [0, 1, 2, 4]
  4. [0, 1, 2, 3, 4]
Đáp ánC. [0, 1, 2, 4]

Khi i là 0, 1, 2 thì cả hai lệnh if đều được vượt qua và append được thực hiện. Khi i là 3, continue hoạt động, phần còn lại của vòng đó, tức là append, bị bỏ qua. Khi i là 4 thì append lại được thực hiện, và khi i là 5 thì break cắt đứt vòng lặp nên append không được thực hiện. Do đó kết quả là [0, 1, 2, 4]. Nếu nghĩ rằng vòng có break cũng được thêm vào thì sẽ ra dạng có cả 5; nếu xử lý continue giống như pass thì sẽ ra dạng còn cả 3.

Câu 6 | range theo chiều ngược

Xét trường hợp truyền bước nhảy âm cho range. Kết quả hiển thị của đoạn mã sau là gì?

print(list(range(10, 0, -3)))
  1. [9, 6, 3, 0]
  2. [7, 4, 1, -2]
  3. [10, 7, 4, 1, 0]
  4. [10, 7, 4, 1]
Đáp ánD. [10, 7, 4, 1]

range(start, stop, step) bắt đầu từ start, tiến từng bước step, và dừng lại trước khi đạt đến stop. Ở đây bắt đầu từ 10, trừ dần 3 nên tiến theo thứ tự 10, 7, 4, 1, và giá trị tiếp theo là -2 vốn nhỏ hơn hoặc bằng 0 nên không được nhận. Vì stop là 0 không được bao gồm, nên không có chuyện 0 nằm ở cuối dãy. Nếu hiểu nhầm rằng start không được bao gồm thì sẽ ra dạng bắt đầu từ 7; nếu hiểu nhầm rằng đếm lùi một bước trước start thì sẽ ra dạng bắt đầu từ 9. Điểm stop không được bao gồm cũng giống như khi bước nhảy dương.

Câu 7 | Kiểu của range

Đâu là mô tả phù hợp về đối tượng nhận được khi gọi hàm dựng sẵn range?

  1. Là đối tượng kiểu generator, sau khi lặp một lần thì trở nên rỗng
  2. Là đối tượng kiểu range, khi truyền vào list() sẽ trở thành danh sách
  3. Là đối tượng kiểu tuple, không thể thay thế phần tử
  4. Là đối tượng kiểu list, được hiển thị trực tiếp dưới dạng có dấu ngoặc vuông
Đáp ánB. Là đối tượng kiểu range, khi truyền vào list() sẽ trở thành danh sách

range trả về là một đối tượng kiểu range, tính toán số nguyên cần thiết mỗi khi được yêu cầu rồi trả về. Vì không giữ sẵn toàn bộ phần tử như danh sách nên không tốn nhiều bộ nhớ dù phạm vi lớn. Khi muốn xếp ra để kiểm tra nội dung, cần truyền qua list(). type(range(3)) là range, không phải list hay tuple, và khi hiển thị trực tiếp cũng không ra dạng liệt kê phần tử mà ra range(0, 3). Ngoài ra, vì không phải dùng một lần là hết mà có thể lặp lại bao nhiêu lần cũng được, nên cũng không phải là generator. Lưu ý điểm có thể đọc bằng chỉ số và không thể thay thế phần tử thì giống với tuple, nên chỉ dựa vào tính chất đó thì không thể phân biệt với tuple.

Câu 8 | Đánh giá ngắn mạch

Xác nhận toán tử logic or và and trả về giá trị gì. Kết quả hiển thị của đoạn mã sau là gì?

print([] or 0 or "z")print(1 and 0 and 2)
  1. Hiển thị True rồi False theo thứ tự đó
  2. Hiển thị False rồi 0 theo thứ tự đó
  3. Hiển thị z rồi 0 theo thứ tự đó
  4. Hiển thị z rồi 2 theo thứ tự đó
Đáp ánC. Hiển thị z rồi 0 theo thứ tự đó

or đánh giá từ trái sang phải và trả về giá trị đầu tiên trở thành đúng (truthy). Vì danh sách rỗng và 0 đều là giá trị sai (falsy), nên "z" ở cuối cùng được trả về. and thì ngược lại, trả về giá trị đầu tiên trở thành sai; 1 là đúng, nhưng đến 0 tiếp theo thì xác định là sai nên 0 được trả về, còn 2 ở bên phải cùng không được đánh giá. Vì giá trị trả về không phải là true/false mà là giá trị tại thời điểm dừng đánh giá, nên không thể ra True hay False. and chỉ trả về 2 ở đầu phải khi tất cả các phần ở giữa đều đúng.

Câu 9 | So sánh chuỗi

Khi kết hợp so sánh chuỗi (chained comparison) với toán tử ba ngôi, thực thi đoạn mã sau, nội dung nào được hiển thị?

x = 3print(1 < x < 5)print("yes" if x % 2 else "no")
  1. Hiển thị True rồi yes theo thứ tự đó
  2. Hiển thị True rồi no theo thứ tự đó
  3. Hiển thị False rồi no theo thứ tự đó
  4. Hiển thị False rồi yes theo thứ tự đó
Đáp ánA. Hiển thị True rồi yes theo thứ tự đó

1 < x < 5 có ý nghĩa giống (1 < x) and (x < 5); nếu x là 3 thì cả hai vế đều đúng nên kết quả là True. Toán tử ba ngôi có dạng giá trị khi đúng if điều kiện else giá trị khi sai, và điều kiện ở đây là x % 2, tức là 1. Trong Python, số nguyên khác 0 được xem là đúng (truthy), nên yes được chọn. Nếu hiểu nhầm so sánh chuỗi kết hợp theo hướng từ sau ra trước như 1 < (x < 5), thì x < 5 sẽ là True tức 1, và 1 < 1 cho ra False, dẫn đến đáp án sai. Ngoài ra nếu nghĩ 1 là sai (falsy) thì sẽ chọn nhầm no.

Câu 10 | Vai trò của pass

Đâu là mô tả phù hợp về câu lệnh pass trong Python?

  1. Biểu thị việc cắt đứt hẳn vòng lặp để thoát ra ngoài
  2. Biểu thị việc không làm gì cả, tại nơi cú pháp yêu cầu phải có một khối lệnh
  3. Biểu thị việc bỏ qua phần còn lại của vòng lặp để tiến sang lần lặp kế tiếp
  4. Biểu thị việc kết thúc thực thi hàm rồi trả về giá trị cho nơi gọi
Đáp ánB. Biểu thị việc không làm gì cả, tại nơi cú pháp yêu cầu phải có một khối lệnh

Vì Python biểu diễn khối lệnh bằng thụt lề nên không thể viết một khối lệnh rỗng. Khi định để nội dung của lớp hay hàm viết sau, hoặc khi cố ý không làm gì khi thỏa điều kiện, pass được dùng để lấp vào vị trí đó. Nó không có tác dụng thay đổi luồng xử lý. Việc tiến sang lần lặp kế tiếp là continue, việc cắt đứt vòng lặp là break, việc trả về giá trị cho nơi gọi là return; cả ba đều có vai trò khác với pass.

Câu 11 | enumerate

Khi truyền đối số thứ hai cho enumerate rồi thực thi đoạn mã sau, điều gì hiện ra trên màn hình?

for i, name in enumerate(["gu", "choki", "pa"], 1):    print(i, name)
  1. Hiển thị 3 dòng 1 gu / 2 choki / 3 pa
  2. Hiển thị 3 dòng 0 gu / 1 choki / 2 pa
  3. Hiển thị 3 dòng gu 1 / choki 2 / pa 3
  4. Chỉ hiển thị 2 dòng 1 gu / 2 choki
Đáp ánA. Hiển thị 3 dòng 1 gu / 2 choki / 3 pa

enumerate lần lượt trả về tuple (số thứ tự, phần tử), và có thể chỉ định giá trị bắt đầu đếm bằng đối số thứ hai start. Ở đây đã truyền 1 nên số thứ tự sẽ là 1, 2, 3. Nếu nhầm lẫn với việc bắt đầu từ 0 khi bỏ qua start thì sẽ ra dạng bắt đầu từ 0. Vì tuple trả về có số thứ tự đứng trước và phần tử đứng sau, nên thứ tự trong print(i, name) cũng theo đúng thứ tự đó, không có chuyện tên đứng trước. Cả 3 phần tử đều được lấy ra nên không dừng lại ở 2 dòng.

Câu 12 | Độ dài của zip

Truyền 2 danh sách có độ dài khác nhau cho zip. Kết quả thực thi của đoạn mã sau là gì?

print(list(zip([1, 2, 3], [10, 20])))
  1. [(1, 10), (2, 20)]
  2. [(1, 10), (2, 20), (3,)]
  3. [(1, 10), (2, 20), (3, 0)]
  4. [(10, 1), (20, 2)]
Đáp ánA. [(1, 10), (2, 20)]

zip lấy từng phần tử từ các đối tượng khả lặp được truyền vào để ghép thành cặp, và kết thúc ngay khi đối tượng ngắn nhất hết phần tử. Ở đây danh sách thứ hai chỉ có 2 phần tử nên chỉ tạo được 2 cặp, phần tử dư ra là 3 sẽ bị bỏ qua một cách âm thầm. Không xảy ra lỗi, cũng không có chuyện phần thiếu được lấp bằng 0, hay tạo ra một tuple chỉ có một phần tử. Nội dung của cặp được sắp theo thứ tự đã truyền vào, nên không có chuyện 10 và 1 bị đảo chỗ.

Câu 13 | Tách bằng zip

Truyền lại dữ liệu đã ghép cặp cho zip kèm dấu hoa thị. Kết quả hiển thị của đoạn mã sau là gì?

pairs = [(1, 'a'), (2, 'b'), (3, 'c')]nums, chars = zip(*pairs)print(nums)print(chars)
  1. Hiển thị [1, 2, 3] rồi ['a', 'b', 'c']
  2. Hiển thị (1, 2, 3) rồi ('a', 'b', 'c')
  3. Hiển thị ((1, 'a'),) rồi ((2, 'b'),)
  4. Hiển thị (1, 'a') rồi (2, 'b')
Đáp ánB. Hiển thị (1, 2, 3) rồi ('a', 'b', 'c')

Khi thêm dấu hoa thị, từng cặp trong danh sách được truyền cho zip như các đối số riêng biệt. Nghĩa là tương đương với việc gọi zip((1, 'a'), (2, 'b'), (3, 'c')), các phần tử thứ nhất của mỗi cặp được gom lại với nhau, các phần tử thứ hai cũng vậy, tách thành 2 dãy (1, 2, 3) và ('a', 'b', 'c'). Đây là cách làm thường dùng để đưa dữ liệu đã ghép cặp trở lại thành 2 dãy ban đầu; nếu cho qua zip 2 lần thì trở lại như cũ. Vì trả về là tuple chứ không phải danh sách nên không có dạng dấu ngoặc vuông. Nếu quên dấu hoa thị mà viết zip(pairs), thì bản thân từng cặp được truyền như một đối số duy nhất, cho ra dạng tuple 1 phần tử xếp liền nhau như ((1, 'a'),).

Câu 14 | dict và zip

Xây dựng từ điển (dict) từ dãy khóa và dãy giá trị. Kết quả thực thi của đoạn mã sau là gì?

keys = ["a", "b", "c"]vals = [10, 20, 30]print(dict(zip(keys, vals)))
  1. [('a', 10), ('b', 20), ('c', 30)]
  2. {10: 'a', 20: 'b', 30: 'c'}
  3. {'a', 'b', 'c', 10, 20, 30}
  4. {'a': 10, 'b': 20, 'c': 30}
Đáp ánD. {'a': 10, 'b': 20, 'c': 30}

zip(keys, vals) lần lượt trả về tuple (khóa, giá trị), và dict() nhận dãy các cặp đó để tạo ra một từ điển. Vì phần tử thứ nhất của cặp là khóa, phần tử thứ hai là giá trị, nên không thể có dạng số trở thành khóa. Vì đã cho qua dict() nên cũng không còn giữ nguyên dạng danh sách các tuple. Dù cùng hiển thị bằng dấu ngoặc nhọn, nhưng dạng có dấu hai chấm ghép thành cặp là từ điển, còn dạng chỉ xếp các giá trị liền nhau là tập hợp (set).

Câu 15 | List comprehension

Khi thực thi đoạn mã sau dùng cú pháp list comprehension, danh sách nào được hiển thị?

print([n * n for n in range(1, 5)])
  1. [0, 1, 4, 9]
  2. [2, 4, 6, 8]
  3. [1, 4, 9, 16]
  4. [1, 4, 9, 16, 25]
Đáp ánC. [1, 4, 9, 16]

range(1, 5) trả về 1, 2, 3, 4; giá trị 5 chỉ định làm stop không được bao gồm. Bình phương từng số này sẽ ra 1, 4, 9, 16. Nếu nghĩ rằng range bắt đầu từ 0 thì sẽ ra dạng bắt đầu từ 0; nếu hiểu nhầm rằng stop được bao gồm thì sẽ ra dạng có cả 25. Nếu đọc nhầm n * n thành n * 2 thì sẽ ra dạng tăng dần 2 đơn vị một. Nên rèn cách đọc rằng list comprehension đánh giá biểu thức ở đầu bên trái cho từng phần tử, rồi tạo ra một danh sách mới gồm các kết quả đó.

Câu 16 | Dict comprehension

Thực thi cú pháp comprehension viết dấu hai chấm bên trong dấu ngoặc nhọn. Kết quả hiển thị của đoạn mã sau là gì?

words = ["sun", "moon"]print({w: len(w) for w in words})
  1. {'sun': 3, 'moon': 4}
  2. [('sun', 3), ('moon', 4)]
  3. {3: 'sun', 4: 'moon'}
  4. {'sun', 'moon', 3, 4}
Đáp ánA. {'sun': 3, 'moon': 4}

Cú pháp comprehension có dấu hai chấm bên trong dấu ngoặc nhọn là dict comprehension, phía trái dấu hai chấm là khóa, phía phải là giá trị. Ở đây tạo ra từ điển lấy từ (word) làm khóa, số ký tự của từ đó làm giá trị. Nếu đọc ngược khóa và giá trị thì sẽ ra dạng số ký tự trở thành khóa. Nếu bao bằng dấu ngoặc vuông thì sẽ thành danh sách các tuple, nhưng ở đây là dấu ngoặc nhọn nên không như vậy. Nếu không có dấu hai chấm thì trở thành set comprehension, chỉ hiển thị các giá trị xếp liền nhau, nhưng vì có dấu hai chấm nên chỉ có thể tạo ra một từ điển.

Câu 17 | Kiểu của dấu ngoặc tròn

Bao một biểu thức giống comprehension bằng dấu ngoặc tròn. Khi thực thi đoạn mã sau, kiểu nào được hiển thị?

g = (n for n in range(3))print(type(g))
  1. <class 'range'>
  2. <class 'list'>
  3. <class 'generator'>
  4. <class 'tuple'>
Đáp ánC. <class 'generator'>

Python không có cú pháp gọi là tuple comprehension, và dạng bao bằng dấu ngoặc tròn như thế này trở thành biểu thức generator (generator expression). Kiểu là generator, không tạo trước toàn bộ giá trị mà tính từng cái một khi được yêu cầu nên tiết kiệm bộ nhớ, nhưng vì là iterator nên dùng một lần là hết. Khi muốn có tuple thì cần bọc bằng tuple(). Nếu viết bằng dấu ngoặc vuông thì trở thành list comprehension cho ra list; nếu gán trực tiếp range(3) thì ra range. Không thể có được tuple bằng cách viết như thế này.

Câu 18 | Set comprehension

Đếm số phần tử của vật chứa được tạo bằng set comprehension. Kết quả hiển thị của đoạn mã sau là gì?

print(len({n % 4 for n in range(10)}))
  1. Hiển thị 3
  2. Hiển thị 0
  3. Hiển thị 10
  4. Hiển thị 4
Đáp ánD. Hiển thị 4

Số dư khi chia từng giá trị của range(10) cho 4 lần lượt là 0, 1, 2, 3, 0, 1, 2, 3, 0, 1. Cú pháp comprehension dùng dấu ngoặc nhọn nhưng không có dấu hai chấm là set comprehension, nên các giá trị trùng nhau được gộp lại thành một, chỉ còn lại 4 loại là 0, 1, 2, 3. Nếu bỏ sót việc trùng lặp bị loại bỏ mà đếm nguyên số lượng giá trị thì sẽ ra 10. Nếu bỏ sót việc có chứa số dư 0 mà chỉ đếm 3 loại 1, 2, 3 thì sẽ ra 3. Giá trị 0 là kết quả của việc hiểu nhầm rằng comprehension không tạo ra gì cả, nhưng chừng nào còn lặp qua range(10) thì nội dung không thể rỗng được. Vì thứ tự hiển thị của set không cố định, nên kiểm tra bằng số phần tử là cách chắc chắn nhất.

Câu 19 | Comprehension lồng nhau

Xác nhận thứ tự khi xếp 2 câu lệnh for trong comprehension. Kết quả thực thi của đoạn mã sau là gì?

print([(x, y) for x in [1, 2] for y in "ab"])
  1. [(1, 'a'), (2, 'b'), (1, 'b'), (2, 'a')]
  2. [('a', 1), ('b', 1), ('a', 2), ('b', 2)]
  3. [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
  4. [(1, 'a'), (2, 'a'), (1, 'b'), (2, 'b')]
Đáp ánC. [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

Khi xếp 2 câu lệnh for trong comprehension, câu lệnh for viết bên trái sẽ trở thành vòng lặp ngoài. Thứ tự này hoàn toàn giống như khi viết lồng câu lệnh for thông thường: cố định x là 1 rồi cho y chạy qua a, b, sau đó chuyển x thành 2 và lặp lại y tương tự. Nếu đọc nhầm rằng for bên phải là vòng ngoài thì sẽ ra thứ tự x chạy trước. Nội dung của cặp theo đúng thứ tự (x, y) đã viết trong biểu thức, nên không có chuyện ký tự đứng trước.

Câu 20 | Đối số start

Đâu là mô tả phù hợp về đối số thứ hai start của hàm dựng sẵn enumerate?

  1. Chỉ định số bắt đầu đếm; nếu bỏ qua thì đếm từ 0
  2. Chỉ định lấy phần tử từ vị trí nào; nếu bỏ qua thì lấy từ đầu
  3. Chỉ định bỏ cách bao nhiêu phần tử một; nếu bỏ qua thì tiến từng một
  4. Chỉ định đếm đến số thứ mấy; nếu bỏ qua thì đếm đến hết
Đáp ánA. Chỉ định số bắt đầu đếm; nếu bỏ qua thì đếm từ 0

Đối số thứ hai start của enumerate chỉ quyết định số thứ tự được gắn bắt đầu từ đâu. Giá trị mặc định là 0, nên nếu truyền 1 thì sẽ có số thứ tự quen thuộc với con người. Chỉ có cách đánh số thay đổi, còn phạm vi hay số lượng phần tử được lấy ra không đổi, đây là điểm mấu chốt. Nó không có tác dụng giới hạn số lượng hay bỏ cách phần tử, cũng không phải là thứ dịch chuyển vị trí bắt đầu lấy ra. Những chức năng này đều thuộc về các công cụ khác như slice.

Câu 21 | Giá trị trả về của sort

Đoạn mã sau nhận giá trị trả về của phương thức sort trên danh sách bằng một biến. Kết quả hiển thị của đoạn mã đó là gì?

nums = [5, 3, 9]result = nums.sort()print(result)print(nums)
  1. Hiển thị [3, 5, 9] rồi [3, 5, 9] theo thứ tự đó
  2. Hiển thị None rồi [5, 3, 9] theo thứ tự đó
  3. Hiển thị [3, 5, 9] rồi [5, 3, 9] theo thứ tự đó
  4. Hiển thị None rồi [3, 5, 9] theo thứ tự đó
Đáp ánD. Hiển thị None rồi [3, 5, 9] theo thứ tự đó

sort là phương thức sắp xếp lại danh sách tại chỗ, giá trị trả về là None. Do đó result nhận giá trị None, còn kết quả sắp xếp nằm ở phía nums. Nếu nghĩ rằng một danh sách mới đã sắp xếp được trả về thì sẽ ra dạng result chứa danh sách. Nếu bỏ sót việc sort làm thay đổi danh sách gốc thì sẽ ra dạng nums vẫn giữ thứ tự ban đầu. Khi muốn có một danh sách đã sắp xếp mà vẫn giữ nguyên bản gốc, cần dùng hàm dựng sẵn sorted.

Câu 22 | Khác biệt của sorted

Đâu là điểm khác biệt phù hợp giữa phương thức sort của danh sách và hàm dựng sẵn sorted?

  1. sort trả về danh sách mới, sorted sắp xếp tại chỗ và trả về None
  2. sort sắp xếp tại chỗ và trả về None, sorted trả về danh sách mới
  3. Cả hai đều trả về danh sách mới, còn danh sách gốc của cả hai đều không đổi
  4. Cả hai đều sắp xếp tại chỗ rồi trả về danh sách đã sắp xếp
Đáp ánB. sort sắp xếp tại chỗ và trả về None, sorted trả về danh sách mới

sort là phương thức của danh sách, sắp xếp lại chính danh sách đó và trả về None. sorted là hàm dựng sẵn, hoàn toàn không thay đổi thứ tự ban đầu mà trả về một danh sách mới đã sắp xếp. Việc chọn dùng cái nào tùy vào có muốn giữ lại bản gốc hay không. Nếu nhớ nhầm vai trò của hai bên thì sẽ ra giải thích sort trả về danh sách mới. Nếu nghĩ tính phá hủy (destructive) nghiêng về một phía duy nhất thì sẽ ra giải thích cả hai đều sắp xếp tại chỗ, hoặc cả hai đều không thay đổi bản gốc. Ngoài ra sorted cũng có thể nhận các đối tượng khả lặp khác ngoài danh sách, và kết quả luôn là một danh sách.

Câu 23 | Khác biệt của append

So sánh hai cách thêm một danh sách khác vào một danh sách. Kết quả hiển thị của đoạn mã sau là gì?

a = [1, 2]a.append([3, 4])b = [1, 2]b.extend([3, 4])print(a, b)
  1. [1, 2, [3, 4]] [1, 2, [3, 4]]
  2. [1, 2, 3, 4] [1, 2, [3, 4]]
  3. [1, 2, 3, 4] [1, 2, 3, 4]
  4. [1, 2, [3, 4]] [1, 2, 3, 4]
Đáp ánD. [1, 2, [3, 4]] [1, 2, 3, 4]

append thêm toàn bộ đối số như một phần tử duy nhất vào cuối, nên nếu truyền vào một danh sách thì sẽ trở thành lồng nhau và độ dài chỉ tăng thêm 1. extend thêm từng giá trị được lấy ra tuần tự từ đối số, nên nội dung được tháo ra và độ dài tăng thêm 2. Nếu đảo vai trò của hai phương thức thì kết quả của a và b sẽ ngược lại. Nếu nghĩ cả hai có cùng chức năng thì sẽ ra dạng cả hai đều lồng nhau, hoặc cả hai đều phẳng. Cả hai phương thức đều trả về None, nên cũng cần nhớ không được nhận kết quả bằng một biến.

Câu 24 | Sao chép nông

Nhân bản một danh sách lồng nhau bằng slice rồi ghi đè phần bên trong. Kết quả thực thi của đoạn mã sau là gì?

orig = [[1, 2], [3, 4]]copy1 = orig[:]copy1[0].append(9)print(orig)
  1. [[1, 2, 9], [3, 4, 9]]
  2. [[1, 2, 9], [3, 4]]
  3. [[1, 2], [3, 4]]
  4. [[1, 2], [3, 4], 9]
Đáp ánB. [[1, 2, 9], [3, 4]]

Việc nhân bản bằng slice là sao chép nông (shallow copy): danh sách ngoài được tạo mới, nhưng các phần tử bên trong vẫn dùng chung với bản gốc. copy1[0] và orig[0] cùng trỏ đến một danh sách, nên khi append vào đó thì phía bản gốc cũng thấy thay đổi. Nếu nghĩ rằng đã tách rời hoàn toàn thì sẽ ra dạng bản gốc không đổi. Vì chỉ ghi đè danh sách bên trong ở đầu tiên nên không lan sang các phần tử phía sau, và cũng không phải là thêm vào danh sách ngoài nên số 9 không xuất hiện xếp ở ngoài. Muốn tách rời cả phần bên trong thì cần dùng copy.deepcopy.

Câu 25 | Sao chép sâu

So sánh sao chép sâu và sao chép nông trong cùng một đoạn mã. Sau khi thực thi, base trở thành gì?

import copybase = [[1, 2], [3, 4]]d = copy.deepcopy(base)s = base[:]d[0].append(8)s[1].append(7)print(base)
  1. [[1, 2], [3, 4]]
  2. [[1, 2, 8], [3, 4, 7]]
  3. [[1, 2, 8], [3, 4]]
  4. [[1, 2], [3, 4, 7]]
Đáp ánD. [[1, 2], [3, 4, 7]]

copy.deepcopy nhân bản cả nội dung bên trong lồng nhau, nên d[0] là một danh sách khác với base[0], việc append vào đó không ảnh hưởng đến base. Trong khi đó s là sao chép nông nên s[1] và base[1] cùng là một danh sách, việc append vào đó cũng được thấy ở base. Do đó chỉ phần tử phía sau bị kéo dài thêm. Nếu nghĩ cả hai đều ảnh hưởng thì sẽ ra dạng cả hai phần tử bên trong đều dài thêm; nếu nghĩ cả hai đều không ảnh hưởng thì sẽ ra dạng giữ nguyên như ban đầu. Nếu nhầm lẫn sao chép sâu với sao chép nông thì sẽ ra dạng chỉ phần tử phía trước dài thêm.

Câu 26 | Cái bẫy của phép nhân

Cố gắng tạo bảng hai chiều bằng phép nhân danh sách. Kết quả thực thi của đoạn mã sau là gì?

grid = [[0] * 3] * 2grid[0][1] = 5print(grid)
  1. [[0, 0, 0], [0, 5, 0]]
  2. [[5, 0, 0], [5, 0, 0]]
  3. [[0, 5, 0], [0, 0, 0]]
  4. [[0, 5, 0], [0, 5, 0]]
Đáp ánD. [[0, 5, 0], [0, 5, 0]]

Phép nhân ở lớp ngoài không tạo ra các hàng mới, mà chỉ xếp 2 tham chiếu cùng trỏ đến một danh sách duy nhất. grid[0] và grid[1] là cùng một thực thể, nên khi ghi đè vị trí chỉ số 1 của một bên thì bên kia cũng bị thay đổi ở đúng vị trí đó. Nếu nghĩ các hàng độc lập với nhau thì sẽ ra dạng chỉ một hàng thay đổi. Vì đã ghi đè vào vị trí chỉ số 1 nên cũng không thể ra dạng phần đầu trở thành 5. Muốn các hàng độc lập với nhau thì cần viết [[0] * 3 for _ in range(2)].

Câu 27 | Tuple một phần tử

So sánh kiểu của một giá trị chỉ bao bằng dấu ngoặc tròn với một giá trị có dấu phẩy ở cuối. Kết quả hiển thị của đoạn mã sau là gì?

x = (7)y = (7,)print(type(x).__name__, type(y).__name__)
  1. Hiển thị int rồi int theo thứ tự đó
  2. Hiển thị tuple rồi tuple theo thứ tự đó
  3. Hiển thị tuple rồi int theo thứ tự đó
  4. Hiển thị int rồi tuple theo thứ tự đó
Đáp ánD. Hiển thị int rồi tuple theo thứ tự đó

Quyết định tuple hay không là dấu phẩy, chứ không phải dấu ngoặc tròn. (7) chỉ là số nguyên được bao trong ngoặc thể hiện thứ tự ưu tiên tính toán nên kiểu là int; phải viết (7,) có dấu phẩy ở cuối thì mới trở thành tuple có 1 phần tử. Nếu nghĩ rằng cứ bao bằng ngoặc là thành tuple thì sẽ ra dạng cả hai đều là tuple; nếu nhầm lẫn hai cái với nhau thì sẽ ra dạng thứ tự ngược lại hoặc cả hai đều là int. Riêng tuple rỗng là ngoại lệ, được viết là () không có dấu phẩy.

Câu 28 | Nội dung của tuple

Thử thêm phần tử vào một danh sách nằm bên trong tuple. Kết quả thực thi của đoạn mã sau là gì?

t = (1, [2, 3], 4)t[1].append(5)print(t)
  1. Phát sinh TypeError
  2. (1, [2, 3], 4, 5)
  3. (1, [2, 3, 5], 4)
  4. (1, [2, 3], 4)
Đáp ánC. (1, [2, 3, 5], 4)

Điều mà tuple đóng băng là sự tương ứng chỉ đến phần tử nào, chứ không đóng băng luôn nội dung mà nó trỏ tới. t[1] là một danh sách, và bản thân danh sách đó là khả biến (mutable) nên có thể append được. Cách viết gán trực tiếp vào phần tử của tuple như t[1] = [] mới gây ra TypeError, nhưng ở đây không phải là thay thế phần tử. Vì thêm vào bên trong danh sách nên độ dài của tuple sẽ không tăng, và cũng không thể giữ nguyên hoàn toàn không đổi.

Câu 29 | Gán cho slice

Gán một danh sách có độ dài khác vào slice của một danh sách. Kết quả hiển thị của đoạn mã sau là gì?

x = [1, 2, 3, 4, 5]x[1:3] = [9]print(x)
  1. [1, 9, 4, 5]
  2. [1, 9, 3, 4, 5]
  3. [1, 9, 9, 4, 5]
  4. [1, 2, 9, 4, 5]
Đáp ánA. [1, 9, 4, 5]

Gán vào slice là thao tác thay thế toàn bộ phạm vi đã chỉ định bằng nội dung của vế phải. x[1:3] trỏ đến 2 phần tử là 2 và 3, chúng bị thay bằng 1 phần tử duy nhất là 9, nên tổng độ dài giảm từ 5 xuống 4. Nếu nghĩ chỉ 1 phần tử được thay thế thì sẽ ra dạng độ dài vẫn là 5; nếu nghĩ vế phải sẽ được kéo dài cho khớp với bề rộng thì sẽ ra dạng có 2 số 9 xếp cạnh nhau. Nếu đọc lệch điểm bắt đầu của phạm vi đi một vị trí thì sẽ ra dạng còn giữ lại số 2. Đặc điểm của việc gán vào slice là bề rộng bên trái và độ dài bên phải có thể khác nhau.

Câu 30 | Chèn và xóa

Thực hiện liên tiếp việc gán vào slice có bề rộng 0 rồi del. Kết quả thực thi của đoạn mã sau là gì?

y = [1, 2, 3]y[1:1] = [7, 8]del y[0]print(y)
  1. [7, 8, 3]
  2. [1, 7, 8, 3]
  3. [7, 8, 2, 3]
  4. [2, 3, 7, 8]
Đáp ánC. [7, 8, 2, 3]

y[1:1] là phạm vi có bề rộng 0, nên việc gán vào đó là chèn thêm mà không xóa bớt, danh sách trở thành [1, 7, 8, 2, 3]. Tiếp theo del y[0] xóa số 1 ở đầu, còn lại [7, 8, 2, 3]. Nếu đọc nhầm rằng khi chèn thì phần tử gốc cũng mất đi 1 cái thì sẽ ra dạng 7 8 3; nếu nghĩ del xóa ở vị trí khác thì sẽ ra dạng còn giữ số 1 ở đầu. Nếu đọc nhầm rằng đã thêm vào cuối thì sẽ ra dạng 2 và 3 đứng trước. Cũng cần nắm rằng del là câu lệnh nên không có giá trị trả về, và xóa mà không lấy giá trị ra.

Câu 31 | Giá trị mặc định của get

Dùng get để tra một khóa không có trong từ điển. Khi thực thi đoạn mã sau, nội dung nào được hiển thị?

d = {"a": 1, "b": 2}print(d.get("z"), d.get("z", 0))
  1. Hiển thị None rồi 0 theo thứ tự đó
  2. Phát sinh KeyError ở lệnh đầu tiên
  3. Hiển thị None rồi None theo thứ tự đó
  4. Hiển thị 0 rồi 0 theo thứ tự đó
Đáp ánA. Hiển thị None rồi 0 theo thứ tự đó

get không ném ra ngoại lệ khi không có khóa; nếu bỏ qua đối số thứ hai thì trả về None, nếu có truyền thì trả về giá trị đó. Do đó lệnh đầu là None, lệnh thứ hai là 0. Nếu nghĩ rằng khi không có đối số thứ hai vẫn trả về 0 thì sẽ ra dạng cả hai đều là 0; nếu nghĩ đối số thứ hai bị bỏ qua thì sẽ ra dạng cả hai đều là None. Viết bằng dấu ngoặc vuông như d["z"] sẽ gây ra KeyError, và get chính là công cụ để tránh điều đó.

Câu 32 | setdefault

Gọi setdefault cho cả một khóa đã có và một khóa chưa có. Kết quả hiển thị của đoạn mã sau là gì?

d = {"a": 1}print(d.setdefault("a", 99))print(d.setdefault("b", 99))print(d)
  1. Hiển thị 99 rồi 99, sau đó hiển thị {'a': 99, 'b': 99}
  2. Hiển thị 1 rồi 99, sau đó hiển thị {'a': 1, 'b': 99}
  3. Hiển thị 1 rồi None, sau đó hiển thị {'a': 1, 'b': None}
  4. Hiển thị 1 rồi 99, sau đó hiển thị {'a': 1}
Đáp ánB. Hiển thị 1 rồi 99, sau đó hiển thị {'a': 1, 'b': 99}

setdefault chỉ trả về giá trị hiện có nếu khóa đã tồn tại, và không thay đổi từ điển. Nếu khóa chưa có thì chèn đối số thứ hai làm giá trị và trả về giá trị đó. Vì vậy lần gọi thứ nhất trả về giá trị 1 sẵn có và từ điển giữ nguyên, lần gọi thứ hai chèn thêm 99 và trả về 99. Nếu nghĩ rằng giá trị đã có cũng bị ghi đè thì sẽ ra dạng cả hai đều là 99. Nếu nghĩ việc chèn không xảy ra thì sẽ ra dạng từ điển không tăng thêm. Nếu bỏ qua đối số thứ hai thì giá trị được chèn sẽ là None, nên dạng có None là kết quả khi không viết đối số thứ hai.

Câu 33 | Nơi in kiểm tra

Xác nhận toán tử in đối với từ điển kiểm tra cái gì. Kết quả hiển thị của đoạn mã sau là gì?

d = {"x": 1, "y": 2}print("x" in d, 1 in d, 1 in d.values())
  1. Hiển thị True False True theo thứ tự đó
  2. Hiển thị True True True theo thứ tự đó
  3. Hiển thị True False False theo thứ tự đó
  4. Hiển thị False True True theo thứ tự đó
Đáp ánA. Hiển thị True False True theo thứ tự đó

in đối với từ điển chỉ kiểm tra khóa. "x" có trong khóa nên là True, còn 1 tuy tồn tại như một giá trị nhưng không có trong khóa nên là False. Khi muốn kiểm tra giá trị thì nhắm vào d.values(), trường hợp này sẽ là True. Nếu nghĩ rằng in cũng xét cả giá trị thì sẽ ra dạng tất cả đều True; nếu nghĩ ngay cả nhắm vào values() cũng không xét giá trị thì sẽ ra dạng phần cuối là False. Nếu đọc hoán đổi vai trò của khóa và giá trị thì sẽ ra dạng phần đầu là False. Cách dùng tiêu chuẩn là kiểm tra sự tồn tại của khóa trước rồi mới tra bằng dấu ngoặc vuông.

Câu 34 | Trùng khóa

Viết cùng một khóa hai lần trong literal của từ điển. Kết quả thực thi của đoạn mã sau là gì?

d = {"a": 1, "b": 2, "a": 3}print(d)
  1. {'a': 3, 'b': 2}
  2. {'a': 1, 'b': 2}
  3. {'b': 2, 'a': 3}
  4. {'a': 3, 'b': 3}
Đáp ánA. {'a': 3, 'b': 2}

Literal của từ điển tạo từng mục theo thứ tự từ trái sang, nên nếu cùng một khóa xuất hiện 2 lần thì giá trị sau sẽ ghi đè giá trị trước. Không xảy ra lỗi hay cảnh báo. Nếu nghĩ giá trị viết trước sẽ được giữ lại thì sẽ ra dạng giá trị của a vẫn là 1. Ngoài ra, từ điển giữ nguyên thứ tự đã chèn vào, việc ghi đè không làm thay đổi vị trí, nên a vẫn đứng ở vị trí đầu như cũ. Do đó không có chuyện thứ tự các khóa bị đảo lộn, cũng không có chuyện giá trị của b bị ảnh hưởng theo.

Câu 35 | Cách tạo từ điển

So sánh từ điển được tạo từ đối số từ khóa với từ điển được tạo từ một dãy các cặp. Kết quả hiển thị của đoạn mã sau là gì?

d1 = dict(x=1, y=2)d2 = dict([("x", 1), ("y", 2)])print(d1 == d2)print(d1)
  1. Hiển thị False, sau đó hiển thị {'x': 1, 'y': 2}
  2. Hiển thị True, sau đó hiển thị {1: 'x', 2: 'y'}
  3. Hiển thị True, sau đó hiển thị {'x': 1, 'y': 2}
  4. Hiển thị True, sau đó hiển thị [('x', 1), ('y', 2)]
Đáp ánC. Hiển thị True, sau đó hiển thị {'x': 1, 'y': 2}

dict có thể tạo từ điển từ đối số từ khóa, cũng như từ một dãy các cặp (khóa, giá trị). Dù dùng cách viết nào thì cũng tạo ra từ điển có cùng nội dung nên phép so sánh cho ra True. Nếu nghĩ cách tạo khác nhau sẽ ra vật khác nhau thì sẽ ra dạng phép so sánh là False. Vì tên của đối số từ khóa trở thành trực tiếp chuỗi làm khóa, nên không có chuyện khóa và giá trị bị đảo chỗ. Vì đã cho qua dict nên đã trở thành từ điển, không còn giữ nguyên dạng dãy các cặp.

Câu 36 | Dấu ngoặc nhọn rỗng

So sánh kiểu của dấu ngoặc nhọn rỗng với set(). Khi thực thi đoạn mã sau, 2 tên kiểu nào được hiển thị?

a = {}b = set()print(type(a).__name__, type(b).__name__)
  1. Hiển thị dict rồi dict theo thứ tự đó
  2. Hiển thị set rồi set theo thứ tự đó
  3. Hiển thị dict rồi set theo thứ tự đó
  4. Hiển thị set rồi dict theo thứ tự đó
Đáp ánC. Hiển thị dict rồi set theo thứ tự đó

{1, 2} có chứa phần tử sẽ trở thành tập hợp (set), nhưng nếu bên trong rỗng thì không thể quyết định là từ điển hay tập hợp. Python xử lý trường hợp này như một từ điển, nên {} là một từ điển rỗng. Khi muốn có một tập hợp rỗng thì buộc phải viết set(). Nếu nghĩ rằng dấu ngoặc nhọn luôn luôn là tập hợp thì sẽ ra dạng cả hai đều là set; nếu nhầm lẫn hai cái với nhau thì sẽ ra dạng thứ tự ngược lại. Nếu nghĩ đến cả set() cũng trở thành từ điển thì sẽ ra dạng cả hai đều là dict. Vì cả tập hợp và từ điển đều dùng dấu ngoặc nhọn nên sự phân biệt này rất dễ nhầm lẫn.

Câu 37 | Phép toán tập hợp

Thực hiện phép giao và phép hiệu đối xứng trên 2 tập hợp. Kết quả hiển thị của đoạn mã sau là gì?

s1 = {1, 2, 3, 4}s2 = {3, 4, 5}print(sorted(s1 & s2), sorted(s1 ^ s2))
  1. Hiển thị [3, 4] rồi [1, 2, 3, 4, 5] theo thứ tự đó
  2. Hiển thị [1, 2, 5] rồi [3, 4] theo thứ tự đó
  3. Hiển thị [3, 4] rồi [1, 2] theo thứ tự đó
  4. Hiển thị [3, 4] rồi [1, 2, 5] theo thứ tự đó
Đáp ánD. Hiển thị [3, 4] rồi [1, 2, 5] theo thứ tự đó

Dấu và (&) là phép giao, giữ lại 3 và 4 vốn có ở cả hai. Dấu mũ (^) là phép hiệu đối xứng, gom các phần tử chỉ có ở một bên duy nhất, nên giữ lại 1 và 2 chỉ có ở s1, và 5 chỉ có ở s2, còn 3 và 4 chung thì bị loại. Nếu nhầm hiệu đối xứng với phép hiệu (difference) thì sẽ ra dạng thiếu số 5; nếu đảo thứ tự 2 phép toán thì thứ tự hiển thị sẽ ngược lại. Nếu nhầm hiệu đối xứng với phép hợp (union) thì sẽ ra dạng có cả 3 và 4. Vì thứ tự hiển thị của tập hợp không cố định nên ở đây dùng sorted để sắp xếp rồi kiểm tra.

Câu 38 | Loại bỏ trùng lặp

Cho một danh sách có phần tử trùng lặp đi qua một tập hợp. Kết quả hiển thị khi thực thi đoạn mã sau là gì?

data = [3, 1, 3, 2, 1, 1]print(len(set(data)), sorted(set(data)))
  1. Hiển thị 6 rồi [3, 1, 3, 2, 1, 1] theo thứ tự đó
  2. Hiển thị 6 rồi [1, 2, 3] theo thứ tự đó
  3. Hiển thị 3 rồi [3, 1, 2] theo thứ tự đó
  4. Hiển thị 3 rồi [1, 2, 3] theo thứ tự đó
Đáp ánD. Hiển thị 3 rồi [1, 2, 3] theo thứ tự đó

Khi truyền một danh sách cho set, các phần tử trùng lặp bị loại bỏ, chỉ còn lại 3 loại giá trị là 1, 2, 3, nên độ dài là 3. Khi truyền một tập hợp cho sorted thì trả về một danh sách mới đã sắp theo thứ tự tăng dần. Nếu nghĩ phần trùng lặp vẫn còn thì sẽ ra dạng số lượng là 6. sorted sắp xếp theo giá trị lớn nhỏ chứ không theo thứ tự xuất hiện gốc, nên cũng không thể xếp theo thứ tự xuất hiện đầu tiên. Thứ tự hiển thị của bản thân tập hợp không có ý nghĩa, nên khi muốn sắp xếp cần cho qua sorted.

Câu 39 | Điều kiện của phần tử

Thử lần lượt thêm một tuple và một danh sách vào một tập hợp. Khi thực thi đoạn mã sau, điều gì sẽ xảy ra?

s = set()s.add((1, 2))s.add([3, 4])print(len(s))
  1. Hiển thị 1, danh sách được chuyển đổi thành tuple
  2. Phát sinh TypeError, vì không thể đưa danh sách vào tập hợp
  3. Phát sinh ValueError, vì các kiểu phần tử không thể trộn lẫn
  4. Hiển thị 2, cả hai phần tử đều được thêm vào tập hợp
Đáp ánB. Phát sinh TypeError, vì không thể đưa danh sách vào tập hợp

Phần tử của tập hợp và khóa của từ điển phải là loại có thể băm (hashable). Tuple không thể thay đổi nội dung nên có thể băm và thêm được, nhưng danh sách có thể thay đổi nội dung về sau nên không thể băm, dẫn đến TypeError với thông báo unhashable type. Nếu nghĩ cả hai đều thêm được thì sẽ ra dạng hiển thị 2; nếu nghĩ danh sách được ngầm chuyển thành tuple thì sẽ ra dạng hiển thị 1. Việc trộn lẫn kiểu tự nó không phải là vấn đề, nên cách giải thích dẫn đến ValueError cũng sai.

Câu 40 | 3 cách lấy ra

Đâu là tổ hợp phù hợp về những gì mà các phương thức keys, values, items của từ điển trả về?

  1. keys trả về cặp giá trị, values trả về cặp khóa, items trả về số lượng mục
  2. keys trả về cặp khóa và giá trị, values trả về khóa, items trả về giá trị
  3. keys trả về giá trị, values trả về khóa, items trả về cặp giữa các giá trị với nhau
  4. keys trả về khóa, values trả về giá trị, items trả về cặp khóa và giá trị
Đáp ánD. keys trả về khóa, values trả về giá trị, items trả về cặp khóa và giá trị

keys chỉ trả về khóa, values chỉ trả về giá trị, còn items lần lượt trả về tuple (khóa, giá trị). Khi duyệt qua từ điển, cách viết chuẩn là for k, v in d.items() nhận bằng 2 biến. Nếu nhớ nhầm và đảo vai trò của 3 phương thức thì sẽ ra giải thích kiểu keys trả về giá trị. Những gì items trả về là một dãy các mục chứ không phải số lượng, nên giải thích rằng nó trả về số lượng mục cũng sai; khi muốn biết số lượng thì dùng len. Ngoài ra, nếu truyền trực tiếp từ điển cho for thì các khóa sẽ được lấy ra.

Luyện tập: giải các câu hỏi trên trang này

Đây là công cụ luyện tập với câu hỏi ngẫu nhiên (hoạt động khi JavaScript được bật). Bạn vẫn có thể đọc toàn bộ câu hỏi và phần giải thích ở trên.

* Lời giải là thông tin phục vụ việc học. Phạm vi ra đề và chế độ thi có thể thay đổi theo từng năm, vì vậy hãy luôn kiểm tra thông báo chính thức của đơn vị tổ chức thi.

Trang này là bản dịch từ nguyên bản tiếng Nhật. Nếu nội dung bản dịch và nguyên bản khác nhau, bản tiếng Nhật sẽ được ưu tiên. Xem nguyên bản tiếng Nhật