PY期末

代码题

第二类“代码分析题”不要按概念题背定义,而要按读代码模板准备。你上次看不懂题,很大一部分是因为中文术语没有翻译成代码动作。所以现在重点不是“Python 会不会”,而是:

看到“实例属性、类属性、私有成员、类方法、静态方法、继承、重载、生成器、上下文管理、断言、异常处理”等术语时,能立刻知道它对应哪种代码写法、哪种错误、哪种输出。

根据你这份资料,第二类题最高优先级是:

  1. OOP 代码分析class_instance.pyclass_inherit.pyABC.pyMyArray.py
  2. 函数代码分析:可变参数、默认参数、返回值、作用域、lambda、yield
  3. 容器/字符串代码分析:列表切片、sort/sorted、字典 get/pop、字符串方法、正则
  4. 文件与异常with open()、编码转换、try/except/finally、assert

一、代码分析题应该怎么做

拿到一段代码,固定按这个顺序看。

1. 先判断:代码能不能运行

优先找这些错误:

错误类型 常见触发
SyntaxError 语法错,括号/冒号/缩进/参数顺序错
NameError 变量名没定义
AttributeError 对象没有这个属性/方法
TypeError 参数个数错、类型不支持、类方法调用方式错
IndexError 列表下标越界
KeyError 字典键不存在
ValueError 类型转换失败,如 int('abc')
FileNotFoundError 读文件但文件不存在
UnicodeEncodeError/DecodeError 编码/解码方式不匹配

你的资料里非常容易考 AttributeErrorTypeError,尤其是 OOP。


2. 再判断:程序执行顺序

重点看:

if __name__ == "__main__":
    ...

如果脚本直接运行__name__ == "__main__" 成立;如果被其他文件 import__name__ 是模块名。

所以代码分析题可能问:

为什么导入模块时某些代码没有执行?

答案就是:被 if __name__ == "__main__": 控制住了。


3. 再判断:变量到底指向谁

Python 变量本质是“名字绑定对象”。

重点区分:

x = [1, 2, 3]
y = x
y.append(4)
print(x)

输出:

[1, 2, 3, 4]

因为 xy 指向同一个列表对象。

但:

x = [1, 2, 3]
y = x.copy()
y.append(4)
print(x)

输出:

[1, 2, 3]

因为 copy() 产生了新列表。

第二类题很喜欢考这种“是不是原地修改”。


4. OOP 代码按“属性查找顺序”分析

这是最重要的。

对象访问属性时,大致按:

先找对象自己的实例属性
找不到,再找类属性
再找父类属性
还找不到,AttributeError

例如你资料里的 class_instance.py

class DemoClass:
    class_attr = "Original Class Attribute"

    def __init__(self, value):
        self.inst_attr = value

这里:

DemoClass.class_attr

可以,因为 class_attr 是类属性。

但:

DemoClass.inst_attr

会报错:

AttributeError

因为 inst_attr 是在 __init__() 里通过 self.inst_attr 创建的,它属于具体实例,不属于类本身。

正确访问:

obj = DemoClass("Original Instance Attribute")
print(obj.inst_attr)

二、必须掌握的中文术语翻译

你上次机试看不懂题,主要就是这些术语。

1. OOP 高频术语

中文术语 代码含义 看到题目时应该想到
class A: 模板,不是具体对象
对象/实例 a = A() 由类创建出来的具体东西
实例化 A() 调用类,创建对象
实例属性 self.x = ... 每个对象自己有一份
类属性 写在类内部、方法外部 类共享,可以 类名.属性 访问
成员 属性 + 方法 类里面定义的东西
数据成员/成员属性 变量形式的成员 self.nameClass.price
成员方法 函数形式的成员 def show(self):
公有成员 普通名字,如 name 类内类外都能正常访问
私有成员 __name 类外不能直接 obj.__name
受保护成员 _name 约定不直接访问,但 Python 不强制
特殊成员 __xxx__ 系统约定,如 __init__
实例方法 def f(self): 通过对象调用,自动传 self
静态方法 @staticmethod 不需要 self/cls
类方法 @classmethod 第一个参数通常是 cls
构造方法 __init__() 创建对象时自动调用
析构方法 __del__() 对象释放时调用
继承 class B(A): B 复用 A 的属性和方法
*类/父类/超类 被继承的类 A
子类/派生类 继承别人的类 B
方法覆盖/重写 子类重新定义父类同名方法 多态常靠它实现
多态 同一个方法名,不同对象表现不同 item.show() 输出不同
运算符重载 重写特殊方法 __add__ 对应 +
抽象超类/抽象*类 ABC 不能直接实例化,子类必须实现抽象方法

2. 私有成员是重点

资料里的说法是:

私有成员名以两个下划线 __ 开头,类外不能直接访问,但可以通过特殊方式访问。

例如:

class A:
    def __init__(self):
        self.__value = 3

a = A()
print(a.__value)

报错:

AttributeError

但可以:

