返回顶部
首页 > 资讯 > 后端开发 > Python >Python编写条件分支代码方法
  • 172
分享到

Python编写条件分支代码方法

2024-04-02 19:04:59 172人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言最佳实践1.避免多层分支嵌套2. 封装那些过于复杂的逻辑判断3. 留意不同分支下的重复代码4. 谨慎使用三元表达式常见技巧1.使用“德摩根定律”2.

前言

编写条件分支代码是编码过程中不可或缺的一部分。如果用道路来做比喻,现实世界中的代码从来都不是一条笔直的高速公路,而更像是由无数个岔路口组成的某个市区地图。我们编码者就像是驾驶员,需要告诉我们的程序,下个路口需要往左还是往右。

编写优秀的条件分支代码非常重要,因为糟糕、复杂的分支处理非常容易让人困惑,从而降低代码质量。所以,这篇文章将会种重点谈谈在 python 中编写分支代码应该注意的地方。

Python 里的分支代码:

Python 支持最为常见的 if/else 条件分支语句,不过它缺少在其他编程语言中常见的 switch/case 语句。

除此之外,Python 还为 for/while 循环以及 try/except 语句提供了 else 分支,在一些特殊的场景下,它们可以大显身手。

下面我会从 最佳实践、常见技巧、常见陷阱 三个方面讲一下如果编写优秀的条件分支代码。

最佳实践

1.避免多层分支嵌套

如果这篇文章只能删减成一句话就结束,那么那句话一定是“要竭尽所能的避免分支嵌套”。

过深的分支嵌套是很多编程新手最容易犯的错误之一。假如有一位新手 javascript 程序员写了很多层分支嵌套,那么你可能会看到一层又一层的大括号:if { if { if { ... }}}。俗称“嵌套 if 地狱(Nested If Statement Hell)”。

但是因为 Python 使用了缩进来代替 {},所以过深的嵌套分支会产生比其他语言下更为严重的后果。比如过多的缩进层次很容易就会让代码超过 PEP8 中规定的每行字数限制。

让我们看看这段代码:

def buy_fruit(nerd, store):
    """去水果店买苹果

    - 先得看看店是不是在营业
    - 如果有苹果的话,就买 1 个
    - 如果钱不够,就回家取钱再来
    """
    if store.is_open():
        if store.has_stocks("apple"):
            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)
        else:
            raise MadAtNoFruit("no apple in store!")
    else:
        raise MadAtNoFruit("store is closed!")

上面这段代码最大的问题,就是过于直接翻译了原始的条件分支要求,导致短短十几行代码包含了有三层嵌套分支。

