{
  "assessmentTests": {
    "python_test": {
      "name": "Bài Kiểm Tra Python",
      "desc": "30 câu hỏi tình huống về cú pháp, hàm, cấu trúc dữ liệu và hành vi đối tượng — tìm hiểu liệu kỹ năng Python của bạn có phù hợp với ý nghĩa của thông báo tuyển dụng hay không.",
      "recommendation": "Hồ sơ kỹ năng Python của bạn",
      "results": {
        "beginner": {
          "name": "Người Mới Bắt Đầu",
          "desc": "Bạn có thể theo dõi một tập lệnh ngắn và thay đổi các giá trị bên trong nó, nhưng những câu hỏi bạn sai tập trung xung quanh hành vi cụ thể của ngôn ngữ hơn là logic chung — một đối số mặc định được xây dựng một lần và tái sử dụng, is so với == trên hai danh sách trông giống nhau, một biến trở thành cục bộ ngay khi bạn gán giá trị cho nó ở bất kỳ đâu trong hàm. Không phải là do kỹ năng lập trình yếu; đây là những quy tắc cụ thể của Python khiến những người từ các ngôn ngữ khác cũng bị vấp phải, cũng như những người mới. Chúng quan trọng ở nơi làm việc vì mỗi quy tắc là nơi ẩn chứa một lỗi trong mã trông chính xác thoạt nhìn.",
          "recommendation": "Hãy bắt đầu với ba điều, theo thứ tự này: đối số mặc định có thể thay đổi (tại sao basket=[] là nguy hiểm), sự khác biệt giữa is và ==, và cách phạm vi biến hoạt động bên trong một hàm. Hướng dẫn Python chính thức tại docs.python.org bao gồm cả ba điều trực tiếp, và thuật ngữ \"những điều khiến Python khó hiểu\" có nhiều ví dụ được giải quyết cho từng cái."
        },
        "intermediate": {
          "name": "Trung Cấp",
          "desc": "Bạn xử lý kịch bản hàng ngày một cách thoải mái — cấu trúc dữ liệu, luồng điều khiển, các hàm thẳng — và sẽ không bị làm chậm bởi công việc bảo trì thông thường hoặc một tính năng nhỏ trên một codebase hiện tại. Khoảng cách giữa đây và Nâng Cao chủ yếu là những gì xảy ra khi các tính năng tiện lợi của Python tương tác với nhau: một bản sao nông để lại dữ liệu lồng nhau được chia sẻ khi bạn mong đợi được nhân bản, giá trị trả về của một trình tạo yên tĩnh không trở thành một phần của đầu ra của nó, những bộ trang trí xếp chồng theo một thứ tự dễ bị đảo ngược. Đó là loại lỗi mà một nhà đánh giá cao cấp gắn cờ trong mười giây và mọi người khác dành một giờ để truy tìm.",
          "recommendation": "Tập trung vào những nội bộ đối tượng và lặp lại: sao chép nông so với sao chép sâu, trình tạo thực sự làm gì với return, và cách thứ tự xếp chồng bộ trang trí hoạt động. Sau đó là những điều cơ bản về lớp mà hầu hết các hướng dẫn bỏ qua — bình đẳng mặc định mà không có __eq__, và tại sao một thuộc tính lớp có thể thay đổi lại được chia sẻ trên mọi thể hiện."
        },
        "advanced": {
          "name": "Nâng Cao",
          "desc": "Đây là mức mà hầu hết thông báo tuyển dụng có ý là \"Python mạnh mẽ.\" Bạn tìm kiếm công cụ phù hợp mà không phải tìm kiếm, bạn biết tại sao một phần trạng thái chia sẻ đã thay đổi thay vì chỉ biết là nó đã thay đổi, và bạn có thể đọc hàm của người khác và dự đoán chính xác đầu ra của nó. Điều tách rời dải này với đỉnh cao là phía bảo vệ của công việc: biết cách tiếp cận nào trong hai cách trông chính xác sẽ hoạt động sai khi một thuộc tính lớp, một đối số chỉ từ khóa, hoặc một hệ thống phân cấp ngoại lệ có liên quan.",
          "recommendation": "Đi sâu vào những phần bảo vệ một codebase mà những người khác cũng chạm vào: các đối số chỉ từ khóa như một lựa chọn thiết kế API hơn là một điều tò mò cú pháp, hệ thống phân cấp ngoại lệ (để các mệnh đề except bắt đúng gia đình lỗi, không chỉ một lớp), và trình quản lý ngữ cảnh là cách tiêu chuẩn để đảm bảo dọn dẹp. Các bài viết đi sâu của Real Python là một điểm dừng tốt tiếp theo cho cả ba."
        },
        "expert": {
          "name": "Chuyên Gia",
          "desc": "Bạn đã ghi điểm ở mức cao nhất trong mọi phần — cú pháp cốt lõi, hàm và phạm vi, cấu trúc dữ liệu và thành ngữ hướng đối tượng. Thực tế, điều đó có nghĩa là bạn có thể được giao tệp của người lạ và giải thích tại sao nó tạo ra đầu ra mà nó làm, không chỉ những gì cú pháp nói rằng nó phải làm, đó là kỹ năng khó hơn và có giá trị hơn. Ở cấp độ này, ngôn ngữ thô hiếm khi là yếu tố hạn chế trong công việc của bạn; giới hạn thường là kích thước hoặc hình dạng của hệ thống xung quanh mã.",
          "recommendation": "Lợi nhuận bây giờ nằm trong công cụ và ôn tập: kiểm tra kiểu tĩnh với mypy hoặc pyright, lập hồ sơ trước khi tối ưu hóa hơn là đoán, và đọc các yêu cầu kéo của những người khác chính xác cho danh mục lỗi này — những lỗi vượt qua mọi bài kiểm tra và vẫn làm sai điều gì đó dưới một đầu vào cụ thể. Nếu bạn đang được sàng lọc cho một vai trò, mô tả một lỗi như thế này mà bạn tìm thấy thay vì đặt tên các tính năng ngôn ngữ — nó chứng minh lý luận, không chỉ là từ vựng."
        }
      },
      "questions": [
        {
          "question": "Bạn viết def add_item(item, basket=[]): basket.append(item); return basket, sau đó gọi add_item('a') và add_item('b'), cả hai lần bỏ qua basket. Lệnh gọi thứ hai trả về cái gì?",
          "options": [
            {
              "icon": "",
              "label": "['b'] — mỗi lệnh gọi nhận được một danh sách trống mới theo mặc định"
            },
            {
              "icon": "",
              "label": "TypeError — bạn phải cung cấp một đối số basket"
            },
            {
              "icon": "",
              "label": "['a', 'b'] — danh sách mặc định được tạo một lần và tái sử dụng trên các lệnh gọi"
            },
            {
              "icon": "",
              "label": "['a'] sau đó ['b'] là hai danh sách độc lập có một mục"
            }
          ]
        },
        {
          "question": "a = [1, 2, 3] và b = [1, 2, 3]. Điều gì làm cho a == b trả về, và điều gì làm cho a is b trả về?",
          "options": [
            {
              "icon": "",
              "label": "True cho cả hai — các danh sách giống nhau luôn cùng một đối tượng"
            },
            {
              "icon": "",
              "label": "True cho ==, False cho is — nội dung bằng nhau nhưng các đối tượng khác nhau trong bộ nhớ"
            },
            {
              "icon": "",
              "label": "False cho cả hai — các chữ tách biệt không bao giờ bằng nhau trong Python"
            },
            {
              "icon": "",
              "label": "True cho is, False cho == — is kiểm tra bình đẳng giá trị cho danh sách"
            }
          ]
        },
        {
          "question": "Trong Python 3, điều gì làm cho 7 / 2 đánh giá, và điều gì làm cho 7 // 2 đánh giá?",
          "options": [
            {
              "icon": "",
              "label": "3.5, sau đó 3 — / luôn trả về một số thực, // làm tròn kết quả"
            },
            {
              "icon": "",
              "label": "3, sau đó 3.5 — / cắt ngắn và // trả về một số thực"
            },
            {
              "icon": "",
              "label": "3.5, sau đó 3.5 — cả hai toán tử trả về một số thực trong Python 3"
            },
            {
              "icon": "",
              "label": "3, sau đó 3 — cả hai toán tử làm tròn kết quả trong Python 3"
            }
          ]
        },
        {
          "question": "s = 'hello', sau đó bạn chạy s[0] = 'H'. Điều gì sẽ xảy ra?",
          "options": [
            {
              "icon": "",
              "label": "s trở thành 'Hello'"
            },
            {
              "icon": "",
              "label": "s trở thành 'Hhello' vì ký tự được chèn, không phải thay thế"
            },
            {
              "icon": "",
              "label": "TypeError — chuỗi không thể thay đổi và không hỗ trợ gán mục"
            },
            {
              "icon": "",
              "label": "Không có gì — sự gán được yên tĩnh bỏ qua và s vẫn là 'hello'"
            }
          ]
        },
        {
          "question": "x = [10, 20, 30, 40, 50]. Điều gì làm cho x[1:4] trả về?",
          "options": [
            {
              "icon": "",
              "label": "[20, 30, 40, 50]"
            },
            {
              "icon": "",
              "label": "[10, 20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[30, 40]"
            }
          ]
        },
        {
          "question": "name = 'Ana' và age = 30. Điều gì làm cho f'{name} is {age}' tạo ra?",
          "options": [
            {
              "icon": "",
              "label": "\"{name} is {age}\""
            },
            {
              "icon": "",
              "label": "Ana is 30"
            },
            {
              "icon": "",
              "label": "name is age"
            },
            {
              "icon": "",
              "label": "Một TypeError, vì chuỗi f yêu cầu phương thức format()"
            }
          ]
        },
        {
          "question": "Điều gì làm cho 1 < 2 < 3 đánh giá?",
          "options": [
            {
              "icon": "",
              "label": "True — Python xâu chuỗi các so sánh như (1 < 2) và (2 < 3)"
            },
            {
              "icon": "",
              "label": "False — các so sánh xâu chuỗi được đánh giá từ trái sang phải mà không có ngắn mạch, cho 1 < 2 < 3 -> 1 < True -> False"
            },
            {
              "icon": "",
              "label": "Một SyntaxError — các so sánh không thể xâu chuỗi"
            },
            {
              "icon": "",
              "label": "3 — Python trả về giá trị cuối cùng trong chuỗi"
            }
          ]
        },
        {
          "question": "Điều gì làm cho bool([]) trả về, và điều gì làm cho bool([0]) trả về?",
          "options": [
            {
              "icon": "",
              "label": "False, sau đó False — bất kỳ danh sách nào chỉ chứa các giá trị giả đều là giả"
            },
            {
              "icon": "",
              "label": "False, sau đó True — một danh sách trống là giả, một danh sách chứa một phần tử (thậm chí 0) là thật"
            },
            {
              "icon": "",
              "label": "True, sau đó True — các đối tượng không phải None luôn luôn thật"
            },
            {
              "icon": "",
              "label": "True, sau đó False — một danh sách là thật chỉ khi trống"
            }
          ]
        },
        {
          "question": "Một count = 0 cấp độ mô-đun tồn tại. Bên trong def increment(): count += 1; return count, bạn gọi increment(). Điều gì sẽ xảy ra?",
          "options": [
            {
              "icon": "",
              "label": "UnboundLocalError — gán cho count ở bất kỳ đâu trong hàm làm cho nó cục bộ, vì vậy count += 1 cố gắng đọc một biến cục bộ trước khi được gán"
            },
            {
              "icon": "",
              "label": "Nó trả về 1 và tăng count cấp độ mô-đun lên 1"
            },
            {
              "icon": "",
              "label": "Nó trả về 1 nhưng để count cấp độ mô-đun ở 0"
            },
            {
              "icon": "",
              "label": "Nó tăng NameError vì count chưa bao giờ được khai báo bên trong hàm"
            }
          ]
        },
        {
          "question": "def f(*args, **kwargs): return args, kwargs. Điều gì làm cho f(1, 2, x=3) trả về?",
          "options": [
            {
              "icon": "",
              "label": "([1, 2], {'x': 3})"
            },
            {
              "icon": "",
              "label": "((1, 2), {'x': 3})"
            },
            {
              "icon": "",
              "label": "(1, 2, {'x': 3})"
            },
            {
              "icon": "",
              "label": "TypeError — các đối số vị trí và từ khóa không thể được trộn lẫn trong một lệnh gọi"
            }
          ]
        },
        {
          "question": "Bạn xây dựng funcs = [lambda: i for i in range(3)] trong một vòng lặp. Điều gì làm cho [f() for f in funcs] trả về?",
          "options": [
            {
              "icon": "",
              "label": "[2, 2, 2] — mỗi lambda tra cứu i khi được gọi, và khi đó vòng lặp đã hoàn thành với i bằng 2"
            },
            {
              "icon": "",
              "label": "[0, 1, 2] — mỗi lambda nắm bắt giá trị của i vào lúc nó được tạo"
            },
            {
              "icon": "",
              "label": "[0, 0, 0] — lambda luôn nắm bắt giá trị đầu tiên được gán cho một biến"
            },
            {
              "icon": "",
              "label": "Một NameError, vì i không còn tồn tại sau khi vòng lặp kết thúc"
            }
          ]
        },
        {
          "question": "Một hàm được định nghĩa với @a trực tiếp phía trên @b, cái nằm trực tiếp phía trên def f(): pass. Các bộ trang trí được áp dụng cho f theo thứ tự nào?",
          "options": [
            {
              "icon": "",
              "label": "b bao bọc f trước tiên, sau đó a bao bọc kết quả của b — bộ trang trí gần nhất với hàm chạy trước"
            },
            {
              "icon": "",
              "label": "a bao bọc f trước tiên, sau đó b bao bọc kết quả — các bộ trang trí áp dụng từ trên xuống dưới"
            },
            {
              "icon": "",
              "label": "Cả hai bộ trang trí bao bọc f độc lập và chỉ cái cuối cùng được định nghĩa có hiệu lực"
            },
            {
              "icon": "",
              "label": "Nó phụ thuộc vào thứ tự các bộ trang trí được nhập, không phải vị trí của chúng trong mã"
            }
          ]
        },
        {
          "question": "def f(a, *, b): return a + b. Cái nào trong những lệnh gọi này hoạt động?",
          "options": [
            {
              "icon": "",
              "label": "f(1, b=2) — b phải được chuyển bằng từ khóa vì nó đứng sau * trần trong chữ ký"
            },
            {
              "icon": "",
              "label": "f(1, 2) — các đối số vị trí điền các tham số từ trái sang phải bất kể *"
            },
            {
              "icon": "",
              "label": "f(a=1, 2) — các đối số từ khóa phải đến trước"
            },
            {
              "icon": "",
              "label": "f(1) — b là tùy chọn vì nó theo sau *"
            }
          ]
        },
        {
          "question": "Một hàm trình tạo yields 1, sau đó yields 2, sau đó làm return 99. Điều gì làm cho list(the_generator()) chứa, và điều gì xảy ra với 99?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 99] — return bên trong một trình tạo hoạt động giống như một yield khác"
            },
            {
              "icon": "",
              "label": "[99] — return ngay lập tức ghi đè bất kỳ giá trị nào đã được yield"
            },
            {
              "icon": "",
              "label": "[1, 2] — giá trị trả về của một trình tạo trở thành giá trị được đính kèm với StopIteration nó tăng, nó không được yield"
            },
            {
              "icon": "",
              "label": "Một RuntimeError, vì trình tạo không thể chứa một câu lệnh return"
            }
          ]
        },
        {
          "question": "Trong một hàm outer(), x = 1 được đặt, sau đó một inner() lồng nhau làm nonlocal x; x += 1, và outer() gọi inner() trước khi trả về x. Điều gì làm cho outer() trả về?",
          "options": [
            {
              "icon": "",
              "label": "1 — inner() hoạt động trên bản sao cục bộ của riêng nó của x, vì vậy thay đổi không tồn tại"
            },
            {
              "icon": "",
              "label": "Một UnboundLocalError, vì x không được khai báo bên trong inner() trước câu lệnh nonlocal"
            },
            {
              "icon": "",
              "label": "Một SyntaxError — nonlocal chỉ có thể được sử dụng bên trong lớp"
            },
            {
              "icon": "",
              "label": "2 — nonlocal cho phép inner() sửa đổi x của hàm bên ngoài thay vì tạo một biến cục bộ mới"
            }
          ]
        },
        {
          "question": "d = {'a': 1, 'b': 2}. Điều gì làm cho d.get('c', 0) trả về, và nó có thêm 'c' vào từ điển không?",
          "options": [
            {
              "icon": "",
              "label": "0, và không — get() trả về mặc định mà không chèn khóa"
            },
            {
              "icon": "",
              "label": "0, và có — get() chèn khóa với giá trị mặc định"
            },
            {
              "icon": "",
              "label": "KeyError, vì 'c' không tồn tại"
            },
            {
              "icon": "",
              "label": "None, và có — get() luôn thêm các khóa thiếu với giá trị None"
            }
          ]
        },
        {
          "question": "t = (1, 2, [3, 4]). Bạn có thể chạy t[2].append(5), và bạn có thể chạy t[0] = 10 không?",
          "options": [
            {
              "icon": "",
              "label": "Cả hai hoạt động — lồng một danh sách bên trong một bộ dữ liệu làm cho toàn bộ bộ dữ liệu có thể thay đổi"
            },
            {
              "icon": "",
              "label": "Cả hai tăng TypeError — không có gì bên trong một bộ dữ liệu bao giờ có thể được thay đổi"
            },
            {
              "icon": "",
              "label": "t[2].append(5) tăng TypeError, nhưng t[0] = 10 hoạt động vì các bộ dữ liệu cho phép tái gán phần tử đầu tiên của chúng"
            },
            {
              "icon": "",
              "label": "t[2].append(5) hoạt động vì danh sách bên trong có thể thay đổi; t[0] = 10 tăng TypeError vì bộ dữ liệu tự nó không thay đổi được"
            }
          ]
        },
        {
          "question": "Cái nào trong số này trả về một trình lặp tính toán giá trị một cách lười biếng thay vì xây dựng toàn bộ chuỗi trong bộ nhớ cùng một lúc: [x*x for x in range(1000000)] hoặc (x*x for x in range(1000000))?",
          "options": [
            {
              "icon": "",
              "label": "Cái có dấu ngoặc đơn, (x*x for x in range(1000000)) — đó là một biểu thức trình tạo"
            },
            {
              "icon": "",
              "label": "Cái có dấu ngoặc vuông — các bao gồm danh sách luôn lười biếng trong Python 3"
            },
            {
              "icon": "",
              "label": "Cả hai lười biếng — điểm khác duy nhất là loại được trả về ở cuối"
            },
            {
              "icon": "",
              "label": "Không — cả hai xây dựng toàn bộ chuỗi trong bộ nhớ ngay lập tức"
            }
          ]
        },
        {
          "question": "Một khối try chia cho không, mệnh đề except ZeroDivisionError in print 'a', và một mệnh đề finally in print 'b'. Điều gì in, và theo thứ tự nào?",
          "options": [
            {
              "icon": "",
              "label": "b sau đó a — finally luôn chạy trước bất kỳ mệnh đề except nào"
            },
            {
              "icon": "",
              "label": "a sau đó b — except khớp nhất chạy trước, và finally luôn chạy sau bất kỳ lúc nào"
            },
            {
              "icon": "",
              "label": "Chỉ b — ngoại lệ không thực sự được bắt, vì vậy 'a' không bao giờ in"
            },
            {
              "icon": "",
              "label": "Chỉ a — finally được bỏ qua sau khi một ngoại lệ đã được xử lý"
            }
          ]
        },
        {
          "question": "import copy; a = [[1, 2], [3, 4]]; b = copy.copy(a); b[0].append(99). Điều gì làm cho a[0] thay đổi quá không?",
          "options": [
            {
              "icon": "",
              "label": "Không — copy.copy() luôn nhân bản các đối tượng lồng nhau"
            },
            {
              "icon": "",
              "label": "Không — nối thêm vào b[0] tạo một danh sách hoàn toàn mới cho b[0] chỉ"
            },
            {
              "icon": "",
              "label": "Có, nhưng chỉ vì copy.copy() được gọi mà không có đối số deepcopy"
            },
            {
              "icon": "",
              "label": "Có — copy.copy() tạo một bản sao nông, vì vậy danh sách lồng nhau vẫn được chia sẻ giữa a và b"
            }
          ]
        },
        {
          "question": "d = {'x': 1, 'y': 2}. Điều gì làm cho 'x' in d kiểm tra chống — các khóa, các giá trị, hoặc cả hai?",
          "options": [
            {
              "icon": "",
              "label": "Các giá trị — `in` kiểm tra xem 1 hoặc 2 có bằng 'x' không"
            },
            {
              "icon": "",
              "label": "Cả khóa và giá trị được kiểm tra"
            },
            {
              "icon": "",
              "label": "Không — `in` trên một dict luôn tăng TypeError"
            },
            {
              "icon": "",
              "label": "Các khóa — `in` trên một từ điển kiểm tra thành viên giữa các khóa của nó, không phải giá trị của nó"
            }
          ]
        },
        {
          "question": "names = ['Al', 'Bo'] và scores = [10, 20]. Điều gì làm cho list(zip(names, scores)) trả về?",
          "options": [
            {
              "icon": "",
              "label": "[('Al', 'Bo'), (10, 20)]"
            },
            {
              "icon": "",
              "label": "['Al', 10, 'Bo', 20]"
            },
            {
              "icon": "",
              "label": "[('Al', 10), ('Bo', 20)]"
            },
            {
              "icon": "",
              "label": "Một ValueError, vì zip yêu cầu ba hoặc nhiều đối số"
            }
          ]
        },
        {
          "question": "class Dog: tricks = [] giữ một danh sách cấp độ lớp, và add_trick nối vào self.tricks. d1 = Dog() và d2 = Dog() đều được tạo, sau đó d1.add_trick('sit') chạy. Điều gì làm cho d2.tricks chứa?",
          "options": [
            {
              "icon": "",
              "label": "[] — mỗi thể hiện nhận được bản sao độc lập của tricks"
            },
            {
              "icon": "",
              "label": "['sit'] — tricks là một danh sách cấp độ lớp được chia sẻ bởi mỗi thể hiện, vì vậy thay đổi của d1 cũng xuất hiện trên d2"
            },
            {
              "icon": "",
              "label": "Một TypeError — các thể hiện không thể nối vào một thuộc tính lớp"
            },
            {
              "icon": "",
              "label": "['sit'] chỉ sau khi d2 = Dog() được chạy lại"
            }
          ]
        },
        {
          "question": "class A có def greet(self): return 'A'. class B(A) có def greet(self): return 'B' + super().greet(). Điều gì làm cho B().greet() trả về?",
          "options": [
            {
              "icon": "",
              "label": "'AB' — super() luôn chạy trước mã của riêng lớp con"
            },
            {
              "icon": "",
              "label": "'B' — super().greet() bị bỏ qua vì B đã ghi đè greet"
            },
            {
              "icon": "",
              "label": "'BA' — super().greet() gọi phương thức của A và kết quả của nó được nối với 'B'"
            },
            {
              "icon": "",
              "label": "Một AttributeError, vì A không có phương thức greet có thể nhìn thấy cho B"
            }
          ]
        },
        {
          "question": "class Point lưu trữ self.x trong __init__ và không xác định các phương thức khác. p1 = Point(1) và p2 = Point(1). Điều gì làm cho p1 == p2 trả về theo mặc định?",
          "options": [
            {
              "icon": "",
              "label": "True — Python so sánh tất cả các thuộc tính khớp theo mặc định"
            },
            {
              "icon": "",
              "label": "False — mà không có __eq__ tùy chỉnh, == quay lại so sánh nhận dạng, và p1 và p2 là các đối tượng khác nhau"
            },
            {
              "icon": "",
              "label": "True, nhưng chỉ vì cả hai đối tượng được tạo bằng cùng một đối số"
            },
            {
              "icon": "",
              "label": "Một TypeError, vì Point không xác định __eq__"
            }
          ]
        },
        {
          "question": "Cái nào trong số này except mệnh đề cũng sẽ bắt lỗi ZeroDivisionError: except ArithmeticError, except ValueError, hoặc except KeyError?",
          "options": [
            {
              "icon": "",
              "label": "except ValueError — lỗi chia được coi là giá trị không hợp lệ"
            },
            {
              "icon": "",
              "label": "except KeyError — bất kỳ lỗi runtime nào không bị ràng buộc với một loại cụ thể đều quay lại KeyError"
            },
            {
              "icon": "",
              "label": "Không — chỉ except ZeroDivisionError tự nó mới có thể bắt nó"
            },
            {
              "icon": "",
              "label": "except ArithmeticError — ZeroDivisionError là một lớp con của ArithmeticError"
            }
          ]
        },
        {
          "question": "Bạn mở một tệp với open('data.txt') as f: và một ngoại lệ được tăng trong khi đọc bên trong khối. Tệp có còn được đóng không?",
          "options": [
            {
              "icon": "",
              "label": "Không — tệp vẫn mở vì khối không hoàn thành bình thường"
            },
            {
              "icon": "",
              "label": "Chỉ nếu bạn cũng thêm một mệnh đề finally xung quanh câu lệnh with"
            },
            {
              "icon": "",
              "label": "Có — câu lệnh with gọi phương thức __exit__ của tệp, đóng nó, ngay cả khi một ngoại lệ xảy ra bên trong khối"
            },
            {
              "icon": "",
              "label": "Nó phụ thuộc vào loại ngoại lệ — chỉ những ngoại lệ được bắt ở nơi khác kích hoạt dọn dẹp"
            }
          ]
        },
        {
          "question": "x = [3, 1, 2] và y = x.sort(). Điều gì làm cho y giữ?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3] — sort() trả về danh sách được sắp xếp mới"
            },
            {
              "icon": "",
              "label": "None — list.sort() sắp xếp tại chỗ và trả về None; x tự nó trở thành [1, 2, 3]"
            },
            {
              "icon": "",
              "label": "[3, 1, 2] — sort() trả về danh sách không được sắp xếp aslinya và chỉ thay đổi thứ tự nội bộ của x"
            },
            {
              "icon": "",
              "label": "Một TypeError, vì sort() không thể được gán cho một biến"
            }
          ]
        },
        {
          "question": "Điều gì sẽ xảy ra khi bạn chạy 'Score: ' + 42?",
          "options": [
            {
              "icon": "",
              "label": "\"'Score: 42'\" — Python chuyển đổi số tự động bên trong một biểu thức +"
            },
            {
              "icon": "",
              "label": "\"'Score: '\" — số được yên tĩnh bỏ qua"
            },
            {
              "icon": "",
              "label": "42 — chuỗi được ép buộc thành một số và thêm vào"
            },
            {
              "icon": "",
              "label": "TypeError — bạn không thể nối một str và một int trực tiếp, 42 phải được chuyển đổi với str() trước tiên"
            }
          ]
        },
        {
          "question": "Bạn cần kiểm tra xem một danh sách được gọi là results có trống không. Cách nào là cách thuần Python: if results == []: , if len(results) == 0: , hoặc if not results: ?",
          "options": [
            {
              "icon": "",
              "label": "if results == []: — đây là cách duy nhất đáng tin cậy để phát hiện một danh sách trống"
            },
            {
              "icon": "",
              "label": "if len(results) == 0: — điều này được yêu cầu vì danh sách trống là thật trong Python"
            },
            {
              "icon": "",
              "label": "Cả ba đều không bao giờ được sử dụng trong thực tế; cách tiếp cận tiêu chuẩn là if results is None:"
            },
            {
              "icon": "",
              "label": "if not results: — thành ngữ Python dựa trên tính thật, và một danh sách trống là giả"
            }
          ]
        }
      ],
      "optionOrderVersion": "92945565db6c55da"
    }
  }
}
