Python编程中的反模式(2)

为什么要这么做?一方面你避免了正确初始化列表可能带来的错误,另一方面,这样写代码让看起来很干净,整洁。对于那些有函数式编程背景的人来说,使用可能感觉更熟悉,但是在我看来这种做法不太Python化。

其他的一些不使用列表解析的常见理由:

1. 需要循环嵌套。这个时候你可以嵌套整个列表解析,或者在列表解析中多行使用循环:

words = ['her', 'name', 'is', 'rio'] letters = [] for word in words: for letter in word: letters.append(letter)

使用列表解析:

words = ['her', 'name', 'is', 'rio'] letters = [letter for word in words for letter in word]

注意:在有多个循环的列表解析中,循环有同样的顺序就像你并没有使用列表解析一样。

2. 你在循环内部需要一个条件判断。你只需要把这个条件判断添加到列表解析中去:

words = ['her', 'name', 'is', 'rio', '1', '2', '3'] alpha_words = [word for word in words if isalpha(word)]

一个不使用列表解析的合理的理由是你在列表解析里不能使用异常处理。如果迭代中一些元素可能引起异常,你需要在列表解析中通过函数调用转移可能的异常处理,或者干脆不使用列表解析。

性能缺陷

在线性时间内检查内容

在语法上,检查list或者set/dict中是否包含某个元素表面上看起来没什么区别,但是表面之下却是截然不同的。如果你需要重复检查某个数据结构里是否包含某个元素,最好使用set来代替list。(如果你想把一个值和要检查的元素联系起来,可以使用dict;这样同样可以实现常数检查时间。)

# 假设以list开始 lyrics_list = ['her', 'name', 'is', 'rio'] # 避免下面的写法 words = make_wordlist() # 假设返回许多要测试的单词 for word in words: if word in lyrics_list: # 线性检查时间 print word, "is in the lyrics" # 最好这么写 lyrics_set = set(lyrics_list) # 线性时间创建set words = make_wordlist() # 假设返回许多要测试的单词 for word in words: if word in lyrics_set: # 常数检查时间 print word, "is in the lyrics"

[译者注:Python中set的元素和dict的键值是可哈希的,因此查找起来时间复杂度为O(1)。]

应该记住:创建set引入的是一次性开销,创建过程将花费线性时间即使成员检查花费常数时间。因此如果你需要在循环里检查成员,最好先花时间创建set,因为你只需要创建一次。

变量泄露

循环 

通常说来,在Python中,一个变量的作用域比你在其他语言里期望的要宽。例如:在Java中下面的代码将不能通过编译:

// Get the index of the lowest-indexed item in the array // that is > maxValue for(int i = 0; i < y.length; i++) { if (y[i] > maxValue) { break; } } // i在这里出现不合法:不存在i processArray(y, i);

然而在Python中,同样的代码总会顺利执行且得到意料中的结果:

for idx, value in enumerate(y): if value > max_value: break processList(y, idx)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6cf98f833d23e9cd8ab458345986043f.html