基础知识
分支惯用写法
没必要显式和布尔值比较,直接:
if user.is_active:
pass
省略零值判断
if containers_count == 0:
-->
if not containers_count:
# 因为bool(0): False
但是两者仍有不同
前者只有为0的时候才满足条件
后者则扩大到0, None, 空字符串等
所以不能因为过度追求简写而引出其他逻辑问题
内置类型布尔值规则:
假: None, 0, False, [], (), {}, set(), frozenset() 等
真: 非0的数值, True, 非空的序列、元组、字典,用户定义的类和实例等
把否定逻辑移入表达式内
if not number > 10:
-->
if number <= 10:
尽可能让三元表达式变得简单
# eg
target=it if it > 10 else None
修改对象的布尔值
>>> class UserCollection:
... def __init__(self, users):
... self.items = users
... def __len__(self):
... return len(self.items)
...
>>> Users = UserCollection(['a', 'b'])
>>> if Users:
... print("have users")
...
have users
>>> Users2 = UserCollection([])
>>> if Users2:
... print("have users")
此外,__bool__
也可以达到同样的效果,且解释器会优先使用__bool__
的执行结果
reference
与None比较时使用is运算符
>>> class EqualWithAnything:
... def __eq__(self, other):
... return True
...
>>> foo = EqualWithAnything()
>>> foo == 1
True
>>> foo == None
True
可以看到 ==
的行为是可以被__eq__
重写的
但是使用is运算符可以严格判断
因为x is y是就是比较id(x) 和 id(y)的结果是否相等
但是仅限于用is比较None,
因为python中除了None, True, False之外, 其他类型的对象即使值一致,在内存中仍是不同对象
>>> x = 257
>>> y = 257
>>> x is y
False
>>> x == y
True
但是上例中如果x y的数值在-5到256之间, x is y就会返回True, 因为在python中-5到256之间的常用整数,Python会把他们缓存在内存的数组里。
案例故事
编程建议
尽量避免多层分支嵌套
提前返回 raise/return
别写太复杂的条件表达式
可以把条件判断封装成函数或者类方法
尽量降低分支内代码的相似性
比如可以利用关键字参数(**kwargs)
使用德摩根定律
not A or not B ⇒ not (A and B)
使用all()/any()函数构造条件表达式
all(interable): 当iterable中所有成员布尔值都为真时返回True, 否则返回False
all(interable): 当iterable中所有成员布尔值一个为真时返回True, 否则返回False
留意and和or的运算优先级
>>> (True or False) and False
False
>>> True or False and False
True
因为and优先级高于or
避开or运算符陷阱
>>> True or (1 / 0)
True
“短路求值”
a or b --> a为False时用b代替
但是a为False的场景很多
eg:
timeout = config.timeout or 60
本来目的是config.timeout为None时,使用60作为默认值
但是config.timeout为0时, timeout便会被赋值成60