print(a._A__value)

因为 Python 会把:

__value

改名为:

_A__value

所以题目说:

在类外通过对象 a 访问类 A 的私有成员 __value

你就写:

a._A__value

如果题目说“设置为 3”:

a._A__value = 3

3. 类属性 vs 实例属性

这是最容易出代码分析题的地方。

class Car:
    price = 100000

    def __init__(self, color):
        self.color = color

car1 = Car("Red")
car2 = Car("Blue")

这里:

Car.price
car1.price
car2.price

都能访问,因为 price 是类属性。

但:

Car.color

报错,因为 color 是实例属性。

如果:

car1.price = 200000

这不是修改类属性,而是给 car1 新增了一个实例属性 price,遮蔽了类属性。

之后:

print(car1.price)  # 200000
print(car2.price)  # 100000
print(Car.price)   # 100000

4. 实例方法、类方法、静态方法

实例方法

class A:
    def show(self):
        print("show")

a = A()
a.show()

对象调用时,自动把 a 传给 self

也可以:

A.show(a)

但不能:

A.show()

因为缺少 self,会报 TypeError


静态方法

class A:
    @staticmethod
    def show():
        print("static")

可以:

A.show()
a = A()
a.show()

不需要 self


类方法

class A:
    value = 10

    @classmethod
    def show(cls):
        print(cls.value)

可以:

A.show()
a = A()
a.show()

第一个参数 cls 自动接收“类对象”。


三、根据资料,第二类代码题最可能怎么考

1. class_instance.py:类属性/实例属性/方法调用

可能考法:

print(DemoClass.inst_attr)

问:是否报错?为什么?

答案:

报 AttributeError。inst_attr 是在 __init__() 中通过 self.inst_attr 定义的实例属性,只属于具体对象 obj,不属于类 DemoClass,不能通过 DemoClass.inst_attr 访问。

正确写法:

obj = DemoClass("value")
print(obj.inst_attr)

2. ABC.py:抽象*类

资料里有:

class Shape(ABC):
    @abstractmethod
    def get_area(self):
        pass

可能考法:

shape = Shape()

问:为什么错?

答案:

Shape 是抽象超类/抽象*类,含有抽象方法,不能直接实例化。

又如:

class BadRectangle(Shape):
    def get_area(self):
        return self.width * self.height

如果没有实现 get_perimeter(),也不能实例化。

正确子类必须实现所有抽象方法:

class Circle(Shape):
    def get_area(self):
        ...

    def get_perimeter(self):
        ...

3. class_inherit.py:继承和 super()

资料里有两种调用父类构造方法:

Person.__init__(self, name)

和:

super().__init__(name)

如果题目问区别,可以答:

显式调用父类方法时必须写父类名,并手动传入 self;super() 会自动按照继承关系查找父类方法,不需要手动传 self,代码更简洁,耦合度更低。

代码修改题可能要求:

把显式父类调用改成 super()

写法:

class Employee(Person):
    def __init__(self, name, staff_id):
        super().__init__(name)
        self.staff_id = staff_id

4. MyArray.py:特殊方法/运算符重载

这是 OOP 里最可能出“代码输出分析”的文件。

例如:

x = MyArray(1, 2, 3)
print(x + 5)

会调用:

__add__(self, n)

输出类似:

[6, 7, 8]

因为 __add__ 返回一个新的 MyArray 对象,而 print() 会调用 __str__()

常见对应关系要背熟:

表达式 调用方法
x + y x.__add__(y)
x - y x.__sub__(y)
x * y x.__mul__(y)
x / y x.__truediv__(y)
x // y x.__floordiv__(y)
x % y x.__mod__(y)
x ** y x.__pow__(y)
len(x) x.__len__()
x[i] x.__getitem__(i)
x[i] = v x.__setitem__(i, v)
v in x x.__contains__(v)
print(x) x.__str__()
交互式直接看 x x.__repr__()

5. text_file_format.py:编码和文件

这个文件里容易考:

with open(file_name, 'r', encoding='gbk') as f:
    read_content = f.read()

题目如果说:

读入 GBK 文件,转存为 UTF-8 文件

模板就是:

with open(old_file, 'r', encoding='gbk') as f:
    content = f.read()

with open(new_file, 'w', encoding='utf8') as f:
    f.write(content)

如果编码错,可能报:

UnicodeDecodeError
UnicodeEncodeError

资料里还有:

s = '***,陶喆'
s.encode('GB2312')

这可能报错,因为 GB2312 不支持部分汉字,换成 GBK 更稳。


四、函数类代码题怎么准备

1. 可变参数

题目说:

函数可以接收任意多个整数

立刻写:

def max_sum(*nums):
    print(max(nums))
    print(sum(nums))

*nums 会把多个位置参数收集成元组。


2. 字典参数

题目说:

接收任意多个关键字参数

写:

def f(**kwargs):
    print(kwargs)

**kwargs 会把关键字参数收集成字典。


3. 默认值参数

