主要是笔者在实际开发中遇到的python函数相关的问题,关系到对python一些概念的深入理解,记下供参考。
1.局部变量作用域问题
python支持闭包,默认闭包中引用的变量读时按照由内而外的顺序(局部->外部->全局->内建)来搜索,但是在写时默认只找当前最近作用域,如果当前作用域没有则默认赋值时新建一个局部变量,如下代码:
def test_local_var():
var1 = 10
var2 = 20
def inner_func():
print 'inner var1:%s id:%s' % (var1, id(var1))
var2 = 200
print 'inner var2:%s id:%s' % (var2, id(var2))
inner_func()
print 'outter var1:%s id:%s' % (var1, id(var1))
print 'outter var2:%s id:%s' % (var2, id(var2))
输出结果如下,这里var1为只读,var2为写,因此内部和外部的var1是同一个变量,内部和外部var2并非同一个变量,在闭包中改变var2的值也就是改变inner_func作用域下的var2的值,对外部var2没有影响。
inner var1:10 id:41183120
inner var2:200 id:41188520
outter var1:10 id:41183120
outter var2:20 id:41182880
那么怎么才能解决这个问题呢,在python3中只需要对内部的var2指明nonlocal参数即可,但是在python2中没有这个关键字,我们常用技巧是先让python去读然后写,其实就是将值存在mutable类型容器中,如下:
def test_local_var2():
var1 = [10]
var2 = [20]
def inner_func():
print 'inner var1:%s id:%s' % (var1, id(var1))
var2[0] = 200
print 'inner var2:%s id:%s' % (var2, id(var2))
inner_func()
print 'outter var1:%s id:%s' % (var1, id(var1))
print 'outter var2:%s id:%s' % (var2, id(var2))
输出结果如下,这里内外层变量取值一致,这里要对var2[0]赋值时必须先找到var2,因此先找到外层作用域中的var2,赋值都是针对它。
inner var1:[10] id:46550216
inner var2:[200] id:46606408
outter var1:[10] id:46550216
outter var2:[200] id:46606408
2.迭代器反复调用问题
在python中迭代器是改进超大列表(大文件/大数据)常用的方法,但是因为迭代器只能用一次,用完后再使用会指向之前的末尾。实际使用中我们经常需要多次使用迭代器,如下:
def generate_iter():
for i in range(0, 10):
yield i
def test_iter1():
l = generate_iter()
total = sum(l)
print total
print(list(l))
for i in l:
print i
输出如下:
45
[]
这里反复使用了迭代器三次,但是第一次使用完成后迭代器已经指向末尾,所以转换成list为空,遍历输出也为空。如果迭代器内容很少,我们可以转换成列表,在列表上反复调用,关键是使用迭代器的很多场合有超大数据,因此不适合转成列表保存在内存中。
可以如下对上述迭代器进行改进,使用容器包装如下:
class RepeatIter():
def __init__(self):
pass
def __iter__(self):
for i in range(0, 10):
yield i
def test_iter2():
l = RepeatIter()
total = sum(l)
print total
print(list(l))
for i in l:
print i
输出结果如下,这里容器类实现了__iter__,这样每次使用迭代器时相当于调用iter(l)即调用__iter__生成新的迭代器,因此始终有效。
45
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0
1
2
3
4
5
6
7
8
9
演示代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219