乐趣区

关于python:Python代码工程实践-条件和循环

三元表达式

在很多状况下,应用一般的 if/else 语句的代码可读性的确更好。自觉谋求三元表达式很容易引诱你写出简单、可读性差的代码。

所以,请记得只用三元表达式解决简略的逻辑分支。比方如下代码是适宜应用三元表达式的:

language = "python" if you.favor("dynamic") else "golang"

对于绝大多数状况,还是应用一般的 if/else 语句吧。比方上面代码

self.enabled = True if kwargs['enable'] and kwargs['already_started'] == 'Yes' and self.checked == 1 else False
self.need_use_ssl = True if kwargs['use_ssl'] is True else False if kwargs['allow_insecure'] is False else True

下面两种状况应用三元表达式反而将代码写的很长,第二行还有条件嵌套,使代码更加不容易了解

上面章节会介绍简化 if-else statement 的具体技巧,这里咱们记住 三元表达式须要慎用

重构 if…else 语句

Nested if-else hell

如果你对这种代码十分观赏,并且心田有一种想要搞清楚它在干什么的激动,请略过这章的内容。

应用卫语语句简化函数

def get_payment_amount(account: Account) -> float:
    result = 0.0
    if account.is_deactivated:
        result = get_deacticated_amount(account)
    else:
        if account.is_separated:
            result = get_separated_amount(account)
        else:
            if account.is_retired:
                result = get_retired_amount(account)
            else:
                result = get_normal_amount(account)
    return result

该代码段存在大量的条件嵌套,应用卫语简化这个代码段,也叫提前结束(early ending)

def get_payment_amount(account: Account) -> float:
    if account.is_deactivated:
        return get_deacticated_amount(account)
    if account.is_separated:
        return get_separated_amount(account)
    if account.is_retired:
        return get_retired_amount(account)
    return get_normal_amount(account)

重构后,根本移除了所有的 else 语句,使整个函数变得更加清晰,容易了解。

应用多态代替条件表达式

以下代码段是判断一个员工是否可能休假的代码

def is_eligible_for_pto(employee: Employee) -> bool:
    if employee.type == "Manager":
        return employee.hired_days > 100 and employee.performance >= 0.8
    elif employee.type == "Developer":
        return employee.hired_days > 30 and employee.performance >= 0.6 and employee.is_on_duty is False
    elif employee.type == "Intern":
        return employee.hired_days > 7 and employee.performance >= 0.4 and employee.is_on_duty is False
    elif employee.type == "Director":
        return employee.is_on_duty is False
    return False

咱们曾经用卫语代替条件分支的办法重构过了,然而这个代码仍然看起来很繁琐,因为每个条件分支都有很长很简单的判断逻辑,而对于这个函数来说,它须要的常识太多了,必须晓得 employee 这个对象的属性,以及影响 PTO 的相干条件能力判断进去。

咱们如果应用多态的形式来重构这段代码,可能将判断逻辑封装在具体的子类中,并且只须要在函数中调用相应接口即可,并不需要晓得对于 Employee 这个对象更多的信息即可实现工作。

class Employee:
    type: str
    hired_days: int
    performance: float

    @property
    def pto_condition(self) -> bool:
        return False

class Manager(Employee):
    @property
    def pto_condition(self) -> bool:
        return self.hired_days > 100 and \
            self.performance >= 0.8

class Developer(Employee):
    @property
    def pto_condition(self) -> bool:
        return self.hired_days > 30 and \
            self.performance >= 0.6 and \
                self.is_on_duty is False

class Intern(Employee):
    @property
    def pto_condition(self) -> bool:
        return self.hired_days > 7 and \
            self.performance >= 0.4 and \
                self.is_on_duty is False

class Director(Employee):
    @property
    def pto_condition(self) -> bool:
        return self.is_on_duty is False

def is_eligible_for_pto(employee: Employee) -> bool:
    return employee.pto_condition is True

用否定条件判断代替 else 分支

bad:

def _to_list(src):
    if src:
        return src if isinstance(src, list) else [src]
    else:
        return []

good:

def _to_list(src):
    if not src:
        return []
    return src if isinstance(src, list) else [src]

逻辑重构

应用 for...else 代替 flag 以简化代码

bad:

flag = False
for index in range(10):
    if index == 20:
        flag = True
        break
if not flag:
    print("not found it")

good:

for index in range(10):
    if index = 20:
        break
else:
    print("not found it")

应用字典代替条件判断

Python 中是不存在 switch 语句的,(新版本才反对),所以,当存在较多条件分支时,会写十分长的 if 判断语句,比方像上面这种:

def global_events_dispatcher(event):
    if event == 'event_1':
        return call_event_handler_1()
    elif event == 'event_2':
        return call_event_handler_2()
    elif event == 'event_3':
        return call_event_handler_3()
    else:
        raise UnknownEventError

这种代码岂但有多个条件分支,看起来比较复杂,同时也是反复代码的一种体现。

咱们能够利用 Python 的dict 对这段条件分支代码进行重构,缩小条件分支,去除反复代码。

def global_events_dispatcher(event):
    event_handlers = {
        'event_1': call_event_handler_1,
        'event_2': call_event_handler_2,
        'event_3': call_event_handler_3,
    }
    if event_handlers.get(event, None):
        func = event_handlers(event)
        return func()
    raise UnknownEventError

重构后代码只有一个条件判断语句,函数的行为没有产生任何变动,让整个函数的逻辑变得更加容易了解。

补充

对于如何重构条件分支语句,能够延长浏览《重构:改善既有代码的设计(第 2 版)》第 10 章:简化条件逻辑,外面列举了多种常见的简化条件逻辑的重构手法,并配有大量的例子,举荐浏览。

退出移动版