2025-10-06 Python不基础 11——if 判断
文章目录
- 1. 四种 if 判断
- 1.1. `if a is True`
- 1.2. `if a == True`
- 1.3. `if a`
- 1.4. `if bool(a)`
- 2. 底层实现:`PyObject_IsTrue`
- 2.1. 字节码入口:`pop_jump_if_false`
- 2.2. 内置类型判定规则:`PyObject_IsTrue`
- 步骤1:直接判断`True/False/None`
- 步骤2:判断是否为“数字类型”(Number)
- 步骤3:判断是否为“映射类型”(Mapping)
- 步骤4:判断是否为“序列类型”(Sequence)
- 2.3. 自定义类型真值判定规则
- 3. `bool(a)`:类的实例化
- 4. 如何正确使用 if
- 4.1. 优先“明确判断”,减少“模糊判断”
- 4.2. 压缩变量的类型范围
- 4.3. 避免滥用`a == True`和`a is True`
本文参考视频链接:
- https://www.bilibili.com/video/BV1dZ4y127fR
1. 四种 if 判断
以变量a
为例,对比四种if
判断形式的行为差异,核心是明确“判断的是变量本身”还是“变量的真值属性”。
先看基础代码示例,当a=True
或a=False
时的表现:
a = True # 或 a = False# 四种判断形式
if a is True:print("True 1")
if a == True:print("True 2")
if a:print("True 3")
if bool(a):print("True 4")
- 当
a=True
:4个if
均成立,打印“True 1/2/3/4”; - 当
a=False
:所有if
均不成立,无输出。
但当a
不是True/False
时,四种判断的差异会完全显现。

1.1. if a is True
- 基于身份判定(
is
比较的是变量的内存地址id()
),仅当a
是Python内置的True
对象时,条件才成立; - 若
a
是任何其他值(包括1
、"非空字符串"
、[1]
等“真值”),条件均不成立。
a = 1 # 1是“真值”,但不是True对象
print(a is True) # 输出:False
a = True
print(a is True) # 输出:True
- 反面不是
a is False
:a is True
的否定是a is not True
,而非a is False
;- 原因:Python中变量可能是
True/False
之外的值(如None
、0
、""
等),这些值既不是True
也不是False
; - 示例:
a = None
,a is not True
成立,但a is False
不成立。
- 原因:Python中变量可能是
- 适用场景:需精确筛选
True
对象的场景(极少用,仅当逻辑中必须区分“True”与其他“真值”时)。
1.2. if a == True
- 基于值相等判定(
==
比较的是值,且可被自定义类重载__eq__
方法修改行为); - 对于内置类型,
== True
的逻辑等同于“是否为真值”(如1 == True
成立,[1] == True
不成立),但行为不可控。
为什么不推荐?
- 重载风险:
==
运算符可被自定义类通过__eq__
方法重载,导致判断逻辑异常;- 示例:自定义类
class MyObj: def __eq__(self, other): return True
,则MyObj() == True
会返回True
,不符合预期。
- 示例:自定义类
- 冗余且模糊:若想判断“真值”,直接用
if a
更简洁;若想判断“是否为True本身”,用a is True
更精确,a == True
处于两者之间,无明确场景。
1.3. if a
- 这是Python中最常见的判断形式,本质是调用Python内部函数
PyObject_IsTrue(a)
,根据返回值(1=真,0=假,-1=出错)判定条件是否成立; - 不同类型的变量,
PyObject_IsTrue
的判定规则不同,可分为“内置类型”和“自定义类型”两类。
1.4. if bool(a)
对比 if a
:
- 逻辑等价:两者均依赖
PyObject_IsTrue(a)
,判定结果完全一致; - 性能差异:
if bool(a)
多一次bool
类的实例化调用(函数调用开销),而if a
直接通过字节码调用PyObject_IsTrue
,更高效; - 适用场景:
- 若仅需判断真值:直接用
if a
,简洁高效; - 若需显式获取布尔值(如存储、传递):用
bool(a)
,例如is_valid = bool(a)
。
- 若仅需判断真值:直接用
2. 底层实现:PyObject_IsTrue
分析Python字节码和C源码,揭示if a
的核心依赖——PyObject_IsTrue
函数,其判定逻辑分内置类型和自定义类型两类。

2.1. 字节码入口:pop_jump_if_false
当执行if a
时,Python编译后的字节码会出现pop_jump_if_false
指令:
- 作用:弹出栈顶的变量
a
,调用PyObject_IsTrue(a)
判断; - 若返回0(假),则跳转到
if
块之外;若返回1(真),则执行if
块内代码。
源码层面(CPython):pop_jump_if_false
会优先检查a
是否为True/False
(快速路径,fast path
),若不是,则调用PyObject_IsTrue(a)
。
2.2. 内置类型判定规则:PyObject_IsTrue
PyObject_IsTrue
对内置类型的判定分4步,优先级从高到低:

