循环复杂度是衡量代码复杂性和混乱程度的指标。
高圈复杂度并不是一件好事,恰恰相反。
简单地说,圈复杂度与程序中可能的执行路径的数量成正比。换句话说,圈复杂度和条件语句的总数(尤其是它们的嵌套)密切相关。
今天我们来谈谈条件语句。
反如果
2007 年,Francesco Cirillo发起了一场名为 Anti-if 的运动。
Francesco Cirillo 是发明番茄工作法的人。我现在正在“番茄钟下”写这篇博文。
我想我们都很快从这个活动的名字就明白了它的含义。有趣的是,该运动的追随者中有不少计算机科学家。
他们的论点坚如磐石——如果语句是邪恶的,会导致程序执行路径呈指数级增长。
简而言之,这就是圈复杂度。它越高,不仅阅读和理解代码就越困难,而且用测试来覆盖它也就越困难。
当然,我们有一种“相反”的指标——代码覆盖率,它显示了测试覆盖了多少代码。但是,这个指标以及我们编程语言中用于检查覆盖率的丰富工具是否证明忽略圈复杂度并仅基于“本能”散布 if 语句是合理的?
我想不会。
几乎每次我发现自己要将一个 if 嵌套在另一个 if 中时,我都会意识到我正在做一些非常愚蠢的事情,可以用不同的方式重写 - 要么没有嵌套的 if ,要么根本没有 if 。
你确实注意到了“几乎”这个词,对吧?
我并没有立即开始注意到这一点。如果您查看我的 GitHub,您会发现不止一个旧代码示例,它们不仅具有高圈复杂度,而且具有直接的圈复杂度。
是什么让我更加意识到这个问题?可能是我一年前学到和接受的经验和一些聪明的事情。这就是我今天想跟大家分享的内容。
破坏 if 语句的两种神圣技术
- Padawan,将未知值的每个条件检查移至该值已知的位置。
- 学徒,改变你的编码逻辑思维模型,让它不再需要条件检查。
1. 让未知为人所知
当我们还不“知道”某件事时检查它可能是使用基于“本能”的条件语句的最常见来源。
例如,假设我们需要根据用户的年龄做一些事情,并且我们必须确保年龄有效(在合理范围内)。我们最终可能会得到这样的代码:
from typing import Optional def process_age(age: Optional[int]) -> None: if age is None: raise ValueError("Age cannot be null") if age 150: raise ValueError("Age must be between 0 and 150")
我们都见过并且可能编写过数百次类似的代码。
我们如何通过遵循所讨论的元原则来消除这些条件检查?
在我们特定的年龄情况下,我们可以应用我最喜欢的方法——摆脱原始的痴迷,转向使用自定义数据类型。
class Age: def __init__(self, value: int) -> None: if value 150: raise ValueError("Age must be between 0 and 150") self.value = value def get_value(self) -> int: return self.value def process_age(age: Age) -> None: # Age is guaranteed to be valid, process it directly
万岁,少一个如果!年龄的验证和验证现在始终在“已知年龄的地方”——在单独类的职责和范围内。
如果我们想删除 Age 类中的 if ,我们可以走得更远/不同,也许可以使用带有验证器的 Pydantic 模型,甚至用断言替换 if — 现在已经不重要了。
其他有助于摆脱同一元思想中的条件检查的技术或机制包括用多态性(或匿名 lambda 函数)替换条件以及分解具有偷偷摸摸的布尔标志的函数等方法。
例如,这段代码(可怕的拳击,对吧?):
class PaymentProcessor: def process_payment(self, payment_type: str, amount: float) -> str: if payment_type == "credit_card": return self.process_credit_card_payment(amount) elif payment_type == "paypal": return self.process_paypal_payment(amount) elif payment_type == "bank_transfer": return self.process_bank_transfer_payment(amount) else: raise ValueError("Unknown payment type") def process_credit_card_payment(self, amount: float) -> str: return f"Processed credit card payment of {amount}." def process_paypal_payment(self, amount: float) -> str: return f"Processed PayPal payment of {amount}." def process_bank_transfer_payment(self, amount: float) -> str: return f"Processed bank transfer payment of {amount}."
如果你用 match/case 替换 if/elif 也没关系——都是同样的垃圾!
很容易将其重写为:
from abc import ABC, abstractmethod class PaymentProcessor(ABC): @abstractmethod def process_payment(self, amount: float) -> str: pass class CreditCardPaymentProcessor(PaymentProcessor): def process_payment(self, amount: float) -> str: return f"Processed credit card payment of {amount}." class PayPalPaymentProcessor(PaymentProcessor): def process_payment(self, amount: float) -> str: return f"Processed PayPal payment of {amount}." class BankTransferPaymentProcessor(PaymentProcessor): def process_payment(self, amount: float) -> str: return f"Processed bank transfer payment of {amount}."
对吗?
将带有布尔标志的函数分解为两个独立函数的示例与时间一样古老,令人痛苦地熟悉,并且令人难以置信地烦人(在我看来)。
def process_transaction(transaction_id: int, amount: float, is_internal: bool) -> None: if is_internal: # Process internal transaction pass else: # Process external transaction pass
无论如何,两个函数都会好得多,即使其中 2/3 的代码是相同的!这是其中一种场景,其中与 DRY 的权衡是常识的结果,使代码变得更好。
The big difference here is that mechanically, on autopilot, we are unlikely to use these approaches unless we've internalized and developed the habit of thinking through the lens of this principle.
Otherwise, we'll automatically fall into if: if: elif: if...
2. Free Your Mind, Neo
In fact, the second technique is the only real one, and the earlier "first" technique is just preparatory practices, a shortcut for getting in place :)
Indeed, the only ultimate way, method — call it what you will — to achieve simpler code, reduce cyclomatic complexity, and cut down on conditional checks is making a shift in the mental models we build in our minds to solve specific problems.
I promise, one last silly example for today.
Consider that we're urgently writing a backend for some online store where user can make purchases without registration, or with it.
Of course, the system has a User class/entity, and finishing with something like this is easy:
def process_order(order_id: int, user: Optional[User]) -> None: if user is not None: # Process order for a registered user pass else: # Process order for a guest user pass
But noticing this nonsense, thanks to the fact that our thinking has already shifted in the right direction (I believe), we'll go back to where the User class is defined and rewrite part of the code in something like this:
class User: def __init__(self, name: str) -> None: self.name = name def process_order(self, order_id: int) -> None: pass class GuestUser(User): def __init__(self) -> None: super().__init__(name="Guest") def process_order(self, order_id: int) -> None: pass
So, the essence and beauty of it all is that we don't clutter our minds with various patterns and coding techniques to eliminate conditional statements and so on.
By shifting our focus to the meta-level, to a higher level of abstraction than just the level of reasoning about lines of code, and following the idea we've discussed today, the right way to eliminate conditional checks and, in general, more correct code will naturally emerge.
A lot of conditional checks in our code arise from the cursed None/Null leaking into our code, so it's worth mentioning the quite popular Null Object pattern.
Clinging to Words, Not Meaning
When following Anti-if, you can go down the wrong path by clinging to words rather than meaning and blindly following the idea that "if is bad, if must be removed.”
Since conditional statements are semantic rather than syntactic elements, there are countless ways to remove the if token from your code without changing the underlying logic in our beloved programming languages.
Replacing an elif chain in Python with a match/case isn’t what I’m talking about here.
Logical conditions stem from the mental “model” of the system, and there’s no universal way to "just remove" conditionals entirely.
In other words, cyclomatic complexity and overall code complexity aren’t tied to the physical representation of the code — the letters and symbols written in a file.
The complexity comes from the formal expression, the verbal or textual explanation of why and how specific code works.
So if we change something in the code, and there are fewer if statements or none at all, but the verbal explanation of same code remains the same, all we’ve done is change the representation of the code, and the change itself doesn’t really mean anything or make any improvement.
以上是避免条件语句的智慧的详细内容。更多信息请关注PHP中文网其他相关文章!

Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

本文解释了如何使用美丽的汤库来解析html。 它详细介绍了常见方法,例如find(),find_all(),select()和get_text(),以用于数据提取,处理不同的HTML结构和错误以及替代方案(SEL)

本文比较了Tensorflow和Pytorch的深度学习。 它详细介绍了所涉及的步骤:数据准备,模型构建,培训,评估和部署。 框架之间的关键差异,特别是关于计算刻度的

在使用Python的pandas库时,如何在两个结构不同的DataFrame之间进行整列复制是一个常见的问题。假设我们有两个Dat...

本文指导Python开发人员构建命令行界面(CLIS)。 它使用Typer,Click和ArgParse等库详细介绍,强调输入/输出处理,并促进用户友好的设计模式,以提高CLI可用性。

本文讨论了诸如Numpy,Pandas,Matplotlib,Scikit-Learn,Tensorflow,Tensorflow,Django,Blask和请求等流行的Python库,并详细介绍了它们在科学计算,数据分析,可视化,机器学习,网络开发和H中的用途

文章讨论了虚拟环境在Python中的作用,重点是管理项目依赖性并避免冲突。它详细介绍了他们在改善项目管理和减少依赖问题方面的创建,激活和利益。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器