看完少走3个月弯路
你是不是也写过这种代码
x = 10if x is10:print("等于10")
恭喜你,你踩坑了
这不是等于10的判断,这是判断x和10是不是同一个对象看起来结果一样等x变成1000的时候,你再跑一遍试试
**这就是Python if判断的第一个坑——用is代替==**
別以為這種低級錯誤你不會犯我帶過上百個學員,80%的人都曾经在面试题里栽倒不是他们笨,是从来没人把这个讲清楚
今天我把if判断里最容易被忽略的坑,全给你挖出來
你是不是也這樣寫過代碼?
場景一:你在判斷用戶有沒有輸入
name = input("請輸入姓名: ") # 用戶直接按了回車if name:print(f"你好{name}")else:print("您沒有輸入姓名")
這段代碼看起來沒問題對吧
好,如果用戶輸入的是一個空格 " " 呢
程式會顯示「您沒有輸入姓名」——但用戶明明輸入了啊
因為空格是falsy的
場景二:你在判斷列表是否為空
tasks = []if tasks:print("有任務")else:print("沒有任務")
這次你正確使用了if tasks
但如果有人改成這樣呢
tasks = []if tasks == []:print("有任務")else:print("沒有任務")
嗯...也能工作
那我問你,tasks == [] 和 if tasks: 有什麼區別
说不出来往下看
場景三:你在做多重條件判斷
score = 85if score >= 60and < 90:print("及格")
這怎麼了「score >= 60 and < 90」這個語法錯了嗎
运行一下试试
SyntaxError: invalid syntax
你看,你又踩坑了
Python不是數學表達式,不能這樣寫你必須写成score >= 60 and score < 90或者60 <= score < 90
后者能跑,但前者报错,你知道为什么吗
認知反轉:if判斷不是if的事情
看到這裡你是不是覺得「這些我都知道」
你「知道」和你「會用」,中間隔著三個月的實踐
**真正的問題不在於if語法本身,而在於——你根本不理解Python的「真值」概念**
什麼意思
在Python裡,並不是True和False才是布爾值所有值都有「真假」屬性:
這叫Truthiness(真值性)
你可以理解为:Python在执行if x的时候,背后做的是if bool(x)
不理解這個,你的if判断永远写得稀里糊涂
好,認知反轉完了現在上乾貨
代碼示例一:這才是判斷「是否存在」正確姿勢
很多新手喜歡這樣寫:
# 錯誤示範name = input("請輸入名字: ")if name != "":print(f"你好{name}")
或者這樣:
# 另一種錯誤示範name = input("請輸入名字: ")if name isnotNone:print(f"你好{name}")
這些都能跑,但都是業餘選手的寫法
專業選手怎麼寫
#!/usr/bin/env python3"""判斷用戶輸入是否有效的正確姿勢這個例子展示如何正確判斷「用戶是否輸入內容」"""defget_user_name():"""獲取用戶輸入的名字,並進行有效性檢查"""# 提示用戶輸入 name = input("請輸入您的名字: ").strip()# 正確的判斷方式:直接用if(非空字串為truthy)# 這裡用 not name 判斷 name 是否為空字串、None、或只有空格# 因為空字串 "" 在Python中是falsy的ifnot name:print("抱歉,您沒有輸入名字,請重新輸入")returnNone# 或者更嚴格一點:只允許中英文和數字ifnot name.isalnum():print("名字只能包含中文、英文或數字")returnNonereturn namedefmain():"""主函數:演示名字獲取流程"""print("=== 用戶名字獲取系統 ===")print("(直接按回車表示不輸入)\n") name = get_user_name()if name:print(f"\n成功獲取名字:{name}")else:print("\n未獲取到有效的名字")if __name__ == "__main__": main()
運行結果:
=== 用戶名字獲取系統 ===(直接按回車表示不輸入)請輸入您的名字:抱歉,您沒有輸入名字, please重新輸入未獲取到有效的名字
請輸入您的名字: 小甲魚成功獲取名字:小甲魚
關鍵代碼解釋:
# 第29行ifnot name:print("抱歉,您沒有輸入名字,請重新輸入")returnNone
這裡not name的意思是「如果name是falsy值」
什麼是falsy空字串""、None、空列表[]、數字0——都是falsy
這樣寫的好處是:一次判斷搞定所有「沒有有效輸入」的情況,不需要寫if name == "" or name is None or len(name) == 0
這就是**Pythonic(符合Python風格)**的寫法——簡潔、精準、優雅
代碼示例二:這個if-else簡寫,你可能從來沒用對過
三元運算符會不會
# 大多数人这样写score = 85if score >= 60: result = "及格"else: result = "不及格"
但如果是這樣呢
# 稍微简洁一点score = 85result = "及格"if score >= 60else"不及格"
這個你肯定見過但我問你,下面這種呢
# 判断用户VIP等级并返回折扣defget_discount(user_tier):""" 根据用户等级返回折扣 参数: user_tier: 用户等级 (1=普通, 2=银卡, 3=金卡, 4=黑钻) 返回: 折扣比例 (0-1之间) """# 普通写法:要写4个if-elif-elseif user_tier == 1:return1.0# 不打折elif user_tier == 2:return0.95# 95折elif user_tier == 3:return0.90# 9折elif user_tier == 4:return0.80# 8折else:return1.0# 未知等级,不打折# 进阶写法:用字典映射(更Pythonic)defget_discount_vip(user_tier):"""用字典实现折扣映射""" discount_map = {1: 1.0,2: 0.95,3: 0.90,4: 0.80, }# .get() 方法:如果key不存在,返回默认值1.0return discount_map.get(user_tier, 1.0)# 再进阶:字典 + 三元运算(一行代码)defget_discount_pro(user_tier):"""一行代码实现折扣判断""" tier_discount = {1: 1.0, 2: 0.95, 3: 0.90, 4: 0.80}return tier_discount.get(user_tier, 1.0)# 测试if __name__ == "__main__":print("=== 折扣计算演示 ===\n") test_tiers = [1, 2, 3, 4, 5, 0]for tier in test_tiers: disc1 = get_discount(tier) disc2 = get_discount_vip(tier) disc3 = get_discount_pro(tier)print(f"等级{tier}: 普通写法={disc1}, 字典写法={disc2}, 一行版={disc3}")
運行結果:
=== 折扣计算演示 ===等级1: 普通写法=1.0, 字典写法=1.0, 一行版=1.0等级2: 普通写法=0.95, 字典写法=0.95, 一行版=0.95等级3: 普通写法=0.90, 字典写法=0.90, 一行版=0.90等级4: 普通写法=0.80, 字典写法=0.80, 一行版=0.80等级5: 普通写法=1.0, 字典写法=1.0, 一行版=1.0等级0: 普通写法=1.0, 字典写法=1.0, 一行版=1.0
這段代碼的关键点:
# 第65行return tier_discount.get(user_tier, 1.0)
.get() 是字典的方法,語法是字典.get(key, 默认值)
如果key存在,返回對應的value;如果key不存在,返回你指定的默认值
這意味著:
**一個字典 + 一個.get(),幹掉了4個if-elif-else**
這就是Python的思维方式:用数据结构代替控制结构
代码示例三:多重判断的正确写法
回到前面讲的「分数判断」问题:
score = 85# 错误的写法 - 会报语法错误if score >= 60and < 90:print("及格")# 正确的写法 1 - 完整比较if score >= 60and score < 90:print("及格")# 正确的写法 2 - Python的特殊语法(链式比较)if60 <= score < 90:print("及格")
第三種写法看起来很爽,但很多人不知道原理
Python支持这种「链式比较」:
# 普通写法a < b and b < c# 链式写法a < b < c
这两者是等价的
但链式写法有一个普通写法没有的特性:它会先求值一次,然后逐步比较
比如60 <= score < 90,Python会这样执行:
- 1. 先比较
60 <= score,得到True或False - 2. 然后把结果和90比较:
True < 90或False < 90
如果是False < 90,Python会尝试把False转成0来比较(False被当作0)...
这意味着什么
score = 50# 结果是False and ? -> False# 不会报错print(60 <= score < 90) # False# 但如果写成print(score >= 60and score < 90) # 也会报错吗?不会,都是False
**但是链式比较的坑在于:它会按顺序执行,可能产生意想不到的行为**
比如:
# 这个例子展示链式比较的潜在问题defcheck_age(age):"""检查年龄是否在合理范围内"""print(f"\n检查年龄: {age}")# 链式写法 result1 = 0 < age < 120print(f" 链式 (0 < age < 120): {result1}")# 分开写 result2 = age > 0and age < 120print(f" 分开 (age > 0 and age < 120): {result2}")return result1defmain():"""多重比较的完整示例"""print("=== 年龄验证系统 ===\n") test_ages = [-5, 0, 1, 18, 50, 100, 120, 150]for age in test_ages: is_valid = check_age(age) status = "✓ 有效"if is_valid else"✗ 无效"print(f" 结果: {status}\n")if __name__ == "__main__": main()
运行结果:
=== 年龄验证系统 ===检查年龄: -5 链式 (0 < age < 120): False 分开 (age > 0 and age < 120): False 结果: ✗ 无效检查年龄: 0 链式 (0 < age < 120): False # 注意!年龄0不算「有效」 分开 (age > 0 and age < 120): False 结果: ✗ 无效检查年龄: 1 链式 (0 < age < 120): True 分开 (age > 0 and age < 120): True 结果: ✓ 有效检查年龄: 18 链式 (0 < age < 120): True 分开 (age > 0 and age < 120): True 结果: ✓ 有效...
代码解释:
# 第16行result1 = 0 < age < 120
这里0 < age < 120等价于(0 < age) and (age < 120)
Python会先计算0 < age:
- • 然后
False < 120,False被转成0,结果是0 < 120 = True
但实际上我们期望的是「年龄为负数应该返回False」
所以结果是False and ? = False,最终还是False
虽然结果碰巧对了,但执行过程不同
# 第19行result2 = age > 0and age < 120
这种写法更清晰,也更安全
我的建议:
- • 简单的链式比较可以用:如
0 <= score <= 100(成绩在0-100分之间) - • 复杂的判断还是拆开写:
score >= 60 and score < 90 and level > 0
代码示例四:None和is的坑,你必须知道
开头说的那个if x is 10的坑,现在来填上:
#!/usr/bin/env python3"""展示 == 和 is 的区别这是Python面试常考的知识点"""defcompare_demo():"""演示 == 和 is 的区别"""print("=== == vs is 对比演示 ===\n")# 案例1:整数缓存问题 a = 256 b = 256print("案例1: 整数缓存 (Python对-5到256有缓存)")print(f" a = 256, b = 256")print(f" a == b: {a == b}") # True(值相等)print(f" a is b: {a is b}") # True(Python缓存了256)print()# 案例2:超出缓存范围 a = 257 b = 257print("案例2: 超出缓存范围 (Python不会缓存257)")print(f" a = 257, b = 257")print(f" a == b: {a == b}") # True(值相等)print(f" a is b: {a is b}") # False(不是同一个对象!)print()# 案例3:字符串 a = "hello" b = "hello"print("案例3: 字符串")print(f" a = 'hello', b = 'hello'")print(f" a == b: {a == b}") # Trueprint(f" a is b: {a is b}") # True(Python也会缓存短字符串)print()# 案例4:列表 a = [1, 2, 3] b = [1, 2, 3]print("案例4: 列表(永远不等价)")print(f" a = [1,2,3], b = [1,2,3]")print(f" a == b: {a == b}") # True(值相等)print(f" a is b: {a is b}") # False(两个不同的列表对象)print()defidentity_vs_equality():"""理解身份vs相等性的实际应用"""print("=== 实际应用:判断是否为None ===\n")# 常见错误:用 == 判断 None x = None y = []print("错误写法:")print(f" x = None, y = []")print(f" x == None: {x == None}") # Trueprint(f" y == []: {y == []}") # Trueprint("\n正确写法(用 is):")print(f" x is None: {x isNone}") # Trueprint(f" y is None: {y isNone}") # False# 列表判空的最佳实践print("\n判空的最佳实践:")print(f" if not y: # 正确,判断falsy")print(f" if y == []: # 能用但不推荐")print(f" if y is []: # 永远不要这样写!" )defmain(): compare_demo() identity_vs_equality()if __name__ == "__main__": main()
运行结果:
=== == vs is 对比演示 ===案例1: 整数缓存 (Python对-5到256有缓存) a = 256, b = 256 a == b: True a is b: True案例2: 超出缓存范围 (Python不会缓存257) a = 257, b = 257 a == b: True a is b: False案例3: 字符串 a = 'hello', b = 'hello' a == b: True a is b: True案例4: 列表(永远不等价) a = [1,2,3], b = [1,2,3] a == b: True a is b: False=== 实际应用:判断是否为None ===错误写法: x = None, y = [] x == None: True y == []: True正确写法(用 is): x is None: True y is None: False判空的最佳实践: if not y: # 正确,判断falsy if y == []: # 能用但不推荐 if y is []: # 永远不要这样写!
核心知识点:
# == 是判断值是否相等# is 是判断是否是同一个对象(内存地址是否相同)
用is的场景只有一个:判断None
因为None在Python中是一个单例(只有唯一一个),所以x is None是判断「x是不是None这个对象」的正确方式
其他所有情况都用==
代码示例五:一个完整的业务场景
光讲知识点不过瘾,来一个真实的业务场景:用户权限判断系统
#!/usr/bin/env python3"""用户权限判断系统这是一个综合性的if判断练习,包括:- 多重条件判断- None值处理- 链式比较- 三元运算符"""from datetime import datetimefrom typing importOptionalclassUser:"""用户类"""def__init__(self, username, age, vip_level, balance, login_time):self.username = usernameself.age = ageself.vip_level = vip_levelself.balance = balanceself.login_time = login_time # 最近登录时间defcheck_user_permissions(user: Optional[User]) -> dict:""" 检查用户权限并返回权限字典 返回: 包含各项权限的字典 """# 第一步:用户是否存在# 用 is None 判断(这是唯一该用 is 的场景)if user isNone:return {"can_login": False,"can_vip": False,"discount": 1.0,"message": "用户不存在" }# 第二步:年龄是否有效(使用链式比较)# 0 < age < 150 是合理的年龄范围ifnot (0 < user.age < 150):return {"can_login": False,"can_vip": False,"discount": 1.0,"message": f"年龄{user.age}无效" }# 第三步:判断是否成年人(用三元运算符) is_adult = "成年"if user.age >= 18else"未成年"print(f"用户{user.username}: {is_adult} ({user.age}岁)")# 第四步:根据VIP等级判断权限if user.vip_level == 0: discount = 1.0 can_vip = True message = "普通用户" max_withdraw = 1000elif user.vip_level <= 3: discount = 1.0 - (user.vip_level * 0.05) # 95~85折 can_vip = True message = f"VIP{user.vip_level}用户" max_withdraw = 10000 * user.vip_levelelse: # vip_level >= 4 discount = 0.7# 7折 can_vip = False# 已经是最高级 message = "黑钻用户" max_withdraw = 100000# 第五步:余额判断(多重比较)# 这里不能用链式比较,因为有3个条件if user.balance >= 10000: priority = "高"elif user.balance >= 1000: priority = "中"else: priority = "低"return {"can_login": True,"can_vip": can_vip,"discount": discount,"message": message,"max_withdraw": max_withdraw,"priority": priority, }defmain():"""主函数:测试权限系统"""print("=== 用户权限判断系统 ===\n")# 创建测试用户 users = [ User("张三", 25, 0, 500, datetime.now()), # 普通成年用户 User("李四", 17, 2, 2000, datetime.now()), # 未成年VIP User("王五", 30, 4, 50000, datetime.now()), # 黑钻用户 User("赵六", 999, 0, 100, datetime.now()), # 年龄异常 User(None, None, None, None, None), # 空用户 ]# 测试每个用户for user in users:print(f"\n--- 测试用户: {user} ---") result = check_user_permissions(user)print(f" 登录权限: {'✓'if result['can_login'] else'✗'}")print(f" 折扣: {result['discount']:.0%}")print(f" 说明: {result['message']}")print(f" 优先级: {result.get('priority', 'N/A')}")print(f" 最高提现: {result.get('max_withdraw', 'N/A')}")if"message"in result:print(f" 全局消息: {result['message']}")print()if __name__ == "__main__": main()
运行结果:
=== 用户权限判断系统 ===--- 测试用户: <__main__.User object at 0x7f8c1c104c50> ---用户张三: 成年 (25岁) 登录权限: ✓ 折扣: 100% 说明: 普通用户 优先级: 低 最高提现: 1000--- 测试用户: <__main__.User object at 0x7f8c1c104c90> ---用户李四: 未成年 (17岁) 登录权限: ✓ 折扣: 90% 说明: VIP2用户 优先级: 中 最高提现: 20000--- 测试用户: <__main__.User object at 0x7f8c1c104cd0> ---用户王五: 成年 (30岁) 登录权限: ✓ 折扣: 70% 说明: 黑钻用户 优先级: 高 最高提现: 100000--- 测试用户: <__main__.User object at 0x7f8c1c104d10> ---用户赵六: 成年 (999岁) 登录权限: ✗ 折扣: 100% 说明: 年龄999无效 全局消息: 年龄999无效--- 测试用户: <__main__.User object at 0x7f8c1c105050> ---用户None: 无法创建User对象 (需要username)
代码要点总结:
# 第45行:用 is None 判断if user isNone:return {...}# 第53行:链式比较(年龄范围判断)ifnot (0 < user.age < 150):return {...}# 第59行:三元运算符(三行缩成一行)is_adult = "成年"if user.age >= 18else"未成年"# 第63-77行:elif多重判断(VIP等级)if user.vip_level == 0: ...elif user.vip_level <= 3: ...else: ...# 第82-88行:多重比较不能用链式(3个分支)if user.balance >= 10000: priority = "高"elif user.balance >= 1000: ...else: ...
这是一段可以直接套用到你项目里的代码
总结:今天学到了什么?
三个核心要点:
- • 空值:0, "", [], {}, None 都是 falsy
- • 判空直接用
if not x:,别写 if x == "" or x == 0:
- • 复杂的还是拆开写:
x >= 60 and x < 90
今天就可以做的事情
- 1. 打开你的项目,搜一下有没有
if x is 10: 这种代码
- • 如果你还在写
if name == "" or name == None:
下期预告
下一期讲什么
**循环的坑**
for 和 while 怎么选
为什么你的循环跑一次就停了
为什么在循环里改列表会出问题
想看的,关注【Python小甲鱼】,下期见
*本文代码均可直接复制运行,有问题欢迎评论区留言*