• 条件分支控制流高级用法


    条件分支控制流高级用法

    1.概述

    这篇文章总结条件判断的一些高级用法,总结下条件分支控制流使用策略。

    • 在编程中能不用条件就不用
    • 能不嵌套条件表达式就不要嵌套
    • 能简化条件表达式就不要复杂化条件表达式。

    2.条件控制流高级用法

    2.1.省略零值判断

    当你编写if分支时,如果需要判断某个类型的对象是否是零值,可能会把代码写成下面。

    if containers_count == 0
    
    if fruits_list != []
    
    • 1
    • 2
    • 3

    这种判断语句其实可以变得更简单,因为某个对象作为主角出现在if分支里,解释器会主动对它进行“真值测试”,也就是调用bool()函数获取他的布尔值。
    每类对象都有着各自的规则。
    布尔值为假:None、0、False、[]、()、{}、set()、frozenset()、等
    布尔值为真:非0的数值、True、非空的列表、元组、字典、用户定义的类和实例等等

    if not containers_count:
    
    if not fruits_list
    
    • 1
    • 2
    • 3

    2.2.把否定逻辑移入表达式内

    在构造布尔逻辑表达式时,你可以用not关键字来表达否定含义。

    i > 8
    not i>8
    
    • 1
    • 2

    有时候过于使用not关键字,反倒忘记了运算符本身就可以表达否定逻辑。这样的代码,就好比你在看到一个人沿着楼梯往上走时,不说“他在上楼”,非要说“他在做和下楼相反的事情”

    if not number < 10
    if not index == 1
    
    • 1
    • 2

    如果把否定逻辑移入表达式内,他们可以改成下面这样。

    if number >= 10
    if current_user is not None
    
    • 1
    • 2

    2.3.尽可能让三元表达式保持简单

    除了标准的分支,python提供了浓缩的表达式,三元表达式

    # 三元表达式语法
    true_value if <expression> else false_value
    
    • 1
    • 2

    2.4.修改对象的布尔值

    class UserCollection:
        def __init__(self, users):
            self.items = users
    
    users = UserCollection(['xiaoming', 'xiaozhang'])
    if len(users.items) > 0:
       print(f'这个属性有值:{users.items}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面的示例判断user对象是否真的有内容,因此在分支判断语句用到了len(users.items) > 0 这样的表达式,其实这个可以变得更简单。
    只要给UserCollection类实现__len__魔法方法,users对象就可以直接用于“真值测试”

    class userCollection_v2:
        def __init__(self, users):
            self.items = users
        # 为类定义len魔法方法,python在计算这类对象的布尔值时,会受len(users)的结果影响,假如长度为0,布尔值为False,反之为True
        def __len__(self):
            return len(self.items)
    
    users = userCollection_v2(['xiaoming', 'xiaozhang'])
    # 不在需要手动判断对象内部items的长度
    if users:
        print(f'这个属性有值:{users.items}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    不过定义len并非影响布尔值结果的唯一办法,还有一个魔法方法__bool__和对象的布尔值息息相关。
    为对象定义__bool__方法后,对它进行布尔值运算会直接返回该方法的调用结果。

    class ScoreJudger:
        def __init__(self, score):
            self.score = score
    
        # 仅当分数大于60时为真
        def __bool__(self):
            return self.score >= 60
    if ScoreJudger(60):
        print('true')
    else:
        print('false')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果一个类中同时定义了__len__和__bool__两个方法,解释器会优先使用__bool__方法的执行结果。

    2.5.判断对象None时用is运算符

    当我们判断两个对象是否相等时,可以使用双等号和is来判断,但是他们是有区别的。因此我们需要了解它的区别在根据场景选择使用哪个方式。

    • 双等号对比两个对象的值是否相等,行为可被__eq__方法重载
    • is判断两个对象指向的内存地址是否是同一个,无法被重载。当在执行x is y时,其实就是在判断id(x)和id(y)的结果是否相等。
    1.双等号计算两个对象是否相等
    # is与==
    x,y,z = 1, 1, 2
    print('x == y的结果:', x == y)
    print('x == z的结果:', x == z)
    
    # 重写eq方法
    class EqualWithAnything:
        def __eq__(self, other):
            '''
            判断 x == y
            :param other: y的值
            :return:
            '''
            return True
    foo = EqualWithAnything()
    print('重写eq魔法方法后,上面定义的EqualWithAnything对象,在和任何对象做==计算时都会返回True。', foo == None)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2.is计算两个对象是否相等

    当你想判断对象是否为None时,应该使用is运算符,它的行为不会被重写。

    print('is判断对象是否为None', foo is None)
    # 输出结果
    False
    
    x = None
    print('有且仅有真正的None 才能通过is判断', x is None)
    # 输出结果
    True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    既然is在进行比较时更严格,为什么不把所有判断都用is来替代那?
    这是因为,除了None,True,False这三个内置对象以外,其他类型对象在python中并不是严格以单例模式存在的,即便值一致他们在内存中仍然可以是两个对象。
    因此当你需要判断某个对象是否是None,True,False时,使用is,其他情况下使用 ==

    2.6.消失的分支

    从一份电影数据中提取电影信息,按照评分rating的值把电影划分为S、A、B、C、等级;按照指定顺序输出电影信息。

    1.电影分析工具第一个版本
    import random
    
    movies = [{'name': '侠客行', 'year': 2008, 'rating': '9'},
              {'name': '西游记', 'year': 1983, 'rating': '9'},
              {'name': '厨神', 'year': 2010, 'rating': '7'},
              {'name': '喜来乐', 'year': 2006, 'rating': '6.9'},
              {'name': '康熙来了', 'year': 2021, 'rating': '8'}
              ]
    
    
    class Movies:
        def __init__(self, name, year, rating):
            self.name = name
            self.year = year
            self.rating = rating
    
        @property
        def rank(self):
            '''
            根据评分对电影分级
            -S:8.5分以上
            -A: 8~8.5
            -B: 7~8
            -C: 6~7
            -D: 6分以下
            '''
            rating_num = float(self.rating)
            if rating_num >= 8.5:
                return 'S'
            elif rating_num > 8:
                return 'A'
            elif rating_num > 7:
                return 'B'
            elif rating_num > 6:
                return 'C'
            else:
                return 'D'
    
    
    def get_scorted_movies(movies, sorting_type):
        '''
        电影列表排序并返回结果
        :param movies: 对象列表
        :param sorting_type: 排序选项
        :return:
        '''
        if sorting_type == "name":
            sorted_movies = sorted(movies, key=lambda movie: movie.name.lower())
        elif sorting_type == "rating":
            sorted_movies = sorted(movies, key=lambda movie: float(movie.rating), reverse=True)
        elif sorting_type == "year":
            sorted_movies = sorted(movies, key=lambda movie: movie.year, reverse=True)
        elif sorting_type == "random":
            sorted_movies = sorted(movies, key=lambda movie: random.random())
        else:
            raise RuntimeError(f'Unknown sorting type: {sorting_type}')
        return sorted_movies
    
    
    def main():
        '''
        为了把上面代码串起来,在main函数里实现了接收排序选项,解析电影数据,排序并打印电影列表功能。
        :return:
        '''
        all_sorting_type = ('name', 'rating', 'year', 'random')
        sorting_type = input('Please input sorting type:')
        if sorting_type not in all_sorting_type:
            print('Sorry,"{}" is not a valid sorting type,please choose from'
                  '"{}",exit now'.format(sorting_type, '/'.join(all_sorting_type))
                  )
            return
    
        # 初始化电影数据对象
        movies_items = []
        for movie_json in movies:
            movie = Movies(**movie_json)
            movies_items.append(movie)
    
        # 排序输出电影列表
        sorted_movies = get_scorted_movies(movies_items,sorting_type)
        for movie in sorted_movies:
            print(
                f'-[{movie.rank} {movie.name} ({movie.year}) | rating: {movie.rating}]'
            )
    
    
    if __name__ == '__main__':
        main()
    
    # 输出结果
    Please input sorting type:name
    -[S 侠客行 (2008) | rating: 9]
    -[C 厨神 (2010) | rating: 7]
    -[C 喜来乐 (2006) | rating: 6.9]
    -[B 康熙来了 (2021) | rating: 8]
    -[S 西游记 (1983) | rating: 9]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    上面的代码完成了一个小工具,虽然这个工具实现了功能,在他的代码里隐藏着两大段可以简化的条件分支代码,如果使用前档的方式可以使分支消失。

    2.使用bisect优化范围类分支判断

    第一个需要优化的分支判断是rank方法属性中的分支。

    @property
        def rank(self):
            '''
            根据评分对电影分级
            -S:8.5分以上
            -A: 8~8.5
            -B: 7~8
            -C: 6~7
            -D: 6分以下
            '''
            rating_num = float(self.rating)
            if rating_num >= 8.5:
                return 'S'
            elif rating_num > 8:
                return 'A'
            elif rating_num > 7:
                return 'B'
            elif rating_num > 6:
                return 'C'
            else:
                return 'D'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    仔细观察这段代码,你会发现它有一个明细的规律,每个if/elif 语句后,都跟着一个评分的分界点,这个分界点把评分分成不同的分段。要优化这段代码,先把所有分界点收集起来,放在一个元组里。

    breakpoints = [6, 7, 8, 8.5]
    
    • 1

    breakpoints已经是一个排好序的元组,所以我们可以直接使用bisect模块来实现查找功能,bisect是python内置的二分算法模块,他有一个同名函数bisect,可以用来在有序列表里做二分查找。

    import bisect
    # 用二分查找的容器必须是排好序的
    breakpoints = [6, 7, 8, 8.5]
    
    print('使用二分查找算法,根据值返回索引位置:', bisect.bisect(breakpoints, 7))
    
    # 将分界点定义成元组,并引入bisect,之前的分支代码可以简化成下面的样子。
    class Movies2:
        def __init__(self, name, year, rating):
            self.name = name
            self.year = year
            self.rating = rating
    
        @property
        def rank(self):
            breakpoints = (6, 7, 8, 8.5)
            grades = ('D', 'C', 'B', 'A', 'S')
            index = bisect.bisect(breakpoints,float(self.rating))
            return grades[index]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    3.使用字典优化k-v相等类型的分支

    在get_sorted_movies()函数里,同样有一段分支代码,这段代码有两个明显的特点。

    • 他用到的条件表达式都非常类似,都是对sorting_type做等值判断也就是key==value。
    • 每个分支内部逻辑也大同小异,都是调用sorted()函数,只是key和reverse略有不同。
      如果有一段条件分支代码同时满足这两个条件,我们就可以使用字典来简化它。
    def get_scorted_movies(movies, sorting_type):
        '''
        电影列表排序并返回结果
        :param movies: 对象列表
        :param sorting_type: 排序选项
        :return:
        '''
        if sorting_type == "name":
            sorted_movies = sorted(movies, key=lambda movie: movie.name.lower())
        elif sorting_type == "rating":
            sorted_movies = sorted(movies, key=lambda movie: float(movie.rating), reverse=True)
        elif sorting_type == "year":
            sorted_movies = sorted(movies, key=lambda movie: movie.year, reverse=True)
        elif sorting_type == "random":
            sorted_movies = sorted(movies, key=lambda movie: random.random())
        else:
            raise RuntimeError(f'Unknown sorting type: {sorting_type}')
        return sorted_movies
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    字典优化判断分支代码

        def get_scorted_movies(movies, sorting_type):
            '''
            电影列表排序并返回结果
            :param movies: 对象列表
            :param sorting_type: 排序选项
            :return:
            '''
            # 将判断的条件封装到字典中
            sorting_algos = {
                #  sorting_type: (key_func, reverse)
                'name': (lambda movie: movie.name.lower(), False),
                'rating': (lambda movie: float(movie.rating), True),
                'year': (lambda movie: movie.year, True)
            }
            try:
                # 通过key获取字典中value的值,值的类型是元组因此可以获取两个变量
                key_func, reverse = sorting_algos[sorting_type]
            except KeyError:
                raise RuntimeError(f'Unknown sorting type: {sorting_type}')
    
            sorted_movies = sorted(movies, key=key_func, reverse=reverse)
            return sorted_movies
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    4.重构代码

    在编写代码时,有事会下意识地编写一段大同小异的条件分支语句,多数情况下,他们只是对业务逻辑的一种直译,使我们对业务逻辑理解处在第一层的表现。
    如果进一步深入业务逻辑,从中总结规律,那么条件分支代码就可以另一种更精简,更易扩展的方式替代。

    class Movies2:
        def __init__(self, name, year, rating):
            self.name = name
            self.year = year
            self.rating = rating
    
        @property
        def rank(self):
            breakpoints = (6, 7, 8, 8.5)
            grades = ('D', 'C', 'B', 'A', 'S')
            index = bisect.bisect(breakpoints, float(self.rating))
            return grades[index]
    
        def get_scorted_movies(movies, sorting_type):
            '''
            电影列表排序并返回结果
            :param movies: 对象列表
            :param sorting_type: 排序选项
            :return:
            '''
            # 将判断的条件封装到字典中
            sorting_algos = {
                #  sorting_type: (key_func, reverse)
                'name': (lambda movie: movie.name.lower(), False),
                'rating': (lambda movie: float(movie.rating), True),
                'year': (lambda movie: movie.year, True)
            }
            try:
                # 通过key获取字典中value的值,值的类型是元组因此可以获取两个变量
                key_func, reverse = sorting_algos[sorting_type]
            except KeyError:
                raise RuntimeError(f'Unknown sorting type: {sorting_type}')
    
            sorted_movies = sorted(movies, key=key_func, reverse=reverse)
            return sorted_movies
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.条件分支编程建议

    3.1.尽量避免多层分支嵌套

    在使用分支语句时要竭尽所能避免分支嵌套。每当业务逻辑变得越来越复杂,条件分支就会越来越多,嵌套越来越深。当代码有了多层嵌套后,可读性和可维护性就会直线下降。这是因为读代码的人很难在深层嵌套里搞清楚,如果不满足某个条件会发生什么。

    下面来看一个卖水果的案例,在这个案例中就嵌套了三层分支判断语句,可读性就很差。

    def buy_fruit(nerd, store):
        '''
        去水果店买水果流程:
        - 先看看水果店是否在营业
        - 如果有苹果就买一个
        - 如果钱不够,就回家取钱再来
        :param nerd: 
        :param store: 
        :return: 
        '''
        # 水果店在营业状态
        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 MadAtNotFruit("no apple in store!")
        else:
            raise MadAtNotFruit("store is closed!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    我们可以使用提前返回技巧简化多层分支嵌套,提前返回指的是:当你在编写分支时,首先找到那些会中断执行的条件,把它们移动到函数的最前面,然后在分支里使用return或raise结束执行。

    通过提前返回,buy_fruit_v2函数变得扁平了,整个逻辑变得更直接,更容易理解了。

    def buy_fruit_v2(nerd, store):
        '''
            去水果店买水果流程:
            - 先看看水果店是否在营业
            - 如果有苹果就买一个
            - 如果钱不够,就回家取钱再来
            :param nerd:
            :param store:
            :return:
            '''
        # 水果店没有开门则结束流程
        if not store.is_open():
            raise MadAtNotFruit("store is closed!")
        
        # 水果店没有苹果则结束流程
        if not store.has_stocks("apple"):
            raise MadAtNotFruit("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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.2.别写太复杂的条件表达式

    假如某个分支的条件非常复杂,当我们把它翻译成代码时,一个包含大量not/and/or的复杂表达式就会横空出世了,看起来像是一个难懂的数学公式,代码可读性会随着表达式复杂度而下降。

    # 如果活动还在开放,并且活动名额大于10,为所有性别为女性或者级别大于3
    # 的用户发放1000个金币
    if(
        activity.is_active
        and activity.remaining > 10
        and user.is_active
        and (user.sex == 'female' or user.level > 3)
    ):
        user.add_coins(1000)
        return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    针对上面这个案例,需要对条件表达式简化,把它们封装成函数或者对应的类方法,这样才能提升分支代码的可读性。

    if activity.allow_new_user() and user.match_activity_condition():
    	user.add_coins(1000)
    	return
    
    • 1
    • 2
    • 3

    3.3.降低分支内代码的相似性

    在编写条件分支语句时,有些操作会因为业务逻辑相似性导致代码也很相似。有时这种相似的代码时完全重复的代码,有时则是调用函数时的重复参数。
    假如不同分支下的代码过于相似,读者就很难区分不同分支下行为有什么差异。如果在编写代码时降低这种相似性就能有效的提升可读性。

    1.分支内重复代码案例

    下面是一个分支内代码相似的案例

    # 仅当分组处于活跃时,允许用户加入分组
    if group.is_active:
        user = get_user_by_id(request.user_id)
        user.join(group)
        log_user_activiry(user, target=group, type=ActivityType.JOINED_GROUP)
    else:
        user = get_user_by_id(request.user_id)
        log_user_activiry(user, target=group, type=ActivityType.JOINED_GROUP_FAILED)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    把重复的代码移到分支外,降量降低分支内代码的相似性。

    user = get_user_by_id(request.user_id)
    if group.is_active:
        user.join(group)
        activity_type = ActivityType.JOINED_GROUP
    else:
        activity_type = ActivityType.JOINED_GROUP_FAILED
    log_user_activiry(user, target=group, type=ActivityType.JOINED_GROUP)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.分支内函数参数重复案例

    判断用户是否存在,如果用户存在则更新用户信息,不存在则创建用户,创建和更新函数的参数有部分是重复的。很难一下看出二者的核心不同点是什么。

    # 如果用户存在则更新用户信息,不存在则创建用户,创建和更新函数的参数有部分是重复的。很难分辨出他们的区别。
    user = True
    
    def create_user(id, name, sex, age):
        print(f'创建用户信息:id:{id}, name:{name}, sex:{sex}, age:{age}')
    
    
    def update_user(id, name, sex, address):
        print(f'更新用户信息:id:{id}, name:{name}, sex:{sex}, address:{address}')
    
    
    if user == False:
        create_user(1, 'jery', 'man', 13)
    else:
        update_user(1, 'jery', 'man', '中关村')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    为了降低函数参数的相似性,可以使用python函数的动态关键字参数(**kwargs),简化上面的代码。

    user = True
    
    def create_user(id, name, sex, age):
        print(f'创建用户信息:id:{id}, name:{name}, sex:{sex}, age:{age}')
    
    
    def update_user(id, name, sex, address):
        print(f'更新用户信息:id:{id}, name:{name}, sex:{sex}, address:{address}')
    
    if user == False:
        # 将函数赋值给一个变量,由该变量为函数传递参数
        _update_or_create = create_user
        extra_args = {'age': 13}
    else:
        _update_or_create = update_user
        extra_args = {'address': '中关村'}
    
    _update_or_create(
        id=1,
        name='jery',
        sex='man',
        **extra_args,
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.4.德摩根定律

    如果遇到下面这样的代码,同时用了2个not和1个or,是不是需要思考一会才能弄明白他想干什么?这是因为人类恰巧不擅长处理这样有过多否定的逻辑关系。
    根据德摩根定律,not A or not B 等价于 not (A and B)
    当你的代码出现太多的否定,请尝试使用德摩根定律来化繁为简吧。

    if not user.has_logged_in or not user.is_from_chrome:
    	return True
    
    # 使用德摩根定律来优化代码
    if not (user.has_logged_in and user.is_from_chrome):
    	return True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.5.使用all或any函数构建表达式

    all()函数和any()这两个函数接收一个可迭代对象作为参数,返回一个布尔值结果
    这两个函数在构建条件表达式时可以实现特殊作用,他们的功能如下:

    • all(iterable) 仅当iterable中所有成员的布尔值都为真时返回True
    • any(iterable) 只要iterable中任何一个成员布尔值结果为真就返回True
    1.all()函数构建条件表达式例子

    判断一个列表里所有的数字是不是都大于10 ,下面是普通的写法。

    def all_number_gt_10(number: list):
        if not number:
            return False
        for n in number:
            if n <= 10:
                return False
        return True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果使用all()内置函数,上面的代码可以简化为下面的样子

    def all_number_gt_10_v2(number: list):
        # boo():当number为空时直接返回False
        return bool(number) and all(n > 10 for n in number)
    
    b = all_number_gt_10_v2([])
    print(f'列表中的数值是否全部大于10:{b}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.6.and和or运算符优先级

    在使用and和or来构建逻辑表达式,要主要他们的优先级,先看下面的例子。
    他们运算结果一样吗,答案是不一样的。他们的值分别是False和True

    出现这个结果的原因是:and运算符优先级高于or运算符。

    (True or False) and False
    True or False and False
    
    • 1
    • 2

    3.7.or运算符陷阱

    or运算符有一个有趣的特性就是”短路求值“特性,比如下面的例子里 1/0永远也不会执行。

    True or (1 / 0)
    
    • 1
    1.or简化代码例子

    因为这个特性在很多场景下可以简化代码,比如下面的例子。

    context = {}
    # 仅当extra_context不为None时,将其追加进contex字典中。
    if extra_context:
        context.update(extra_context)
    
    # 使用or可以简化为一行代码
    context.update(extra_context or {})
    在对象不为空时就是extra_context自身,如果为None时就变成{}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2.or陷阱例子

    因为or计算的是变量的布尔值真假,所以不光是None,0、[]、{}、以及其他布尔值为假的东西,都会在or运算中忽略。
    下面来看一个or陷阱的例子

    它的目的是判断timeout为None时,使用60作为默认值,但假如 config.timeout 的值被置为0秒,timeout也会被赋值60,正确的配置反而被忽略了。

    timeout = config.timeout or 60
    
    • 1
  • 相关阅读:
    【VTK】关于VTK图像的系列功能
    从性能选择⭐《Java并发队列》⭐
    机器学习算法——K近邻算法详解
    Nginx 禁止国外 IP 访问网站
    win10安装配置ssh服务
    计算机毕业设计springboot基于大数据的疫情追踪系统的设计和实现rva1s源码+系统+程序+lw文档+部署
    OS2.3.9:读者-写者问题
    Go Web——Gin简介
    【C++】类和对象(下)
    GPT研究
  • 原文地址:https://blog.csdn.net/m0_38039437/article/details/126570606