危险点:

def f(x, lst=[]):
    lst.append(x)
    return lst

这个 lst 只在函数定义时创建一次,所以多次调用会共享同一个列表。

正确写法:

def f(x, lst=None):
    if lst is None:
        lst = []
    lst.append(x)
    return lst

4. 返回值

题目问“输出什么”时注意:

def f():
    print(1)

x = f()
print(x)

输出:

1
None

因为函数没有 return,默认返回 None


5. 生成器

题目说:

用生成器方式产生数据

立刻想到:

def gen():
    yield ...

例如资料里的质数生成器:

def prime_generator(start, end):
    for num in range(start, end + 1):
        if is_prime(num):
            yield num

含有 yield 的函数不会一次性返回列表,而是创建生成器对象,按需产生数据。


五、代码题备考顺序

第一轮:只练老师代码里的“会报错点”

优先看这些文件:

  1. class_instance.py
  2. ABC.py
  3. class_inherit.py
  4. MyArray.py
  5. text_file_format.py
  6. 实验二 5 个程序

每个文件按下面 4 个问题练:

1. 这段代码有没有错误?
2. 如果有,错误类型是什么?
3. 为什么错?
4. 怎么改?

第二轮:把每个程序改成题目需求

比如实验二:

原程序 可能改法
字符统计 改成统计空格、标点、汉字
最大值求和 改成返回最大值和平均值
模拟 sorted 增加 reverse=True
通讯录 增加修改联系人、模糊查询
质数生成器 改成生成质数列表、统计数量、求和

OOP:

原程序 可能改法
class_instance.py 判断类属性/实例属性输出
class_inherit.py 把显式父类调用改成 super()
ABC.py 增加矩形类、三角形类
MyArray.py 增加 __gt____contains____getitem__ 功能
三维向量类 实现 + - * / 运算符重载

六、你现在最该背的“代码模板”

1. 类模板

class Student:
    school = "XDU"          # 类属性

    def __init__(self, name, age):
        self.name = name    # 实例属性
        self.age = age

    def show(self):         # 实例方法
        print(self.name, self.age)

2. 继承模板

class Person:
    def __init__(self, name):
        self.name = name

class Student(Person):
    def __init__(self, name, sid):
        super().__init__(name)
        self.sid = sid

3. 私有成员模板

class A:
    def __init__(self):
        self.__value = 0

    def get_value(self):
        return self.__value

类外特殊访问:

a = A()
print(a._A__value)

4. 抽象类模板

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, r):
        self.r = r

    def area(self):
        return 3.14 * self.r * self.r

5. 运算符重载模板

class Vector:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y, self.z - other.z)

    def __mul__(self, n):
        return Vector(self.x * n, self.y * n, self.z * n)

    def __truediv__(self, n):
        return Vector(self.x / n, self.y / n, self.z / n)

    def __str__(self):
        return f"({self.x}, {self.y}, {self.z})"

这个和第 6-8 章作业里的“三维向量类”高度对应。


6. 文件读写模板

with open("a.txt", "r", encoding="utf8") as f:
    content = f.read()

with open("b.txt", "w", encoding="utf8") as f:
    f.write(content)

7. 异常处理模板

try:
    x = int(input())
    print(10 / x)
except ValueError:
    print("输入必须是整数")
except ZeroDivisionError:
    print("除数不能为0")
else:
    print("没有异常")
finally:
    print("无论是否异常都会执行")

七、考试答题格式

代码分析题不要只写“报错”或“输出”。最好按这个格式:

该代码会报 AttributeError。
原因是 inst_attr 是实例属性,只在对象创建时通过 self.inst_attr 定义,
不能通过类名 DemoClass.inst_attr 访问。
应先创建对象 obj = DemoClass(...),再使用 obj.inst_attr 访问。

输出题按这个格式:

输出为:
...
原因:
1. ...
2. ...
3. ...

修改题按这个格式:

错误位置:第 x 行 ...
错误原因:...
修改后代码:
...
修改后作用:...

八、最短备考方案

现在别平均用力。按这个顺序:

必做

  1. 把 OOP 术语表背熟。
  2. 手敲一遍三维向量类。
  3. 看懂 class_instance.py 每一行为什么能/不能访问。
  4. 看懂 ABC.py 为什么 Shape()BadRectangle() 会报错。
  5. 看懂 MyArray.py+、//、in、len、[]、print() 分别调用哪个特殊方法。
  6. 把实验二 5 个程序能默写出核心函数。

次做

  1. 文件 GBK 转 UTF-8。
  2. try-except-else-finally
  3. 字典通讯录增删查改。
  4. 正则 re.findall()re.sub()
  5. yield 生成器。

核心判断:这门代码分析题不是考复杂算法,主要考 Python 语义和老师 PPT 术语。你现在最该补的是“中文术语 → 代码行为 → 常见报错”。

posted @ 2026-06-25 19:24  Guzq_juruo  阅读(13)  评论(0)    收藏  举报