107 lines
4.5 KiB
Markdown
107 lines
4.5 KiB
Markdown
一、选择题
|
||
1. B 2. B 3. B 4. B 5. B 6. B 7. B 8. B 9. B 10. B
|
||
每题思路
|
||
1. `[1, 2]` —— 可变默认参数:`def f(x, lst=[])` 里的 `[]` 只在函数定义时创建一次,之后所有调用共用同一个列表。`f(1)` 后是 `[1]`,`f(2)` 再 append 2 变成 `[1, 2]`。
|
||
|
||
2. `[1, 2, 3, 4] [1, 2, 3]` —— `b = a` 是别名(指向同一列表),`c = a.copy()` 是复制出的新列表。`a.append(4)` 改的是 a/b 共用的列表,所以 b 变、c 不变。
|
||
|
||
3. 输出 A 和 C —— 出错走 `except` 打印 A;`else` 只在没出错时执行(这里出错,跳过);`finally` 一定执行打印 C。
|
||
|
||
4. `7 5` —— `" hello "` 是 1 空格 + 5 字母 + 1 空格 = 7 个字符;`strip()` 去掉首尾空格后 `"hello"` 长 5。
|
||
|
||
5. 只输出 end —— for 循环被 `break` 打断时,`else` 不执行,所以 `done` 不打印,只执行循环外的 `end`。
|
||
|
||
6. `Rex: woof` —— Dog 继承了 Animal 的 `__init__`,又重写了 `speak()`,所以 `d.speak()` 调用 Dog 版本,打印 `Rex: woof`。
|
||
|
||
7. `{'b': 2}` —— 字典推导式 `{k: v for k, v in d.items() if v > 1}` 只保留 `v > 1` 的项,只有 `"b": 2` 满足。
|
||
|
||
8. `<class 'str'>` —— `json.dumps()` 把字典序列化成 JSON 字符串,所以结果是 str。
|
||
|
||
9. 只输出 6 —— `f(5)` 单独一行返回了 6 但没打印,无输出;`print(f(5))` 才打印 6,所以只有一行 6。
|
||
|
||
10. get() 返回 None,[] 抛 KeyError —— `user.get("city")` 键不存在返回 None(不报错),`user["city"]` 键不存在抛 KeyError。
|
||
|
||
二、简答题
|
||
|
||
第 1 题:浅拷贝与深拷贝
|
||
|
||
```python
|
||
a = [[1, 2], [3, 4]]
|
||
b = a.copy()
|
||
import copy
|
||
c = copy.deepcopy(a)
|
||
```
|
||
|
||
三者关系:
|
||
|
||
- `a`:原列表 `[[1, 2], [3, 4]]`
|
||
- `b = a.copy()`:浅拷贝,外层列表是新的,但内层列表还是和 a 共享的同一个对象(`b[0] is a[0]` 为 True)
|
||
- `c = copy.deepcopy(a)`:深拷贝,外层、内层全是独立的新对象(`c[0] is a[0]` 为 False)
|
||
|
||
执行 `a[0].append(99)` 后:
|
||
|
||
- `b` → `[[1, 2, 99], [3, 4]]`(因为 b[0] 和 a[0] 是同一个内层列表,一起变了)
|
||
- `c` → `[[1, 2], [3, 4]]`(c 的内层是独立副本,不受影响)
|
||
|
||
原因:浅拷贝只复制最外层容器,内部元素仍是引用(指向同一对象);深拷贝会递归复制每一层,得到完全独立的对象。
|
||
|
||
第 2 题:字典与列表的综合应用
|
||
|
||
```python
|
||
logs = [
|
||
{"user": "张三", "action": "login", "level": "INFO"},
|
||
{"user": "李四", "action": "logout", "level": "INFO"},
|
||
{"user": "张三", "action": "error", "level": "ERROR"},
|
||
{"user": "王五", "action": "login", "level": "INFO"},
|
||
{"user": "李四", "action": "error", "level": "ERROR"},
|
||
]
|
||
```
|
||
|
||
找出所有 level 为 "ERROR" 的日志:
|
||
|
||
```python
|
||
error_logs = [log for log in logs if log["level"] == "ERROR"]
|
||
# [{'user': '张三', 'action': 'error', 'level': 'ERROR'},
|
||
# {'user': '李四', 'action': 'error', 'level': 'ERROR'}]
|
||
```
|
||
|
||
统计每个用户出现几次:
|
||
|
||
```python
|
||
user_count = {}
|
||
for log in logs:
|
||
user = log["user"]
|
||
user_count[user] = user_count.get(user, 0) + 1
|
||
# {'张三': 2, '李四': 2, '王五': 1}
|
||
```
|
||
|
||
也可以用 `collections.Counter` 一行完成:`Counter(log["user"] for log in logs)`。
|
||
|
||
为什么不能用 len(logs):`len(logs)` 只返回日志的总条数(这里是 5),它不做任何分类统计。要按用户分别计数,必须用一个 for 循环逐条遍历 logs,取出每条里的 `"user"` 字段,再用字典以用户名为键累加次数。所以需要的是「for 遍历 + 字典累加」这种结构,而不是一个 `len()`。
|
||
|
||
第 3 题:异常处理设计
|
||
|
||
函数代码:
|
||
|
||
```python
|
||
def safe_divide(a, b):
|
||
try:
|
||
return float(a) / float(b)
|
||
except (ValueError, ZeroDivisionError):
|
||
return None
|
||
```
|
||
|
||
说明:
|
||
|
||
- `float(a)`、`float(b)` 把字符串转成数字,转不了会抛 ValueError;
|
||
- b 是 "0" 时 `float(b)` 为 0.0,做除法抛 ZeroDivisionError;
|
||
- 两种异常在同一个 except 里捕获,统一返回 None。
|
||
|
||
为什么用 try/except 比先用 if 判断更好:
|
||
|
||
- 避免重复转换:用 if 先判断"能不能转",得先试转一次确认、再转一次真正计算,等于转两遍;try/except 直接转,失败就捕获。
|
||
- 一个 try 块覆盖多个出错点:a 转失败、b 转失败、除数为零,if 要写一串嵌套判断,try 一个块全包住。
|
||
- 更符合 Python 的 EAFP 风格(先做、出错再补救),比 LBYL(先判断再执行)更简洁健壮。
|
||
|
||
|