步骤1:直接判断True/False/None
- 若
a is True
:返回1(真); - 若
a is False
或a is None
:返回0(假);- 关键结论:
None
在if a
中会被判定为假,这是很多新手容易忽略的点。
- 关键结论:
步骤2:判断是否为“数字类型”(Number)
- 适用类型:
int
、float
、complex
、decimal.Decimal
等; - 判定规则:非零即真,零即假;
- 示例:
a = 5
(非零int)→ 真;a = 0.0
(零float)→ 假;a = 3+4j
(非零complex)→ 真;a = 0+0j
(零complex)→ 假。
- 示例:
步骤3:判断是否为“映射类型”(Mapping)
- 适用类型:
dict
(字典)、set
(集合)、frozenset
(不可变集合)等(key-value结构或无重复元素集合); - 判定规则:非空即真,空即假(判断
len(a) > 0
);- 示例:
a = {"name": "Alice"}
(非空dict)→ 真;a = {}
(空dict)→ 假;a = {1,2,3}
(非空set)→ 真;a = set()
(空set)→ 假。
- 示例:
步骤4:判断是否为“序列类型”(Sequence)
- 适用类型:
str
(字符串)、list
(列表)、tuple
(元组)、range
(范围)等(可数、有序结构); - 判定规则:非空即真,空即假(判断
len(a) > 0
);- 示例:
a = "hello"
(非空str)→ 真;a = ""
(空str)→ 假;a = [1,2]
(非空list)→ 真;a = []
(空list)→ 假;a = range(5)
(非空range,len=5)→ 真;a = range(0)
(空range,len=0)→ 假。
- 示例:
类型分类 | 判定规则 | 真(True)示例 | 假(False)示例 |
---|---|---|---|
布尔/None | True=真,False/None=假 | True | False、None |
数字(Number) | 非零=真,零=假 | 3、-2.5、1+0j | 0、0.0、0+0j |
映射(Mapping) | 非空=真,空=假 | {“a”:1}、{1,2} | {}、set() |
序列(Sequence) | 非空=真,空=假 | “hi”、[1]、(2,3)、range(1) | “”、[]、()、range(0) |
2.3. 自定义类型真值判定规则
若a
是自定义类的实例(如class MyClass: pass
),PyObject_IsTrue
的判定逻辑与内置类型不同,核心依赖类的两个特殊方法:__bool__
和__len__
。

判定优先级(从高到低)
-
检查是否定义
__bool__
方法:__bool__
方法需返回布尔值(True/False
);- 若定义,则
PyObject_IsTrue
直接使用该方法的返回值(返回True
则判定为真,False
则为假)。
-
若未定义
__bool__
,检查是否定义__len__
方法:__len__
方法需返回非负整数(长度);- 若定义,则
PyObject_IsTrue
判定规则为:len(a) > 0
即真,否则为假(与序列/映射一致)。
-
若两者均未定义:
PyObject_IsTrue
直接返回1(真),即自定义实例默认被判定为真。
# 示例1:定义__bool__
class MyObj1:def __bool__(self):return False # 强制返回Falsea = MyObj1()
if a:print("真") # 不执行,因为__bool__返回False# 示例2:未定义__bool__,定义__len__
class MyObj2:def __len__(self):return 0 # 长度为0a = MyObj2()
if a:print("真") # 不执行,因为len(a)=0# 示例3:两者均未定义
class MyObj3:passa = MyObj3()
if a:print("真") # 执行,默认判定为真
__bool__
和__len__
的返回值会被严格检查,避免递归调用PyObject_IsTrue
:

__bool__
必须返回布尔值:若返回非布尔值(如1
),Python会报错(TypeError: __bool__ should return bool, not int
);__len__
必须返回非负整数:若返回非整数(如"abc"
),Python会报错(TypeError: __len__() should return an integer
);- 因此,
__bool__
/__len__
的返回值可直接判定,不会再次调用PyObject_IsTrue
,避免无限递归。
3. bool(a)
:类的实例化
bool
不是函数,而是Python的内置类(class bool
),bool(a)
本质是创建bool
类的实例,其逻辑与if a
完全等价。

- 源码层面(CPython):
bool
类继承自int
类(class bool(int): ...
),其__new__
方法(实例化方法)核心调用PyObject_IsTrue(a)
; - 实例化逻辑:
- 调用
PyObject_IsTrue(a)
获取结果(1/0/-1); - 若结果为1:返回
True
(bool
类的唯一“真”实例); - 若结果为0:返回
False
(bool
类的唯一“假”实例); - 若结果为-1(出错):抛出异常。
- 调用
print(type(bool)) # 输出:<class 'type'>(证明是类)
print(bool(123)) # 输出:True(PyObject_IsTrue(123)=1)
print(bool([])) # 输出:False(PyObject_IsTrue([])=0)
4. 如何正确使用 if
视频结尾给出了关键建议,避免因“真值判定”的歧义导致bug:
4.1. 优先“明确判断”,减少“模糊判断”
- 问题:
if a
会将None
、False
、0
、""
、[]
等均判定为假,但实际业务中可能需要区分这些情况(如“None
代表未初始化,[]
代表已初始化但为空”); - 解决方案:根据业务逻辑做明确判断,而非依赖
if a
的模糊判定:# 坏示例:无法区分None和空列表 if not a:print("错误")# 好示例:明确区分None和空列表 if a is None:print("未初始化") elif len(a) == 0:print("已初始化但为空")
4.2. 压缩变量的类型范围
- 尽量确保变量的类型可预测(如明确
a
是“列表”或“布尔值”),减少“跨类型真值判定”的风险; - 示例:若
a
的取值仅为None
或列表,可先判断a is not None
,再判断列表是否非空,逻辑更清晰。
4.3. 避免滥用a == True
和a is True
- 仅当需精确判断“是否为True对象”时,用
a is True
; - 永远不要用
a == True
(冗余且有重载风险); - 若需判断“真值”,直接用
if a
(简洁且符合Python习惯)。