python条件分支语句例子,python分支结构的条件表达式
本文主要介绍Python编写条件分支代码的方法。编写条件分支代码是编码过程中不可缺少的一部分。有关更多详细信息,请参考以下文章。
前言最佳实践1。避免多个分支嵌套2。封装那些过于复杂的逻辑判断3。注意不同分支下的重复代码4。谨慎使用三元表达式的常用技巧1。使用“德摩根定律”2。自定义对象3的布尔值true和false。在条件判断4中使用all ()/any()。在try/while/for中使用else。
目录
编写条件分支代码是编码过程中不可缺少的一部分。如果用道路来比喻,现实世界中的代码从来都不是一条笔直的高速公路,而更像是由无数岔路组成的一个城区的地图。我们编码员就像司机一样,需要告诉我们的程序在下一个路口左转还是右转。
编写优秀的条件分支代码非常重要,因为糟糕而复杂的分支处理很容易让人迷惑,从而降低代码质量。因此,本文将重点讨论用Python写分支代码时应该注意些什么。
Python 里的分支代码:
Python支持最常见的if/else条件分支语句,但它缺少其他编程语言中常见的switch/case语句。
此外,Python还提供了for/while循环和try/except语句的else分支,可用于一些特殊场景。
我将从最佳实践、常用技巧和常见陷阱三个方面来谈谈如何写出优秀的条件分支代码。
前言
最佳实践
如果这篇文章只能以一句话结尾,那么那句话一定是“尽量避免分支嵌套”。
太深的分支嵌套是许多新程序员最常犯的错误之一。如果一个JavaScript编程新手编写了多层分支嵌套,您可能会看到多层花括号:if {if {if {.}}}.俗称“嵌套If语句地狱”。
但是因为Python使用的是缩进而不是{},所以嵌套过深的分支会产生比其他语言更严重的后果。例如,过多的缩进级别很容易使代码超过PEP8中指定的每行字数限制。
让我们看看这段代码:
defbuy_fruit(书呆子,商店):
去水果店买苹果。
-我们先看看商店是否开门。
-如果有苹果,就买一个。
-如果钱不够,回家拿点钱。
ifstore.is_open():
if store . has _ stocks( apple ):
if nerd . can _ affordable(store . price( apple ,amount=1)):
nerd.buy(商店,苹果,金额=1)
返回
else:
nerd.go_home_and_get_money()
returnbuy_fruit(书呆子,商店)
else:
raisedatnofruit( noappleinstore!)
else:
raisedatnofruit( storeisclosed!)
上述代码的最大问题是,它直接翻译了原始的条件分支需求,导致只有十几行代码包含三个嵌套分支。
这样的代码可读性和维护性都很差。不
过我们可以用一个很简单的技巧:提前结束来优化这段代码:
def buy_fruit(nerd, store):if not store.is_open():
raise MadAtNoFruit("store is closed!")
if not store.has_stocks("apple"):
raise MadAtNoFruit("no apple in store!")
if nerd.can_afford(store.price("apple", amount=1)):
nerd.buy(store, "apple", amount=1)
return
else:
nerd.go_home_and_get_money()
return buy_fruit(nerd, store)
提前结束指:在函数内使用 return 或 raise 等语句提前在分支内结束函数。比如,在新的 buy_fruit 函数里,当分支条件不满足时,我们直接抛出异常,结束这段这代码分支。这样的代码没有嵌套分支,更直接也更易读。
2. 封装那些过于复杂的逻辑判断
如果条件分支里的表达式过于复杂,出现了太多的 not/and/or,那么这段代码的可读性就会大打折扣,比如下面这段代码:
# 如果活动还在开放,并且活动剩余名额大于 10,为所有性别为女性,或者级别大于 3# 的活跃用户发放 10000 个金币
if activity.is_active and activity.remaining > 10 and
user.is_active and (user.sex == female or user.level > 3):
user.add_coins(10000)
return
对于这样的代码,我们可以考虑将具体的分支逻辑封装成函数或者方法,来达到简化代码的目的:
if activity.allow_new_user() and user.match_activity_condition():user.add_coins(10000)
return
事实上,将代码改写后,之前的注释文字其实也可以去掉了。因为后面这段代码已经达到了自说明的目的。至于具体的什么样的用户满足活动条件?这种问题,就应由具体的 match_activity_condition() 方法来回答了。
Hint:恰当的封装不光直接改善了代码的可读性,事实上,如果上面的活动判断逻辑在代码中出现了不止一次的话,封装更是必须的。不然重复代码会极大的破坏这段逻辑的可维护性。
3. 留意不同分支下的重复代码
重复代码是代码质量的天敌,而条件分支语句又非常容易成为重复代码的重灾区。所以,当我们编写条件分支语句时,需要特别留意,不要生产不必要的重复代码。
让我们看下这个例子:
# 对于新用户,创建新的用户资料,否则更新旧资料if user.no_profile_exists:
create_user_profile(
username=user.username,
email=user.email,
age=user.age,
address=user.address,
# 对于新建用户,将用户的积分置为 0
points=0,
created=now(),
)
else:
update_user_profile(
username=user.username,
email=user.email,
age=user.age,
address=user.address,
updated=now(),
)
在上面的代码中,我们可以一眼看出,在不同的分支下,程序调用了不同的函数,做了不一样的事情。但是,因为那些重复代码的存在,我们却很难简单的区分出,二者的不同点到底在哪。
其实,得益于 Python 的动态特性,我们可以简单的改写一下上面的代码,让可读性可以得到显著的提升:
if user.no_profile_exists:profile_func = create_user_profile
extra_args = {points: 0, created: now()}
else:
profile_func = update_user_profile
extra_args = {updated: now()}
profile_func(
username=user.username,
email=user.email,
age=user.age,
address=user.address,
**extra_args
)
当你编写分支代码时,请额外关注由分支产生的重复代码块,如果可以简单的消灭它们,那就不要迟疑。
4. 谨慎使用三元表达式
三元表达式是 Python 2.5 版本后才支持的语法。在那之前,Python 社区一度认为三元表达式没有必要,我们需要使用 x and a or b 的方式来模拟它。
事实是,在很多情况下,使用普通的 if/else 语句的代码可读性确实更好。盲目追求三元表达式很容易诱惑你写出复杂、可读性差的代码。
所以,请记得只用三元表达式处理简单的逻辑分支
language = "python" if you.favor("dynamic") else "golang"
对于绝大多数情况,还是使用普通的 if/else 语句吧。
常见技巧
1.使用德摩根定律
在做分支判断时,我们有时候会写成这样的代码:
# 如果用户没有登录或者用户没有使用 chrome,拒绝提供服务if not user.has_logged_in or not user.is_from_chrome:
return "our service is only available for chrome logged in user"
第一眼看到代码时,是不是需要思考一会才能理解它想干嘛?这是因为上面的逻辑表达式里面出现了 2 个 not 和 1 个 or。而我们人类恰好不擅长处理过多的否定以及或这种逻辑关系。
这个时候,就该德摩根定律出场了。通俗的说,德摩根定律就是 not A or not B 等价于 not (A and B)。通过这样的转换,上面的代码可以改写成这样:
if not (user.has_logged_in and user.is_from_chrome):return "our service is only open for chrome logged in user"
怎么样,代码是不是易读了很多?记住德摩根定律,很多时候它对于简化条件分支里的代码逻辑非常有用。
2. 自定义对象的布尔真假
我们常说,在 Python 里,万物皆对象。其实,不光万物皆对象,我们还可以利用很多魔法方法(文档中称为:user-defined method)
我们可以用很多在别的语言里面无法做到、有些魔法的方式来影响代码的执行。
比如,Python 的所有对象都有自己的布尔真假:
布尔值为假的对象:None, 0, False, [], (), {}, set(), frozenset(), ... ...
布尔值为真的对象:非 0 的数值、True,非空的序列、元组,普通的用户类实例,... ...
通过内建函数 bool(),你可以很方便的查看某个对象的布尔真假。而 Python 进行条件分支判断时用到的也是这个值:
>>> bool(object())True
重点来了,虽然所有用户类实例的布尔值都是真。但是 Python 提供了改变这个行为的办法:自定义类的__bool__魔法方法(在 Python 2.X 版本中为nonzero)。当类定义了 bool 方法后,它的返回值将会被当作类实例的布尔值。
另外,bool不是影响实例布尔真假的唯一方法。如果类没有定义 bool 方法,Python 还会尝试调用len 方法(也就是对任何序列对象调用 len 函数),通过结果是否为 0 判断实例真假。
那么这个特性有什么用呢?看看下面这段代码:
class UserCollection(object):def __init__(self, users):
self._users = users
users = UserCollection([piglei, raymond])
if len(users._users) > 0:
print("Theres some users in collection!")
上面的代码里,判断 UserCollection 是否有内容时用到了 users._users 的长度。其实,通过为 UserCollection 添加 len 魔法方法,上面的分支可以变得更简单:
class UserCollection:def __init__(self, users):
self._users = users
def __len__(self):
return len(self._users)
users = UserCollection([piglei, raymond])
# 定义了 __len__ 方法后,UserCollection 对象本身就可以被用于布尔判断了
if users:
print("Theres some users in collection!")
通过定义魔法方法 len 和 bool ,我们可以让类自己控制想要表现出的布尔真假值,让代码变得更 pythonic。
3. 在条件判断中使用 all() / any()
all() 和 any() 两个函数非常适合在条件判断中使用。这两个函数接受一个可迭代对象,返回一个布尔值,其中:
- all(seq):仅当 seq 中所有对象都为布尔真时返回 True,否则返回 False
- any(seq):只要 seq 中任何一个对象为布尔真就返回 True,否则返回 False
假如我们有下面这段代码:
def all_numbers_gt_10(numbers):"""仅当序列中所有数字大于 10 时,返回 True
"""
if not numbers:
return False
for n in numbers:
if n <= 10:
return False
return True
如果使用 all() 内建函数,再配合一个简单的生成器表达式,上面的代码可以写成这样:
def all_numbers_gt_10_2(numbers):return bool(numbers) and all(n > 10 for n in numbers)
简单、高效,同时也没有损失可用性。
4. 使用 try/while/for 中 else 分支
让我们看看这个函数:
def do_stuff():first_thing_successed = False
try:
do_the_first_thing()
first_thing_successed = True
except Exception as e:
print("Error while calling do_some_thing")
return
# 仅当 first_thing 成功完成时,做第二件事
if first_thing_successed:
return do_the_second_thing()
在函数 do_stuff 中,我们希望只有当 do_the_first_thing() 成功调用后(也就是不抛出任何异常),才继续做第二个函数调用。为了做到这一点,我们需要定义一个额外的变量 first_thing_successed 来作为标记。
其实,我们可以用更简单的方法达到同样的效果:
def do_stuff():try:
do_the_first_thing()
except Exception as e:
print("Error while calling do_some_thing")
return
else:
return do_the_second_thing()
在 try 语句块最后追加上 else 分支后,分支下的do_the_second_thing() 便只会在 try 下面的所有语句正常执行(也就是没有异常,没有 return、break 等)完成后执行。
类似的,Python 里的 for/while 循环也支持添加 else 分支,它们表示:当循环使用的迭代对象被正常耗尽、或 while 循环使用的条件变量变为 False 后才执行 else 分支下的代码。
常见
1.与 None 值的比较
在 Python 中,有两种比较变量的方法:== 和 is,二者在含义上有着根本的区别:
- ==:表示二者所指向的的值是否一致
- is:表示二者是否指向内存中的同一份内容,也就是 id(x) 是否等于 id(y)
None 在 Python 语言中是一个单例对象,如果你要判断某个变量是否为 None 时,记得使用 is 而不是 ==,因为只有 is 才能在严格意义上表示某个变量是否是 None。
否则,可能出现下面这样的情况:
>>> class Foo(object):... def __eq__(self, other):
... return True
...
>>> foo = Foo()
>>> foo == None
True
在上面代码中,Foo 这个类通过自定义 eq 魔法方法的方式,很容易就满足了 == None 这个条件。
所以,当你要判断某个变量是否为 None 时,请使用 is 而不是==。
2. 留意 and 和 or 的运算优先级
看看下面这两个表达式,猜猜它们的值一样吗?
>>> (True or False) and False>>> True or False and False
答案是:不一样,它们的值分别是 False 和 True,你猜对了吗?
问题的关键在于:and 运算符的优先级大于 or。因此上面的第二个表达式在 Python 看来实际上是 True or (False and False)。所以结果是 True 而不是 False。
在编写包含多个 and 和 or 的表达式时,请额外注意 and 和 or 的运算优先级。即使执行优先级正好是你需要的那样,你也可以加上额外的括号来让代码更清晰。
结语
代码内的分支语句不可避免,我们在编写代码时,需要尤其注意它的可读性,避免对其他看到代码的人造成困扰。
到此这篇关于Python编写条件分支代码方法的文章就介绍到这了,更多相关Python条件分支内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。