
刚学Python那会儿,我被None和0这两个家伙搞得有点懵。看起来都像“啥也没有”,但Python偏偏对它们区别对待,这背后到底有啥讲究?咱们今天就掰扯掰扯。
这就像你问朋友“你钱包里有多少钱?”。如果他钱包丢了,他会说“没有钱包”(这对应None)。如果他钱包在,但里面一毛钱都没有,他会说“有零块钱”(这对应0)。
在Python的世界里,None是一个单独的类型,叫NoneType,它只有一个值,就是它自己。它表示的是“空无”、“不存在”或者“尚未赋值”。而0呢?它是一个实实在在的数字,是整数类型(int)家族里的一员,它有明确的数学意义和数值。
>>> type(None)
<class 'NoneType'>
>>> type(0)
<class 'int'>
看,Python解释器都告诉你它们是两码事了。这就好比猫和狗,虽然都是宠物,但你能说它们一样吗?
这个区别在写条件判断时特别要命。很多新手容易在这里栽跟头。
def find_user(user_id):
# 假设去数据库没找到这个用户
return None
result = find_user(999)
if result == 0: # 错误!用户不存在,不是找到了一个数值为0的用户
print("找到了一个积分是0的用户")
else:
print("用户不存在")
上面这个判断就错了,因为没找到用户返回的是None,而不是0。正确的写法应该是判断if result is None。这里又引出一个关键点:判断None,通常用is,而不是==。
>>> a = None
>>> b = None
>>> a == b
True
>>> a is b # 更推荐这种方式判断None
True
>>> x = 0
>>> y = 0
>>> x == y
True
>>> x is y # 对于小整数,Python有缓存机制,这里可能为True,但不保证!
True # 注意:这只是一个实现细节,别依赖它!
简单说,==比较的是值,而is比较的是内存中的身份(是不是同一个对象)。在Python中,None是一个全局唯一的对象,所以用is None来判断既准确又符合习惯。
基本上不能。因为类型不同,很多运算都没法直接做。
>>> None + 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
>>> None > 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'NoneType' and 'int'
Python会直接告诉你:类型错误,这俩不是一路人,没法比大小也没法做算术。但有趣的是,在布尔判断(if语句)里,它俩却“同流合污”了——都会被当成False。
>>> bool(None)
False
>>> bool(0)
False
>>> if not None:
... print("None是False")
...
None是False
这是Python“真假值测试”的规则决定的。除了None和0,空字符串""、空列表[]等也都被视为False。这个特性用好了能让代码很简洁,但也要小心别把“空无”和“零值”的语义混淆了。
记住一个原则:看语义。
0:当你要表示一个数值上的零。比如“账户余额为0元”、“失败次数为0次”、“列表的初始索引为0”。None:当你要表示缺失、未定义、无返回值。比如“函数找不到结果时返回None”、“一个可选的配置项如果用户没填就是None”、“对象的某个属性可能还不存在”。说白了,0是一个有意义的答案,而None意味着没有答案。下次你再写代码时,如果拿不准,就问问自己:我这儿是“钱包里没钱”,还是“压根儿就没钱包”?
分清楚了,你的代码逻辑就会清晰一大截,那些莫名其妙的bug也会少很多。Python设计者把它们分开,可不是为了增加学习难度,恰恰是为了让程序更能准确地表达现实世界里的各种“空”。
参与讨论
钱包的比喻太形象了,一下就懂了!