Python 高手编程系列二千九百三十九 :避免现有名称

使用上下文中已经存在的名称是不好的做法,因为它会导致阅读代码时 — 特别是调
试时 — 非常混乱,例如以下代码:

def bad_ citizen():
… os = 1
… import pdb; pdb.set
trace()
… return os

bad
citizen()
(4)bad
citizen()
(Pdb) os
1
(Pdb) import os
(Pdb) c
<module ‘os’ from ‘/Library/Frameworks/Python.framework/Versions/2.5/lib/
python2.5/os.pyc’>
在这个例子中,os 名称被代码屏蔽。内置函数名称和来自标准库的模块名称都应该避免。
尽量使用原创的名称,即使是上下文的局部名称。对于关键字而言,后缀下划线是一
种避免冲突的方法:
def xapian_query(terms, or
=True):
“”“if or_ is true, terms are combined with the OR clause”“”

注意,class 通常被替换为 klass 或 cls:
def factory(klass, *args, kwargs):
return klass(args, **kwargs)
参数的最佳实践
函数和方法的签名是代码完整性的保证,它们驱动函数和方法的使用并构建其 API。除
了我们之前看到的命名规则之外,对参数也要特别小心。这可以通过 3 个简单的规则来实现。
• 通过迭代设计构建参数。
• 信任参数和测试。
• 小心使用魔法参数
args 和
kwargs。
通过迭代设计构建参数
如果每个函数都有一个固定的、定义明确的参数列表,那么代码的鲁棒性会更好。但
这在第一个版本中无法完成,所以参数必须通过迭代设计来构建。它们应该反映创建该元
素所针对的使用场景,并相应地逐渐发展。
例如,如果添加了一些参数,它们应该尽可能有默认值,以避免任何退化:
class Service: # 版本 1
def _query(self, query, type):
print(‘done’)
def execute(self, query):
self._query(query, ‘EXECUTE’)
Service().execute(‘my query’)
done
import logging
class Service(object): # 版本 2
def _query(self, query, type, logger):
logger(‘done’)
def execute(self, query, logger=logging.info):
self._query(query, ‘EXECUTE’, logger)
Service().execute(‘my query’) # 旧式调用
Service().execute(‘my query’, logging.warning)
WARNING:root:done
如果一个公共元素的参数必须被修改,那么将使用一个 deprecation 进程,本节稍后将
对此进行说明。
信任参数和测试
考虑到 Python 的动态类型特性,有些开发人员在函数和方法的顶部使用断言(assertion)
来确保参数具有正确的内容,代码如下:
def division(dividend, divisor):
assert isinstance(dividend, (int, float))
assert isinstance(divisor, (int, float))
return dividend / divisor
division(2, 4)
0.5
division(2, None)
Traceback (most recent call last):
File “”, line 1, in
File “”, line 3, in division
AssertionError
这通常是那些习惯于静态类型、并且感觉 Python 中缺少点什么的开发者的做法。
这种检查参数的方法是契约式设计(Design by Contract ,DbC,参见http://en.wikipedia.org/
wiki/Design_By_Contract)编程风格的一部分。在这种设计中,在代码实际运行之间会检查
先决条件。
这种方法有两个主要问题。
• DbC 的代码对应该如何使用它进行解释,导致其可读性降低。
• 这可能使代码速度变慢,因为每次调用都要进行断言。
后者可以通过解释器的"-O"选项来避免。在这种情况下,在创建字节码之前,所有断
言都将从代码中删除,这样检查也就会丢失。
在任何情况下,断言都必须小心进行,并且不应该用于使 Python 变成一种静态类型语
言。唯一的使用场景就是保护代码不被无意义地调用。
在大多数情况下,健康的测试驱动开发(TDD)风格可以提供鲁棒性很好的基础代码。
在这里,功能测试和单元测试验证了创建代码所针对的所有使用场景。
如果库中的代码被外部元素使用,那么进行断言可能是有用的,因为传入的数据可能
会导致程序结束甚至造成破坏。这在处理数据库或文件系统的代码中可能发生。
另一种方法是模糊测试(fuzz testing,参见 https://en.wikipedia.org/wiki/Fuzzing),它通
过向程序发送随机的数据块来检测其弱点。如果发现了新的缺陷,代码会被修复以解决这
一缺陷,并添加一次新的测试。
让我们来关注一个遵循 TDD 方法的代码库,它向正确的方向发展,每当出现新的缺陷
时都会对其进行调整,从而鲁棒性越来越好。当它以正确的方式完成时,测试中的断言列
表在某种程度上变得类似于先决条件列表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值