这样的代码可读性和维护性都很差。不过我们可以用一个很简单的技巧:“提前结束” 来优化这段代码:

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("There's 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("There's 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条件分支内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python编写条件分支代码方法

本文链接: https://lsjlt.com/news/118435.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python编写条件分支代码方法
    目录前言最佳实践1.避免多层分支嵌套2. 封装那些过于复杂的逻辑判断3. 留意不同分支下的重复代码4. 谨慎使用三元表达式常见技巧1.使用“德摩根定律”2. ...
    99+
    2024-04-02
  • Java代码编写的30条建议分别有哪些
    Java代码编写的30条建议分别有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。(1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包...
    99+
    2023-06-17
  • python编写execl文件方法
    1. 安装xlwt模块1)下载地址https://pypi.python.org/pypi/xlwt#downloads2)安装方法tar zxvf xlwt-1.1.2.tar.gzcd xlwt-1.1.2python setup.py...
    99+
    2023-01-31
    文件 方法 python
  • 编写Python代码的方式是什么
    这篇文章主要讲解了“编写Python代码的方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“编写Python代码的方式是什么”吧!Python以句法简单、简洁而闻名,只需掌握简单的英语...
    99+
    2023-06-16
  • 浅谈python条件表达式:多项分支,双向分支
    如下所示: # ### 多项分支 '''<br> if 条件表达式1: code1 code2 elif 条件表达式2: code3 ...
    99+
    2024-04-02
  • 了解python条件表达式:多项分支,双向分支
    这篇文章主要讲解了“了解python条件表达式:多项分支,双向分支”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“了解python条件表达式:多项分支,双向分支”吧!Python主要用来做什么...
    99+
    2023-06-14
  • C++代码编写举例分析
    本篇内容主要讲解“C++代码编写举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++代码编写举例分析”吧!C++代码如下://log.h   #ifndef...
    99+
    2023-06-17
  • 编写vbs/js基础代码方法教程
    这篇文章主要讲解了“编写vbs/js基础代码方法教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“编写vbs/js基础代码方法教程”吧!我们的第一个vbs程序:还是那个老得掉牙的冬冬。 **...
    99+
    2023-06-08
  • Python文件相关应用方案以及代码怎么编写
    Python文件相关应用方案以及代码怎么编写,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python  文件import os  im...
    99+
    2023-06-17
  • 如何快速编写Python代码
    本篇内容主要讲解“如何快速编写Python代码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何快速编写Python代码”吧!1."二维列表"...
    99+
    2024-04-02
  • Python文件处理方法实例代码分析
    今天小编给大家分享一下Python文件处理方法实例代码分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起...
    99+
    2024-04-02
  • python九九乘法表编程代码怎么写
    以下是Python中打印九九乘法表的代码:```pythonfor i in range(1, 10):for j in range...
    99+
    2023-10-11
    python
  • Python加法代码怎么写_Python加法代码写法教程
    1、首先打开在线python编辑页面。 2、然后在程序区输入程序代码。 3、接着点击左上角的】运行【,输入第一个加数,按下回车,输入第二个加数。 4、最后按下回车,得出两个加数的和...
    99+
    2024-04-02
  • python二分查找算法代码怎么写
    下面是一个示例的Python二分查找算法代码: def binary_search(arr, target): left =...
    99+
    2023-10-22
    python
  • Python编写春联的示例代码(支持行书隶书楷书)
    目录选择矢量字库选择一款喜欢的春联背景图案完整代码效果展示仅供学习编程技术之用,绝无侵犯字体权利人之权力的故意,特此声明。 选择矢量字库 虽然有很多方法可以帮你呈现出系统支持的所有字...
    99+
    2024-04-02
  • 写好Python代码的几条重要技巧
    目录面向对象五个基本原则立竿见影的单一职责原则让代码稳定性飞升的开放封闭原则和依赖倒置原则挑肥拣瘦的接口隔离原则轻装上阵的合成复用原则常见的三种架构单体架构分布式架构微服务架构分布式和微服务并不是银弹画好图起一个好名...
    99+
    2022-06-02
    python 代码技巧 写好python技巧
  • Swift语言编写代码的方法有哪些
    本篇内容主要讲解“Swift语言编写代码的方法有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Swift语言编写代码的方法有哪些”吧!在初始化时调用will...
    99+
    2024-04-02
  • Python编程实现二分法和牛顿迭代法求平方根代码
    求一个数的平方根函数sqrt(int num) ,在大多数语言中都提供实现。那么要求一个数的平方根,是怎么实现的呢? 实际上求平方根的算法方法主要有两种:二分法(binary search)和牛顿迭代法(N...
    99+
    2022-06-04
    迭代法 平方根 代码
  • mysql支持gbk编码的方法
    小编给大家分享一下mysql支持gbk编码的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!mysql支持gbk编码的方法:首...
    99+
    2024-04-02
  • Python贪吃蛇游戏编写代码
    最近在学Python,想做点什么来练练手,命令行的贪吃蛇一般是C的练手项目,但是一时之间找不到别的,就先做个贪吃蛇来练练简单的语法。 由于Python监听键盘很麻烦,没有C语言的kbhit(),所以这条贪吃...
    99+
    2022-06-04
    贪吃蛇 代码 游戏
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作