{
  "assessmentTests": {
    "python_test": {
      "name": "Python 测试",
      "desc": "30 道关于语法、函数、数据结构和对象行为的场景题 — 判断你对 Python 的理解是否与职位要求的 Python 工作能力相符。",
      "recommendation": "你的 Python 技能概览",
      "results": {
        "beginner": {
          "name": "初级",
          "desc": "你能读懂一个短脚本，改改里面的数值，但你错的题往往涉及 Python 特有的行为，而不是通用编程逻辑 — 比如默认参数只构建一次还是重用，is 和 == 对两个看起来一样的列表有什么不同，或者在函数里只要你对某个变量赋值，它就变成局部变量。这些都不是说你编程能力不行；这些是 Python 特有的规则，从其他语言转过来的人或初学者都容易踩坑。在工作中很重要，因为每一个这样的坑都是代码乍一看没问题但其实有 bug 的地方。",
          "recommendation": "先集中学三样东西，按这个顺序：可变的默认参数（为什么 basket=[] 很危险）、is 和 == 的区别、以及函数内变量作用域怎么工作。Python 官方文档 docs.python.org 直接讲了这三个，搜「Python gotchas」能找到大量讲解和例子。"
        },
        "intermediate": {
          "name": "中级",
          "desc": "你日常脚本写得很顺手 — 数据结构、控制流、直白的函数 — 日常维护工作或在现有代码库上加小功能不会有什么压力。从这里到高级的差距主要是 Python 便利特性互相作用时会发生什么：浅拷贝会留下嵌套数据共享（本以为是复制了），生成器的返回值悄悄不成为输出的一部分，装饰器堆叠顺序容易搞反。这些是资深审查员十秒钟就能指出、其他人要花一小时追的 bug。",
          "recommendation": "专注对象和迭代的内部机制：浅拷贝和深拷贝、生成器的 return 真正做什么、装饰器堆叠顺序怎么工作。然后学类的基础知识，很多教程跳过了 — 没有自定义 __eq__ 的默认相等性，为什么一个可变的类属性会在所有实例间共享。"
        },
        "advanced": {
          "name": "高级",
          "desc": "这是大多数职位招聘信息说的「熟练 Python」的等级。你知道该用哪个工具不用费力翻，你清楚为什么某块共享状态会变，不只是知道它变了；读别人的函数能正确预判它的输出。从这个等级到顶部的差别在防守工作：知道哪种看起来正确的做法一旦涉及类属性、只能传关键字的参数或异常继承体系就会出问题。",
          "recommendation": "深入那些保护别人也要动的代码库的东西：关键字唯一参数作为 API 设计选择而不只是语法怪癖、异常继承体系（这样 except 子句才能捕住正确的错误族，不只是一个类）、上下文管理器作为保证清理的标准方式。Real Python 的深度文章对这三个都是很好的下一步。"
        },
        "expert": {
          "name": "专家",
          "desc": "你在每一部分都拿了高分 — 核心语法、函数和作用域、数据结构、对象编程习语。实际上这意味着你可以被丢进陌生人的代码文件，解释为什么它产生那个输出，而不只是语法说它应该产生什么 — 这才是难的、更有价值的技能。在这个等级，原生语言很少是你工作的限制因子；限制通常来自你周围系统的规模和形状。",
          "recommendation": "收益现在来自工具和审查：用 mypy 或 pyright 做静态类型检查，在优化前先做性能分析而不是猜，读别人的 pull request 找的就是这一类 bug — 通过了所有测试但在特定输入下还是做错事的。如果你在竞聘某个职位，讲一个你找到的这样的 bug，而不是只列语言特性 — 这展示的是你的推理能力，不只是词汇。"
        }
      },
      "questions": [
        {
          "question": "你写 def add_item(item, basket=[]): basket.append(item); return basket，然后调用 add_item('a') 和 add_item('b')，两次都不传 basket 参数。第二次调用返回什么？",
          "options": [
            {
              "icon": "",
              "label": "['b'] — 每次调用都会得到一个新的空列表作为默认值"
            },
            {
              "icon": "",
              "label": "TypeError — 你必须提供 basket 参数"
            },
            {
              "icon": "",
              "label": "['a', 'b'] — 默认列表只构建一次，在各次调用间被重用"
            },
            {
              "icon": "",
              "label": "['a'] 然后 ['b'] 作为两个独立的单项列表"
            }
          ]
        },
        {
          "question": "a = [1, 2, 3] 和 b = [1, 2, 3]。a == b 返回什么，a is b 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "都返回 True — 内容相同的列表永远是同一个对象"
            },
            {
              "icon": "",
              "label": "== 返回 True，is 返回 False — 内容相等但在内存中是不同的对象"
            },
            {
              "icon": "",
              "label": "都返回 False — Python 中分开的字面量永远不相等"
            },
            {
              "icon": "",
              "label": "is 返回 True，== 返回 False — is 检查列表的值相等性"
            }
          ]
        },
        {
          "question": "在 Python 3 中，7 / 2 计算为多少，7 // 2 计算为多少？",
          "options": [
            {
              "icon": "",
              "label": "3.5，然后 3 — / 总是返回浮点数，// 对结果向下取整"
            },
            {
              "icon": "",
              "label": "3，然后 3.5 — / 截断，// 返回浮点数"
            },
            {
              "icon": "",
              "label": "3.5，然后 3.5 — 两个运算符在 Python 3 中都返回浮点数"
            },
            {
              "icon": "",
              "label": "3，然后 3 — 两个运算符在 Python 3 中都向下取整"
            }
          ]
        },
        {
          "question": "s = 'hello'，然后你运行 s[0] = 'H'。会发生什么？",
          "options": [
            {
              "icon": "",
              "label": "s 变成 'Hello'"
            },
            {
              "icon": "",
              "label": "s 变成 'Hhello'，因为字符被插入了而不是替换了"
            },
            {
              "icon": "",
              "label": "TypeError — 字符串是不可变的，不支持项赋值"
            },
            {
              "icon": "",
              "label": "什么都不发生 — 赋值被默默忽略，s 还是 'hello'"
            }
          ]
        },
        {
          "question": "x = [10, 20, 30, 40, 50]。x[1:4] 返回什么？",
          "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' 和 age = 30。f'{name} is {age}' 产生什么？",
          "options": [
            {
              "icon": "",
              "label": "{name} is {age}"
            },
            {
              "icon": "",
              "label": "Ana is 30"
            },
            {
              "icon": "",
              "label": "name is age"
            },
            {
              "icon": "",
              "label": "TypeError，因为 f 字符串需要 format() 方法"
            }
          ]
        },
        {
          "question": "1 < 2 < 3 计算为什么？",
          "options": [
            {
              "icon": "",
              "label": "True — Python 会把比较链式处理为 (1 < 2) and (2 < 3)"
            },
            {
              "icon": "",
              "label": "False — 链式比较从左到右计算，不短路，给出 1 < 2 < 3 -> 1 < True -> False"
            },
            {
              "icon": "",
              "label": "SyntaxError — 比较不能链式"
            },
            {
              "icon": "",
              "label": "3 — Python 返回链中最后的值"
            }
          ]
        },
        {
          "question": "bool([]) 返回什么，bool([0]) 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "都是 False — 任何只包含假值的列表都是假的"
            },
            {
              "icon": "",
              "label": "False，然后 True — 空列表是假，包含一个元素的列表（即使是 0）是真"
            },
            {
              "icon": "",
              "label": "都是 True — 非 None 对象总是真的"
            },
            {
              "icon": "",
              "label": "True，然后 False — 列表只在为空时是真的"
            }
          ]
        },
        {
          "question": "有一个模块级 count = 0。在 def increment(): count += 1; return count 内，你调用 increment()。会发生什么？",
          "options": [
            {
              "icon": "",
              "label": "UnboundLocalError — 在函数内任何地方对 count 赋值都会使它变成局部的，所以 count += 1 试图读一个赋值前的局部变量"
            },
            {
              "icon": "",
              "label": "返回 1 并把模块级 count 增到 1"
            },
            {
              "icon": "",
              "label": "返回 1 但模块级 count 还是 0"
            },
            {
              "icon": "",
              "label": "NameError，因为 count 从未在函数内声明"
            }
          ]
        },
        {
          "question": "def f(*args, **kwargs): return args, kwargs。f(1, 2, x=3) 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "([1, 2], {'x': 3})"
            },
            {
              "icon": "",
              "label": "((1, 2), {'x': 3})"
            },
            {
              "icon": "",
              "label": "(1, 2, {'x': 3})"
            },
            {
              "icon": "",
              "label": "TypeError — 位置参数和关键字参数不能在一次调用中混用"
            }
          ]
        },
        {
          "question": "你用一个循环构建 funcs = [lambda: i for i in range(3)]。[f() for f in funcs] 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "[2, 2, 2] — 每个 lambda 在被调用时查找 i，此时循环已结束，i 等于 2"
            },
            {
              "icon": "",
              "label": "[0, 1, 2] — 每个 lambda 在创建时捕获 i 的值"
            },
            {
              "icon": "",
              "label": "[0, 0, 0] — lambda 总是捕获分配给变量的第一个值"
            },
            {
              "icon": "",
              "label": "NameError，因为一旦循环结束 i 就不存在了"
            }
          ]
        },
        {
          "question": "一个函数定义上方有 @a，@b 直接在它上方，def f(): pass 在 @b 下面。装饰器按什么顺序应用到 f？",
          "options": [
            {
              "icon": "",
              "label": "b 先包装 f，然后 a 包装 b 的结果 — 离函数最近的装饰器先运行"
            },
            {
              "icon": "",
              "label": "a 先包装 f，然后 b 包装结果 — 装饰器从上到下应用"
            },
            {
              "icon": "",
              "label": "两个装饰器独立包装 f，只有最后定义的起作用"
            },
            {
              "icon": "",
              "label": "取决于装饰器的导入顺序，不是它们在代码中的位置"
            }
          ]
        },
        {
          "question": "def f(a, *, b): return a + b。这些调用中哪个工作？",
          "options": [
            {
              "icon": "",
              "label": "f(1, b=2) — b 必须以关键字传，因为它在签名中的 * 后面"
            },
            {
              "icon": "",
              "label": "f(1, 2) — 位置参数从左到右填充参数，不管 * 怎样"
            },
            {
              "icon": "",
              "label": "f(a=1, 2) — 关键字参数必须先来"
            },
            {
              "icon": "",
              "label": "f(1) — b 是可选的因为它在 * 后面"
            }
          ]
        },
        {
          "question": "一个生成器函数 yield 1，然后 yield 2，然后 return 99。list(the_generator()) 包含什么，99 怎么处理？",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 99] — 生成器内的 return 行为像再 yield 一次"
            },
            {
              "icon": "",
              "label": "[99] — return 立即覆盖已 yield 的任何值"
            },
            {
              "icon": "",
              "label": "[1, 2] — 生成器的返回值变成它引发的 StopIteration 上附加的值，不是被 yield"
            },
            {
              "icon": "",
              "label": "RuntimeError，因为生成器不能包含 return 语句"
            }
          ]
        },
        {
          "question": "在 outer() 函数内，x = 1 被设置，然后嵌套的 inner() 做 nonlocal x; x += 1，outer() 在返回 x 前调用 inner()。outer() 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "1 — inner() 操作 x 的自己的局部副本，改动不持久"
            },
            {
              "icon": "",
              "label": "UnboundLocalError，因为 x 在 nonlocal 语句前没在 inner() 内声明"
            },
            {
              "icon": "",
              "label": "SyntaxError — nonlocal 只能在类内用"
            },
            {
              "icon": "",
              "label": "2 — nonlocal 让 inner() 修改外层函数的 x 而不是创建新局部变量"
            }
          ]
        },
        {
          "question": "d = {'a': 1, 'b': 2}。d.get('c', 0) 返回什么，它会把 'c' 加到字典吗？",
          "options": [
            {
              "icon": "",
              "label": "0，不会 — get() 返回默认值而不插入键"
            },
            {
              "icon": "",
              "label": "0，会 — get() 用默认值插入键"
            },
            {
              "icon": "",
              "label": "KeyError，因为 'c' 不存在"
            },
            {
              "icon": "",
              "label": "None，会 — get() 总是用 None 值加入缺失的键"
            }
          ]
        },
        {
          "question": "t = (1, 2, [3, 4])。你能运行 t[2].append(5) 吗，你能运行 t[0] = 10 吗？",
          "options": [
            {
              "icon": "",
              "label": "都工作 — 在元组内嵌套列表会使整个元组可变"
            },
            {
              "icon": "",
              "label": "都引发 TypeError — 元组内任何东西永远不能改变"
            },
            {
              "icon": "",
              "label": "t[2].append(5) 引发 TypeError，但 t[0] = 10 工作因为元组允许重新赋值首元素"
            },
            {
              "icon": "",
              "label": "t[2].append(5) 工作因为列表是可变的；t[0] = 10 引发 TypeError 因为元组本身不可变"
            }
          ]
        },
        {
          "question": "这两个中哪个返回一个惰性计算值的迭代器而不是把整个序列构建到内存中：[x*x for x in range(1000000)] 还是 (x*x for x in range(1000000))？",
          "options": [
            {
              "icon": "",
              "label": "括号那个，(x*x for x in range(1000000)) — 那是生成器表达式"
            },
            {
              "icon": "",
              "label": "方括号那个 — 列表推导在 Python 3 中总是惰性的"
            },
            {
              "icon": "",
              "label": "都是惰性的 — 唯一区别是最后返回的类型"
            },
            {
              "icon": "",
              "label": "都不是 — 两个都立即把完整序列构建到内存中"
            }
          ]
        },
        {
          "question": "一个 try 块除以零，except ZeroDivisionError 子句打印 'a'，finally 子句打印 'b'。打印什么和什么顺序？",
          "options": [
            {
              "icon": "",
              "label": "b 然后 a — finally 总是在任何 except 子句前运行"
            },
            {
              "icon": "",
              "label": "a 然后 b — 匹配的 except 先运行，finally 总是之后不管怎样"
            },
            {
              "icon": "",
              "label": "只有 b — 异常没被真的捕获，所以 'a' 从不打印"
            },
            {
              "icon": "",
              "label": "只有 a — 异常被处理后 finally 被跳过"
            }
          ]
        },
        {
          "question": "import copy; a = [[1, 2], [3, 4]]; b = copy.copy(a); b[0].append(99)。a[0] 也变了吗？",
          "options": [
            {
              "icon": "",
              "label": "不会 — copy.copy() 总是也复制嵌套对象"
            },
            {
              "icon": "",
              "label": "不会 — 向 b[0] append 为 b[0] 创建了一个全新的列表"
            },
            {
              "icon": "",
              "label": "会，但只因为 copy.copy() 被调用时没有 deepcopy 参数"
            },
            {
              "icon": "",
              "label": "会 — copy.copy() 做浅拷贝，所以嵌套列表在 a 和 b 间还是共享的"
            }
          ]
        },
        {
          "question": "d = {'x': 1, 'y': 2}。'x' in d 检查什么 — 键、值还是都检查？",
          "options": [
            {
              "icon": "",
              "label": "值 — `in` 检查 1 或 2 是否等于 'x'"
            },
            {
              "icon": "",
              "label": "键和值都检查"
            },
            {
              "icon": "",
              "label": "都不是 — 在字典上的 `in` 总是引发 TypeError"
            },
            {
              "icon": "",
              "label": "键 — 在字典上的 `in` 测试键的成员关系，不是值"
            }
          ]
        },
        {
          "question": "names = ['Al', 'Bo'] 和 scores = [10, 20]。list(zip(names, scores)) 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "[('Al', 'Bo'), (10, 20)]"
            },
            {
              "icon": "",
              "label": "['Al', 10, 'Bo', 20]"
            },
            {
              "icon": "",
              "label": "[('Al', 10), ('Bo', 20)]"
            },
            {
              "icon": "",
              "label": "ValueError，因为 zip 需要三个或更多参数"
            }
          ]
        },
        {
          "question": "class Dog: tricks = [] 有一个类级列表，add_trick append 到 self.tricks。d1 = Dog() 和 d2 = Dog() 都被创建，然后 d1.add_trick('sit') 运行。d2.tricks 包含什么？",
          "options": [
            {
              "icon": "",
              "label": "[] — 每个实例有自己独立的 tricks 副本"
            },
            {
              "icon": "",
              "label": "['sit'] — tricks 是每个实例共享的类级列表，所以 d1 的改动在 d2 上也看得见"
            },
            {
              "icon": "",
              "label": "TypeError — 实例不能 append 到类属性"
            },
            {
              "icon": "",
              "label": "['sit'] 只在 d2 = Dog() 重新运行后"
            }
          ]
        },
        {
          "question": "class A 有 def greet(self): return 'A'。class B(A) 有 def greet(self): return 'B' + super().greet()。B().greet() 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "'AB' — super() 总是在子类自己的代码前运行"
            },
            {
              "icon": "",
              "label": "'B' — super().greet() 被忽略因为 B 已经覆盖了 greet"
            },
            {
              "icon": "",
              "label": "'BA' — super().greet() 调用 A 的方法，其结果 append 到 'B'"
            },
            {
              "icon": "",
              "label": "AttributeError，因为 A 对 B 没有可见的 greet 方法"
            }
          ]
        },
        {
          "question": "class Point 在 __init__ 中存储 self.x，不定义其他方法。p1 = Point(1) 和 p2 = Point(1)。默认情况下 p1 == p2 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "True — Python 默认比较所有匹配的属性"
            },
            {
              "icon": "",
              "label": "False — 没有自定义 __eq__，== 回退到身份比较，p1 和 p2 是不同对象"
            },
            {
              "icon": "",
              "label": "True，但只因为两个对象用相同参数创建"
            },
            {
              "icon": "",
              "label": "TypeError，因为 Point 不定义 __eq__"
            }
          ]
        },
        {
          "question": "下面哪个 except 子句也会捕获 ZeroDivisionError：except ArithmeticError、except ValueError 还是 except KeyError？",
          "options": [
            {
              "icon": "",
              "label": "except ValueError — 除法错误被当作无效值"
            },
            {
              "icon": "",
              "label": "except KeyError — 任何特定类型无关的运行时错误都回退到 KeyError"
            },
            {
              "icon": "",
              "label": "都不是 — 只有 except ZeroDivisionError 本身能捕获它"
            },
            {
              "icon": "",
              "label": "except ArithmeticError — ZeroDivisionError 是 ArithmeticError 的子类"
            }
          ]
        },
        {
          "question": "你用 open('data.txt') as f: 打开文件，块内读取时引发异常。文件还是会关闭吗？",
          "options": [
            {
              "icon": "",
              "label": "不会 — 因为块没有正常结束，文件保持打开"
            },
            {
              "icon": "",
              "label": "只有在你也在 with 语句周围加 finally 子句时才会"
            },
            {
              "icon": "",
              "label": "会 — with 语句调用文件的 __exit__ 方法关闭它，即使块内发生异常"
            },
            {
              "icon": "",
              "label": "取决于异常类型 — 只有被其他地方捕获的异常才触发清理"
            }
          ]
        },
        {
          "question": "x = [3, 1, 2] 和 y = x.sort()。y 包含什么？",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3] — sort() 返回新排序的列表"
            },
            {
              "icon": "",
              "label": "None — list.sort() 原地排序并返回 None；x 本身变成 [1, 2, 3]"
            },
            {
              "icon": "",
              "label": "[3, 1, 2] — sort() 返回原始未排序列表，只改变 x 的内部顺序"
            },
            {
              "icon": "",
              "label": "TypeError，因为 sort() 不能赋值给变量"
            }
          ]
        },
        {
          "question": "当你运行 'Score: ' + 42 时会发生什么？",
          "options": [
            {
              "icon": "",
              "label": "'Score: 42' — Python 在 + 表达式内自动转换数字"
            },
            {
              "icon": "",
              "label": "'Score: ' — 数字被默默丢弃"
            },
            {
              "icon": "",
              "label": "42 — 字符串被强制转成数字并相加"
            },
            {
              "icon": "",
              "label": "TypeError — 你不能直接拼接 str 和 int，42 必须先用 str() 转换"
            }
          ]
        },
        {
          "question": "你需要检查一个叫 results 的列表是否为空。地道的 Python 方式是什么：if results == []: 、if len(results) == 0: 还是 if not results: ？",
          "options": [
            {
              "icon": "",
              "label": "if results == []: — 这是检测空列表的唯一可靠方式"
            },
            {
              "icon": "",
              "label": "if len(results) == 0: — 这是必需的因为空列表在 Python 中是真的"
            },
            {
              "icon": "",
              "label": "三个在实践中从不用；标准方法是 if results is None:"
            },
            {
              "icon": "",
              "label": "if not results: — Python 习语依赖真假性，空列表是假的"
            }
          ]
        }
      ],
      "optionOrderVersion": "92945565db6c55da"
    }
  }
}
