全文1929字,阅读时间3分钟,点击蓝色字体关注
号内福利
精华文章大合集: 认真就能打动人:273篇干货资料汇总
机器学习入门视频 吴恩达机器学习完整系列视频教程
承接上文:Python解惑之对象可变与不可变,文中提到,对象的可变(mutable object) 与不可变(immutable object)值得重视。不可变对象更改会创建很多新的对象,造成内存堆积;可变对象,易于修改,也会产生副作用。
分别通过两个经典例子解释:不可变和可变对象之陷阱。
不可变对象陷阱
思路:生成1百万个随机字符串,分别使用不可对象或可变对象合并字符串,比较花费时间。
生成随机字符串的代码:
import random import time
big = [chr(i) for i in range(65,91)]small = [chr(i) for i in range(97,123)]
def randNStr(n): ...: result = [] ...: for i in range(n): ...: strlen = random.randint(3,9) ...: result.append(''.join(random.sample(small+big,strlen))) ...: return result
使用不可变对象方法:combine+s 再赋值给combine,这条语句:因为combine, s都为不可变对象,返回的结果就是新生成一个对象,对象不断堆积。
def immfn(n): ...: combine='' ...: res = randNStr(n) ...: beg = time.time() ...: print('beg time %s'%str(beg)) ...: for s in res: ...: combine = combine + s ...: #print(combine) ...: end = time.time() ...: print('end time %s'%str(end)) ...: print('elispe time: %s'%str(end-beg))
为了避免重复生成新的对象,使用可变对象,文中 Python解惑之对象可变与不可变 提到过,一般可迭代对象,都是可变的。
def mutfn(n): ...: combine='' ...: res = randNStr(n) ...: beg = time.time() ...: print('beg time %s'%str(beg)) ...: combine = ''.join(res) ...: #print('print result:%s'%combine) ...: end = time.time() ...: print('end time %s'%str(end)) ...: print('elispe time: %s'%str(end-beg))
此处使用 str.join(iter),接受可迭代对象,并只返回一个新对象。比较以上两种方法的计算时间,分别从10万,步长10万,终止到100万,比较分析合并字符串的时间。
可以看到可变对象只生成一个新对象的方法,比不可变对象在数据量越大情况下,优势更明显,呈现扩张的喇叭口,当数据为90万时,节省时间成本高达:(0.19-0.025)/0.025 = 6.6 倍。当数据量增长到1千万或更大时,优势更明显。
可变对象陷阱
这篇文章是号内推送过的一篇文章,也是Python一道经典面试题,非常容易掉入考官陷阱。再分析一遍。
题目是这样的:
def f(x,l=[]): ...: for i in range(x): ...: l.append(i*i) ...: print(l)
f(2)f(3)
结果为:
In [2]: f(2) [0, 1]
In [3]: f(3) [0, 1, 0, 1, 4]
原因,可变对象作为函数参数,并被设为默认值后,当被再次调用函数后,函数参数原来取值将被再次索引。
为了避免这个问题,可变对象的默认值一般取值为常数:None
def f(x,l=None): ...: if l is None: ...: l = [] ...: for i in range(x): ...: l.append(i*i) ...: print(l) ...:
这样连续被调用时,将会按照预期输出。