Python笔记:控制流优化

发布时间 2023-10-01 20:05:11作者: xzqbear

零值判断

Python当中有个语法糖是可以直接对某个对象做空值判断:

if nums_arr:
	pass

不同类型的数据对应什么样的bool值呢?我们可以有如下的判断:

  • None 、0、False 、空列表、空元组、空字典、空集合等等都对应布尔值为假。
  • 其余的对应布尔值为真。

但是现在问题来了,对于开发者自己写的对象,布尔值应该返回什么?默认情况下返回的一定是True,但是我们可以写 __bool__ 方法来自定义:

class ScoreJudger:
	def __init__(self,score):
		self.score = score
	def __bool__(self):
		return self.score >= 60

None值比较

我们可以利用 == 运算符来判断是否等于 None

if m == None:
	pass

对于自定义的对象,有一个内置的方法叫做 __eq__ ,这个方法的作用是重载 == 运算符的作用:

def __eq__(self,other):
	# other 表示作比较的另一个对象
	return True

这样就会出现一个问题,如何严格判断是否为None?当我写出上面的函数时,我有可能在与None比较的时候无论怎样都返回True,这是不行的。解决方案就是使用 is 方法:

if l is None:
	pass

is 的特点就是不能被重载,并且在比对的时候比对的是内存地址而非值,这就使得在与None比较的时候,不是None的都不会通过 is 的检验。

分支判断优化

在使用边界条件判断等级的时候,我们往往碰到这样的情况:

if score >= 90:
	return 'S'
elif score >= 80:
	return 'A'
elif score >=70:
	return 'B'
else:
	return 'C'

这段代码不能说不好,但是在编写的时候比较繁琐,不够Pythonic,一个相对比较好的替代方案就是利用官方库 bisect 来进行查找:

from bisect import bisect
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
    i = bisect(breakpoints, score)
    return grades[i]

print([grade(score) for score in [33, 99, 77, 70, 89, 90, 100]])

上面的代码写出了替代方案,bisect 函数的作用是利用二分查找,并且返回所处的数值段,就上面的代码来说可以依据下图理解:
![[bisect分段.png]]
\(i\leq60\) ,那么就返回 \(0\) ,若 \(60<i\leq70\) ,那么返回 \(0\) ,以此类推,有了这个代码,我们可以更快速地返回我们想要的分数段对应结果。

条件封装

在使用分支语句判断时,我们常常会遇到复杂的条件判断式:

class Student:
	def __init__(self,score,sex):
		self.score = score
		self.sex = sex

s1 = Student(100,'female')
s2 = Student(99,'male')
if(
   s1.sex == 'female'
   and s1.score > 60
):
	print('合格')

上面的条件表达式实际上可以封装成一个类方法来简化条件表达式。

def is_female_and_passed():
	return s1.sex == 'female' and s1.score > 60

这样在后面调用的时候就能更好地提升代码的可读性。

条件表达式的逻辑构建

德摩根定律

我们知道德摩根定律如下:

\[\neg\bigwedge_{i=1}^n p_i=\bigvee_{i=1}^{n}\neg{}p_i \]

我们在写程序的时候,左边的形式要更加容易理解一些,因此建议使用左边形式。例如 not (A and B)(not A) or (not B) 当中,前者要更易于理解。

all()和any()

实际上上图的并与且在Python当中已经有了一个语法糖就是 all()any() 的方法。他们分别表示完全的且和完全的或。使用方法就是将条件判断式放在这两个函数当中(以列表的形式):

all([True,False,True])
any([True,False,True])