第二部分:Python 高频选择题 85 道(含答案解析)
一、基础语法与运算符(P01–P10)
P01 · 知识点:变量命名规则
【题目】下列选项中符合 Python 变量命名规则的是?
A. 3_1 B. my-var C. _AI D. class
答案:C
【考点】标识符规则:字母、下划线、数字组成,不能以数字开头,不能是关键字。
【结论】选 C。_AI 以下划线开头、仅含字母,完全符合 Python 标识符语法规则。
【逐项辨析】 A. 3_1:以数字“3”开头,违反“不能以数字开头”的硬约束,非法。 B. my-var:包含连字符“-”,标识符字符集仅限字母、下划线和数字,非法。 C. _AI:以下划线开头,后接大写字母,字符集与开头规则均满足,合法。 D. class:属于 Python 保留关键字,语言层面已禁止用作普通标识符,非法。
【知识点】 Python 标识符的命名规则由《Python Language Reference》明确规定。第一,字符集限制:标识符只能由 Unicode 字母(包括中文但不推荐)、下划线(_)和数字(0-9)组成。第二,开头限制:不能以数字开头,这是为了避免与数字字面量产生词法歧义。第三,关键字隔离:and、as、assert、break、class、continue、def、del、elif、else、except、False、finally、for、from、global、if、import、in、is、lambda、None、nonlocal、not、or、pass、raise、return、True、try、while、with、yield 等 35 个保留关键字不能被覆盖。此外,以下划线开头的标识符具有约定俗成的语义:单下划线开头(如 _x)表示“内部使用”或“私有”属性;双下划线开头(如 __x)会触发名称改写(name mangling);双下划线开头且结尾(如 init)用于魔法方法。这些约定不影响语法合法性,但属于工程规范层面的重要知识。
【记忆锚点】 “字母下划线数字串,数字打头不能干;关键字是高压线,触碰就报错。”
【易混对比】
| 场景 | 合法性 | 说明 |
|---|---|---|
| _var | 合法 | 单下划线开头,约定“私有” |
| __var | 合法 | 双下划线开头,触发名称改写 |
| 1var | 非法 | 数字开头 |
| var-1 | 非法 | 含连字符 |
| var 1 | 非法 | 含空格 |
| class | 非法 | 保留关键字 |
换问法:以下哪个标识符在 Python 中是合法的?A) 1_a B) _1a C) a-b D) if
答:选 B。
_1a以下划线开头且字符集合法;A 数字开头、C 含连字符、D 是关键字。
【自测】 以下代码能否正常运行?若不能,报错类型是什么?
_123 = 10
1_23 = 20
class = "语文"答:三条的报错文案不一样,别混(本机 3.12.3 实测):
_123 = 10正常(下划线开头的标识符合法);1_23 = 20报SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?——因为1_23本身是合法的数字字面量(下划线分隔写法),只是不能当赋值目标;class = “语文”报SyntaxError: invalid syntax(关键字不能作变量名)。真正报invalid decimal literal的是1var = 2这类「数字开头紧接字母」的写法——词法阶段就把1var判成非法数字字面量,与1_23 = 20的语法阶段错误不是一回事。与第 P02 题连考。
【知识关联】
- 同库关联:与 P02(类型)、P41(def 命名)命名规范题群;与 Java 标识符规则对照。
- 实现层:CPython 用符号表处理标识符;关键字在
keyword模块;Unicode 标识符 PEP 3131。 - 面试追问:① 哪些是 Python 关键字?② 下划线前缀约定含义?
【拓展延伸】
- 变式问法:给一组名字问哪些合法;
class/def/lambda不可作名。 - 版本差异:Py3.0+ Unicode 标识符;async/await 成为关键字(3.5/3.7)。
- 工程注意点:遵循 PEP8;避免单字符易混(l/O/I);模块名全小写。
P02 · 知识点:数据类型
【题目】下列哪种类型在 Python 中不存在?
A. int B. float C. char D. bool
答案:C
【考点】Python 内置类型:Python 没有独立的字符类型。
【结论】选 C。Python 中没有独立的 char 类型,单个字符也是 str。
【逐项辨析】 A. int:Python 内置整数类型,存在。 B. float:Python 内置浮点数类型,存在。 C. char:C/Java 等语言中的独立字符类型,Python 中没有,不存在。 D. bool:Python 内置布尔类型,存在。
【知识点】 Python 采用极简的类型系统设计。在 Python 中,文本数据统一由 str(字符串)类型表示,单个字符如 'a'、'中' 都是长度为 1 的字符串,其类型仍是 str。这与 C 语言的 char(通常 1 字节)、Java 的 char(UTF-16,2 字节)形成鲜明对比。Python 3 的 str 内部使用 Unicode 码点序列存储,没有固定字节长度限制。除了 int、float、bool、str,Python 还内置了 complex(复数)、bytes(不可变字节串)、bytearray(可变字节数组)、memoryview、NoneType 等。初学者从 C/Java 转 Python 时,常误以为需要 char 来存储单个字符,这是典型的迁移惯性错误。
【记忆锚点】 “Python 无 char,字符也是串,长度为一不奇怪。”
【易混对比】
| 语言 | 字符类型 | 表示方式 | 类型示例 |
|---|---|---|---|
| C | char | 'a' | char |
| Java | char | 'a' | char |
| Python | 无 | 'a' | str |
| Python | 字节 | b'a' | bytes |
换问法:在 Python 中,表达式 type('x') 的结果是什么?
【自测】 执行以下代码,输出分别是什么?
print(type('a'))
print(type(b'a'))
print(type(97))答:输出依次为
<class 'str'>、<class 'bytes'>、<class 'int'>。与第 P03 题连考。
【知识关联】
- 同库关联:与 P09/P19(类型转换)、P05(is/==)、P02–P10 基础语法题群。
- 实现层:CPython 对象模型一切皆对象;int 为任意精度(不是固定 32 位)。
- 面试追问:① Python int 与 Java int 差异?② 动态类型 vs 强类型如何理解?
【拓展延伸】
- 变式问法:
type(3)与type(3.0);True是否 int 子类(是)。 - 版本差异:Py3 废除 long,统一 int;str 仅 unicode。
- 工程注意点:类型注解 + mypy;数值计算用 decimal/numpy 明确精度。
P03 · 知识点:除法运算
【题目】7 // 2 和 7 / 2 的结果分别是?
A. 3.5 和 3.5 B. 3 和 3 C. 3 和 3.5 D. 3 和 3.0
答案:C
【考点】整除(//)与真除法(/)的区别;向下取整方向。
【结论】选 C。7 // 2 执行地板除得 3,7 / 2 执行真除法得 3.5。
【推导过程】 在 Python 3 中,运算符 / 为真除法(true division),无论操作数类型均返回 float: $$7 / 2 = 3.5$$ 运算符 // 为地板除(floor division),结果向负无穷方向取整: $$7 // 2 = \lfloor 3.5 \rfloor = 3$$ 若操作数为负数,如 -7 // 2: $$-7 / 2 = -3.5$$ $$-7 // 2 = \lfloor -3.5 \rfloor = -4$$
【逐项辨析】 C. 3 和 3.5:// 得 3,/ 得 3.5,完全正确。 B. 3 和 3:/ 在 Python 3 中不会返回整数 3,错误。 A. 3.5 和 3.5:// 不会返回 3.5,错误。 D. 3 和 3.0:/ 返回 3.5 而非 3.0,错误。
【知识点】 Python 3 对除法进行了语义拆分。/ 始终返回浮点数,即使整除也不例外(如 4 / 2 = 2.0)。// 返回不大于数学结果的最大整数(向下取整),其数学本质是 floor() 函数。当操作数含有 float 时,// 返回 float(如 7.0 // 2 = 3.0)。初学者从 C/Java 迁移时,常把 // 等同于整数除法——在 C/Java 中整数除法是向零取整(truncation),而 Python 的 // 是向负无穷取整,这是负数场景下最关键的差异点。
【记忆锚点】 “一斜杠是真除,浮点结果留不住;双斜杠地板除,向下取整要记住。”
【易混对比】
| 运算符 | Python 3 行为 | C/Java 行为 | 示例结果 |
|---|---|---|---|
| / | 真除法,返回 float | 整数除法,向零取整 | 7/2 → 3.5 (Py) / 3 (C) |
| // | 地板除,向负无穷取整 | 无直接对应(或同 /) | -7//2 → -4 (Py) / -3 (C) |
| % | 取模,结果符号与除数一致 | 取余,结果符号与被除数一致 | -7%2 → 1 (Py) / -1 (C) |
换问法:在 Python 3 中,表达式 -5 // 2 的结果是?
【自测】 以下代码的输出是什么?
print(5 // 2)
print(-5 // 2)
print(5.0 // 2)答:输出依次为 2、-3、2.0。注意 -5 // 2 是向下取整得 -3,而非向零取整的 -2。与第 P04 题连考。
【知识关联】
- 同库关联:与 J03(Java 整数除法截断)经典对照;与 P04(幂运算)。
- 实现层:CPython
/调用 float 除法;//地板除对负数向负无穷。 - 面试追问:①
-7 // 2在 Python 与 Java 的差异?② 如何取余数?
【拓展延伸】
- 变式问法:
7/2、7//2、7%2;Py2 vs Py3 除法。 - 版本差异:Py3
/为真除法(PEP 238);Py2 整数/截断。 - 工程注意点:迁移 Py2 代码注意
/;金额用 Decimal。
P04 · 知识点:幂运算与结合性
【题目】2**3**2 的结果是?
A. 64 B. 语法错误 C. 36 D. 512
答案:D
【考点】幂运算符(**)的优先级与右结合性。
【结论】选 D。幂运算右结合,2**3**2 等价于 2**(3**2) = 512。
【推导过程】 幂运算符 ** 在 Python 中具有最高优先级之一,且为右结合性(right-associative)。计算顺序从右向左: $$32 = 9$$ $$29 = 512$$ 若错误地按左结合计算: $$23 = 8$$ $$82 = 64$$ 将得到错误结果 64(对应选项 A)。
【逐项辨析】 A. 64:按左结合错误计算 23=8、82=64,不符合 Python 语义,错误。 D. 512:按右结合计算 32=9、29=512,正确。 C. 36:无对应计算逻辑,干扰项,错误。 B. 语法错误:** 连续使用完全合法,错误。
【知识点】 Python 运算符优先级从高到低依次为:() > ** > +x、-x、~x > *、/、//、% > +、- > <<、>> > & > ^ > | > 比较运算 > not > and > or。其中 ** 是唯一具有右结合性的二元运算符,设计原因是数学惯例:$a^{b^c}$ 天然表示 $a^{(b^c)}$。与之对比,* 和 + 等运算符为左结合。当表达式含多个 ** 时,务必明确结合方向,否则极易产生隐蔽的逻辑错误。
【记忆锚点】 “幂运算优先级高,右结合要记牢;从右往左算,结果才不会跑。”
【易混对比】
| 运算符 | 结合性 | 计算方向 | 示例 | 实际结果 |
|---|---|---|---|---|
| ** | 右结合 | 从右向左 | 232 | 2**(3**2)=512 |
| * | 左结合 | 从左向右 | 232 | (2*3)*2=12 |
| + | 左结合 | 从左向右 | 2+3+2 | (2+3)+2=7 |
| - | 左结合 | 从左向右 | 2-3-2 | (2-3)-2=-3 |
换问法:表达式 223 的值是多少?
【自测】 以下代码的输出是什么?
print(2 ** 3 ** 2)
print((2 ** 3) ** 2)
print(2 * 3 * 2)答:输出依次为 512、64、12。第一个体现右结合,第二个括号改变优先级体现左结合,第三个是普通乘法左结合。与第 P05 题连考。
【知识关联】
- 同库关联:与 P03;运算符优先级与结合性;Java 用 Math.pow。
- 实现层:
**右结合;int 幂任意精度可导致巨数。 - 面试追问:①
2**3**2等于多少?② 与pow(2,3,5)模幂?
【拓展延伸】
- 变式问法:负指数
2**-1得 float(0.5);(-2)**0.5不报错,返回复数——Python 3 对负数的分数次幂直接转 complex,本机 3.12.3 实测为(8.659560562354934e-17+1.4142135623730951j)(即 √2 的虚数结果,实部是浮点误差)。同理(-8)**(1/3)也返回 complex 而不是 -2,想要实数根得自己按符号处理(如-abs(x)**(1/3))。 - 版本差异:语义稳定。
- 工程注意点:大数据幂避免内存爆炸;密码学用内置 pow 模幂。
P05 · 知识点:is 与 ==
【题目】a = [1, 2, 3]; b = [1, 2, 3]; 则 a == b 和 a is b 的结果分别是?
A. True 和 True B. False 和 False C. False 和 True D. True 和 False
答案:D
【考点】== 比较值(内容),is 比较身份(内存地址/id)。
【结论】选 D。a == b 比较值相等得 True,a is b 比较身份不同得 False。
【推导过程】
a = [1, 2, 3]
b = [1, 2, 3]== 运算符调用列表的 __eq__ 方法,逐元素比较内容: $$[1, 2, 3] == [1, 2, 3] \Rightarrow \text{True}$$ is 运算符比较两个对象的内存地址(id): $$\text{id}(a) \neq \text{id}(b) \Rightarrow \text{False}$$ 因为 a 和 b 是通过两次独立的列表字面量创建的,系统分配了不同的内存块。
【逐项辨析】 A. True 和 True:is 不会为 True,因为 a、b 不是同一对象,错误。 D. True 和 False:== 比较内容得 True,is 比较身份得 False,正确。 C. False 和 True:== 比较内容应得 True,错误。 B. False 和 False:== 比较内容应得 True,错误。
【知识点】== 是值相等(equality),is 是身份相等(identity)。在 CPython 中,is 等价于 id(a) == id(b)。对于不可变对象,Python 可能启用驻留(interning)机制以节省内存:小整数(-5 ~ 256)会被缓存,短字符串可能被驻留。但列表、字典、集合等可变对象永远不会被自动驻留,即使内容完全相同也会创建独立对象。判断是否为同一对象应使用 is,判断内容是否相同应使用 ==。None 的比较推荐使用 is None,因为 None 是单例对象。
【记忆锚点】 “等号比内容,is 比地址;可变对象不共享,每次新建各不同。”
【易混对比】
| 比较方式 | 本质 | 适用场景 | 典型陷阱 |
|---|---|---|---|
| == | 值相等,调用 eq | 比较内容、数据 | 自定义类未重载 eq |
| is | 身份相等,比较 id | 判断单例(None、True、False) | 误以为 == 和 is 等价 |
| 小整数缓存 | 驻留机制 | -5~256 的整数 | x=257; y=257; x is y 可能为 False(口径要写清:本机 3.12.3 实测同一编译单元内两句共用同一个常量对象,结果 True;REPL 逐行输入或分处不同模块才 False。所以「可能为 False」成立,但归因是编译单元的常量缓存,不是稳定的语言保证) |
换问法:以下代码的输出是什么?a = [1,2]; b = a; print(a is b)
【自测】 以下代码的输出分别是什么?
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b, a is b, a == c, a is c)答:输出为 True False True True。a == b 内容相同为 True,a is b 不同对象为 False,a == c 和 a is c 均为 True 因为 c 是 a 的引用。与第 P06 题连考。
【知识关联】
- 同库关联:与 J22(equals vs ==)对照;与 P22(引用)、P70(驻留)。
- 实现层:
is比 id(地址);==默认比值可重载__eq__;小整数/短字符串常驻。 - 面试追问:① 何时必须用 is?② None 判断为何用 is?
【拓展延伸】
- 变式问法:
a=[]; b=[]; a is b;a=1; b=1可能 is 为 True(缓存)。 - 版本差异:实现细节(驻留范围)随 CPython 版本/实现而异,考试以语义为准。
- 工程注意点:判 None/True/False 用 is;比值用 ==;别依赖小整数缓存写业务逻辑。
P06 · 知识点:真值测试
【题目】下列哪个值在布尔上下文中被视为 False?
A. 0 B. 0.0 C. "" D. 以上都是
答案:D
【考点】Python 的 falsy(假值)集合。
【结论】选 D。0、0.0 和空字符串在布尔上下文中均被判定为 False。
【逐项辨析】 A. 0:整数零属于 falsy 值,布尔上下文为 False,但单独选 A 不全面。 B. 0.0:浮点数零属于 falsy 值,布尔上下文为 False,但单独选 B 不全面。 C. "":空字符串属于 falsy 值,布尔上下文为 False,但单独选 C 不全面。 D. 以上都是:A、B、C 均为 falsy 值,此选项最全面,正确。
【知识点】 Python 的真值测试(truth value testing)遵循明确的协议。对象在 if/while/and/or/not 等布尔上下文中被视为 False 的条件是:1)定义了 __bool__() 方法且返回 False;2)若未定义 __bool__(),则定义了 __len__() 方法且返回 0。内置的 falsy 值包括:None、False、0(任意数值类型的零,包括 int、float、complex、Fraction、Decimal)、""(空字符串)、[](空列表)、()(空元组)、{}(空字典)、set()(空集合)、frozenset()、range(0) 等。其余对象默认视为 True,包括非零数字、非空容器、自定义实例(默认)。需要特别注意的是,字符串 "0" 和 "False" 是非空字符串,属于 truthy 值,这是常见陷阱。
【记忆锚点】 “None 假零空容器,见到它们就是 False;非空非零自定义,默认都是 True。”
【易混对比】
| 表达式 | 布尔值 | 常见误判 | 说明 |
|---|---|---|---|
| 0 | False | 误以为 True | 数值零 |
| 0.0 | False | 误以为 True | 浮点零 |
| "" | False | 误以为 True | 空字符串 |
| "0" | True | 误以为 False | 非空字符串,内容是字符'0' |
| "False" | True | 误以为 False | 非空字符串,不是布尔值 |
| [0] | True | 误以为 False | 非空列表,含一个元素 0 |
换问法:在 Python 中,表达式 bool("False") 的结果是什么?
【自测】 以下代码的输出是什么?
print(bool([]))
print(bool([0]))
print(bool("0"))
print(bool(0.0))答:输出依次为 False、True、True、False。[0] 和 "0" 是非空容器/字符串,属于 truthy 值。与第 P07 题连考。
【知识关联】
- 同库关联:与 J08(Java 短路)对照——Python and/or 返回操作数而非强制 bool。
- 实现层:真值测试调用
__bool__/__len__;空容器为假。 - 面试追问:①
[] or "x"结果?② 如何写三元表达式?
【拓展延伸】
- 变式问法:
0 or [] or "hi";not 的优先级。 - 版本差异:语义稳定。
- 工程注意点:避免把 and/or 当作完整三元滥用;显式判断更清晰。
P07 · 知识点:元组的定义
【题目】type((1)) 和 type((1,)) 的结果分别是?
A. int 和 int B. tuple 和 int C. tuple 和 tuple D. int 和 tuple
答案:D
【考点】单元素元组的定义必须加逗号。
【结论】选 D。(1) 的括号是分组符号,类型为 int;(1,) 带尾随逗号,类型为 tuple。
【推导过程】
type((1))解析时,内层括号 (1) 被解释为分组运算符(grouping operator),与数学表达式中的括号等价,不改变操作数类型。因此 (1) 等价于 1,类型为 int。
type((1,))逗号 , 在括号内表示元组构造运算符。(1,) 是单元素元组的显式语法,尾随逗号是区分“分组括号”与“元组构造”的唯一标志。
【逐项辨析】 A. int 和 int:(1,) 是 tuple 而非 int,错误。 D. int 和 tuple:(1) 为 int,(1,) 为 tuple,正确。 C. tuple 和 tuple:(1) 不是 tuple,错误。 B. tuple 和 int:顺序颠倒,错误。
【知识点】 元组(tuple)是 Python 中不可变的有序序列类型。其语法特殊性在于:逗号是构造元组的真正运算符,圆括号只是辅助界定。例如 1, 2 无需括号也是合法元组。空元组写作 ();单元素元组必须加尾随逗号 (x,),否则括号仅起分组作用。这一设计源于 Python 语法解析的需要:若 (1) 表示元组,则数学表达式 (1+2)*3 将产生歧义。理解“逗号构造元组、括号仅分组”的本质,可避免大量类型判断错误。
【记忆锚点】 “元组不靠括号靠逗号,单个元素逗号不能掉;空元组括号表,多元素逗号来构造。”
【易混对比】
| 表达式 | 类型 | 本质 | 常见错误 |
|---|---|---|---|
| () | tuple | 空元组 | 误以为是空集合 |
| (1) | int | 分组符号 | 误以为是单元素元组 |
| (1,) | tuple | 单元素元组 | 漏写逗号 |
| (1, 2) | tuple | 两元素元组 | 正确理解 |
| 1, 2 | tuple | 两元素元组(无括号) | 误以为需要括号 |
换问法:以下代码的输出是什么?print(type((1,)))
【自测】 以下代码的输出分别是什么?
print(type(()))
print(type((1)))
print(type((1,)))
t = 1, 2
print(type(t))答:输出依次为
<class 'tuple'>、<class 'int'>、<class 'tuple'>、<class 'tuple'>。最后一个利用逗号构造元组,无需括号。与第 P08 题连考。
【知识关联】
- 同库关联:与 P18(元组特性)、P11(列表)、P24(字典键需可哈希)。
- 实现层:元组不可变可哈希(元素也可哈希时);比列表更省内存、可作 dict key。
- 面试追问:① 元组可变吗(元素若是列表呢)?② 为何能作字典键?
【拓展延伸】
- 变式问法:
t=([1],2)能否哈希(不能);单元素元组要逗号。 - 版本差异:语义稳定。
- 工程注意点:坐标/记录用 namedtuple/元组;需要修改用 list。
P08 · 知识点:字符串运算
【题目】print("5" * 3) 的输出结果是?
A. 15 B. "5"*3 C. 抛出异常 D. 555
答案:D
【考点】字符串重复操作符 *(不是乘法)。
【结论】选 D。字符串与整数相乘表示重复拼接,"5" * 3 = "555"。
【推导过程】
"5" * 3Python 的 * 运算符在字符串与整数之间被重载(overloaded)为序列重复协议。其语义为:将字符串重复 n 次后拼接。计算过程: $$"5" \times 3 = "5" + "5" + "5" = "555"$$ 注意:乘数必须是非负整数,负数产生空字符串。
【逐项辨析】 A. 15:将字符串“5”误解为整数 5 后做乘法,错误。 D. 555:字符串“5”重复 3 次,结果为“555”,正确。 C. 抛出异常:字符串与整数相乘是合法操作,不会抛异常,错误。 B. "5"*3:print 会输出运算结果而非字面表达式,错误。
【知识点】 Python 的序列类型(str、list、tuple)均支持 * 重复操作。seq * n 或 n * seq 返回将序列重复 n 次的新序列。重复操作的底层实现通过 __mul__ 和 __rmul__ 魔术方法完成。字符串是不可变序列,* 返回新字符串。需要严格区分的是:字符串与整数相加("5" + 3)会抛出 TypeError,因为 + 在字符串间表示拼接,不支持跨类型操作;而 * 被显式设计为支持序列与整数的跨类型操作。列表和元组同样支持 * 重复:[1] * 3 = [1, 1, 1]。
【记忆锚点】 “字符串遇乘号,重复来报到;乘数是整数,次数要记牢。”
【易混对比】
| 表达式 | 结果 | 合法性 | 说明 |
|---|---|---|---|
| "5" * 3 | "555" | 合法 | 字符串重复 |
| 3 * "5" | "555" | 合法 | 反向乘法同样支持 |
| "5" + "3" | "53" | 合法 | 字符串拼接 |
| "5" + 3 | TypeError | 非法 | 字符串与整数不能直接相加 |
| [1] * 3 | [1, 1, 1] | 合法 | 列表重复 |
| (1,) * 3 | (1, 1, 1) | 合法 | 元组重复 |
换问法:表达式 [0] * 3 的结果是什么?
【自测】 以下代码的输出分别是什么?
print("5" * 3)
print("5" + "3")
print(["Hi"] * 2)答:输出依次为 "555"、"53"、["Hi", "Hi"]。注意字符串和列表的重复操作行为一致。与第 P09 题连考。
【知识关联】
- 同库关联:与 J07(Java 拼接)、P39(f-string)、P33(不可变)。
- 实现层:str 不可变;
+生成新对象;CPython 对 intern/拼接有优化但语义是新串。 - 面试追问:① 循环拼接为何低效?② 应该用什么?
【拓展延伸】
- 变式问法:
"a"*3;str + int报错需转换。 - 版本差异:f-string 3.6+ 成为主流。
- 工程注意点:大量拼接用
"".join(parts)(先收集进列表再一次拼)或io.StringIO,别在循环里反复s += x。注意归因要准:CPython 对s += x有「引用计数为 1 时原地扩容」的实现优化,本机 3.12.3 实测 8 万次+=仅 2.9 ms(同规模 join 0.41 ms),但一旦结果串被别处持有引用(如把中间态 append 进列表)优化立刻失效,同样 8 万次退化到 1310 ms(二次方级)。也就是说+=快不快取决于实现与引用情况,不可移植;跨实现/长期代码一律用 join。
P09 · 知识点:类型转换
【题目】执行 int("3.14") 会?
A. 返回 3 B. 返回 3.14 C. 抛出 ValueError D. 返回 "3"
答案:C
【考点】int() 转换字符串时要求字符串是合法整数字面量。
【结论】选 C。int() 转换字符串时要求合法整数字面量,"3.14" 含小数点,抛出 ValueError。
【推导过程】
int("3.14")int() 函数对字符串参数的处理流程:1)去除前后空白;2)检查字符串是否符合整数字面量语法(可选正负号后接数字,不能含小数点或指数);3)解析为整数。"3.14" 含小数点,步骤 2 失败,抛出 ValueError。 与之对比:
int(3.14) # 传入 float,返回 3(截断小数)
float("3.14") # 传入合法浮点字符串,返回 3.14【逐项辨析】 A. 返回 3:int("3.14") 不会自动截取小数,错误。 B. 返回 3.14:int() 返回类型为 int,不可能返回 float,错误。 C. 抛出 ValueError:字符串含小数点,不符合整数字面量规范,正确。 D. 返回 "3":int() 返回 int 类型,不会返回字符串,错误。
【知识点】 Python 的类型转换函数具有严格的参数约束。int(x, base=10) 的两种调用模式:1)x 为数字类型(int、float 等),返回截断后的整数(向零取整,非四舍五入);2)x 为字符串或 bytes-like 对象,要求内容必须是目标进制的合法字面量。常见陷阱:int("3.14") 报错而 int(3.14) 成功,因为两种模式的处理逻辑完全不同。字符串模式先进行语法校验,而数字模式直接截断。若需将字符串形式的浮点数转为整数,标准路径是 int(float("3.14")),先转 float 再截断。
【记忆锚点】 “int 转字符串,字面量要纯;有小数点不行,先 float 再求整。”
【易混对比】
| 表达式 | 结果 | 类型 | 关键区别 |
|---|---|---|---|
| int("3") | 3 | int | 合法整数字符串 |
| int("3.14") | ValueError | - | 字符串含小数点 |
| int(3.14) | 3 | int | 浮点数截断(向零取整) |
| int(float("3.14")) | 3 | int | 正确路径:先 float 后 int |
| int("10", 2) | 2 | int | 按二进制解析 |
换问法:执行 int(3.9) 的结果是什么?
【自测】 以下代码的输出或行为分别是什么?
print(int("100"))
print(int(3.9))
print(int("3.9"))答:第一个输出 100;第二个输出 3(浮点数截断);第三个抛出 ValueError(字符串含小数点)。与第 P10 题连考。
【知识关联】
- 同库关联:与 P02/P19;与 J74(Java 强转向零)对照——int(3.99) 也是截断。
- 实现层:
int()截断小数;float();str()调__str__。 - 面试追问:①
int("12a")?②bool([])?
【拓展延伸】
- 变式问法:进制转换
int("ff",16);科学计数法。 - 版本差异:语义稳定。
- 工程注意点:用户输入转换要 try;金融用 Decimal。
P10 · 知识点:print 参数
【题目】print(1, 2, sep="-") 的输出是?
A. 1 2 B. 12 C. 1-2 D. 抛异常
答案:C
【考点】print 的 sep 与 end 参数。
【结论】选 C。指定 sep="-" 后,print 用连字符连接各值,输出 1-2。
【推导过程】
print(1, 2, sep="-")print() 的签名:print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)。默认 sep=' ' 用空格分隔多个值,end='\n' 以换行结尾。本题显式指定 sep="-",因此输出过程为:
- 将 1 转为字符串 "1"
- 将 2 转为字符串 "2"
- 用 sep="-" 连接:"1" + "-" + "2" = "1-2"
- 追加 end="\n"(换行) 终端显示:1-2
【逐项辨析】 C. 1-2:sep="-" 生效,用连字符连接,正确。 B. 12:未指定 sep 时默认空格而非空字符串,且空字符串 sep="" 才得 12,错误。 A. 1 2:默认 sep=" " 的输出,本题已显式修改 sep,错误。 D. 抛异常:sep 参数类型为 str,传入 "-" 完全合法,错误。
【知识点】 print() 是 Python 最常用的内置函数之一,其 sep 和 end 参数提供强大的输出定制能力。sep 控制多个值之间的分隔符,可为任意字符串(包括空字符串、换行符、制表符等);end 控制行尾字符,默认 \n,可改为空字符串实现不换行输出。Python 3 中 print 是函数,必须用括号调用;Python 2 中 print 是语句,语法不同。print 会自动调用每个对象的 __str__ 方法获取字符串表示。通过 file 参数可将输出重定向到文件或日志流。
【记忆锚点】 “print 参数两兄弟,sep 管中间 end 管尾;默认空格和换行,改成啥样随你意。”
【易混对比】
| 调用方式 | 输出结果 | 说明 |
|---|---|---|
| print(1, 2) | 1 2\n | sep=" ", end="\n"(默认) |
| print(1, 2, sep="-") | 1-2\n | sep 改为 "-" |
| print(1, 2, sep="", end="") | 12 | 无分隔、无换行 |
| print(1, 2, end=";") | 1 2; | end 改为 ";" |
| print(*[1,2,3], sep=",") | 1,2,3\n | 解包列表 |
换问法:print(1, 2, 3, sep=",", end="!") 的输出是什么?
【自测】 以下代码的输出分别是什么?
print("A", "B", sep="-")
print("A", "B", end="!")
print("A", "B", sep="", end="")答:第一个输出 "A-B\n";第二个输出 "A B!"(默认空格分隔,结尾无换行);第三个输出 "AB"(无分隔无换行)。与第 P01 题连考。
【知识关联】
- 同库关联:与 P39;输出格式化题群。
- 实现层:print 调用 sys.stdout.write;sep/end/file/flush 参数。
- 面试追问:① 如何输出到 stderr?② 如何不换行?
【拓展延伸】
- 变式问法:
print(1,2,sep="-",end="!")。 - 版本差异:Py3 print 是函数;Py2 是语句。
- 工程注意点:生产日志用 logging 而不是 print;重定向注意缓冲。