1.尽量用异常来表示特殊情况,而不要返回 None
用 None 这个返回值来表示特殊意义的函数,很容易使调用者犯错,因为 None 和 0 以及空字符串之类的值,在表达式里都会评估为 False。
函数在遇到特殊情况时,应该抛出异常,而不要返回 None 。调用者在看到该函数的文档中所描述的异常之后,应该就会编写相应的代码来处理它们了。
def divide(a, b):
try:
return a / b
except ZeroDivisionError as e:
raise ValueError('Invalid inputs') from e # 抛出异常
x, y = 5, 2
try:
result = divide(x, y)
except ValueError:
print('Invalid inputs')
else:
print('Result is %.lf' % result)
2.了解如何在闭包里使用外围作用域中的变量
我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。
def 外层函数(参数):
def 内层函数():
print("内层函数执行", 参数)
return 内层函数
内层函数的引用 = 外层函数("传入参数")
内层函数的引用()
参考:https://blog.csdn.net/weixin_44141532/article/details/87116038
1)python比较两个元组:首先比较各元组中下标为0(第一个)的对应元素,如果相等,再比较下标为1的对应元素...列表比较也类似。
2)在表达式中引用变量时,Python解释器将按如下顺序遍历各作用域,以解析该引用:
如果上面这些地方都没有定义过与名称相符的变量,就抛出 NameError 异常。
变量名
nonlocal:在闭包内给变量赋值,会在上层作用域中查找该变量,在闭包内修改的其实是闭包外那个作用域的变量。nonlocal的唯一限制在于,它不能延申到模块级别。除了那种简单的函数,尽量不要用 nonlocal 语句,应该将相关状态封装成辅助类,也可以利用上面的变量搜寻规则,将变量改为列表类型: 变量名[0] = ?(字典,集合,某个类的实例也类似)。
global:用来表示对该变量的赋值操作,将会直接修改模块作用域里那个变量。
3. 考虑用生成器来改写直接返回列表的函数
生成器(generator)是使用 yield 表达式的函数,调用生成器函数时,它并不会真正的运行,而是会返回迭代器。每次在这个迭代器上面调用内置的 next 函数时,迭代器会把生成器推进到下一个 yield 表达式那里。生成器传给yield的每一个值,都会由迭代器返回给调用者。
例,查出字符串中每个词的首字母在整个字符串里的位置。
def index_file(handle):
offset = 0
# 从文件里依次读入各行内容
for line in handle:
if line:
yield offset
# 逐行处理每个单词
for letter in line:
offset += 1 # 指向letter后一个地址
if letter == ' ':
yield offest
with open('filepath', 'r') as f:
it = index_file(f)
results = islice(it, 0 , 3) # 迭代前三个
print(list(result))
islice(iterable, [start, ] stop [, step]):
创建一个迭代器: iterable[start : stop : step],跳过前start个项,迭代在stop所指定的位置停止,step指定用于跳过项的步幅。迭代默认将从0开始,步幅默认1。
注意:迭代器只能使用一轮次。
办法:1)将迭代器复制一份列表;2)通过参数来接受另外一个函数;3)新编一种实现迭代器协议的容器类(python容器)
4.用数量可变的位置参数减少视觉杂讯
*arg: 适用于能够确定输入的参数个数比较少时,需要把很多变量或变量名一起传给某个函数的场合。
5.用关键字参数来表达可选的行为
关键字参数:1)明确参数的含义; 2)在函数定义时提供默认值; 3)提供一种扩充函数参数的有效方式,使得扩充之后的函数依然能够与原有的那些调用的代码相兼容。
注意:可选的关键字参数,总是应该以关键字形式来指定,而不是以位置参数的形式来指定。
6.用 None 和文档字符串来描述具有动态默认值的参数
例子:
def log(message, when=datetime.now()):
print('%s: %s' % (when, message))
log('Hi there!')
sleep(0.1)
log('Hi again!')
两条消息的时间戳是一样的,这是因为 datetime.now() 只执行了一次,也就是它只在函数定义的时候执行了一次。参数的默认值,会在每个模块加载进来的时候求出,而很多模块都是在程序启动时加载的。包括这段代码的模块一旦加载进来,参数的默认值就固定不变了,程序不会再次执行 datetime.now()。
应该把默认值设为 None,并在文档字符串里面把 None 所对应的实际行为描述出来。
def log(message, when=None):
"""记录时间。
Args:
message:打印的消息。
when:时间为 when 打印消息message,默认为 present time。
"""
when = datetime.now() if when is None else when
print('%s: %s' % (when, message))
7.用只能以关键字形式指定的参数来确保代码清晰
以下函数参数列表里的 * 号,标志着位置参数就此终结,之后的那些参数,都只能以关键字形式来指定。
def safe_division_c(number, divisor, *, ignore_overflow=False, ignore_zero_division=False):
# ...
这样就不能用位置参数的形式来指定关键字参数了,关键字参数不指定会采取默认值。对于接受多个布尔标志的函数,更应该这样做。