这是一则关于时间复杂度的思考引发的代码瘦身案
由时间复杂度引出的思考与行动
之前看到这样一段代码:
class SequencePattern(object):
def __init__(self, sequence, frequent):
self.sequence = []
for s in sequence:
self._sequence.append(s)
self.frequent = frequent
初始化后self._sequence的值与sequence的值相等,这段代码没有语法错误;但我非常好奇,既然如此,为什么要通过for循环来给self._sequence赋值,增加时间复杂度,而不直接使用self._sequence = sequence来赋值?这样写有什么好处?
于是,按照我的想法修改代码如下:
class SequencePattern(object):
def __init__(self, sequence, frequent):
self.sequence = sequence
self.frequent = frequent
我们来测试看看:
if __name__ == "__main__":
seq, freq = [1, 2, 3], 2
sp = SequencePattern(seq, freq)
sp.sequence.append(4)
print "sp.sequence:", sp.sequence
print "seq:", seq
得到如下结果:
sp.sequence: [1, 2, 3, 4]
seq: [1, 2, 3, 4]
我只想修改sp实例的sequence属性,并不想修改变量seq,那么变量seq为什么也被修改了呢?这就涉及到了Python对象的赋值、拷贝等相关概念
Python对象的赋值、深拷贝、浅拷贝
python中的变量存储的是变量的地址,而非变量的值
- 赋值
复制原变量的地址,原变量与被赋值变量共享内存地址,一个变量修改,另一个变量也会同时被修改
若a = [1,2,3],将a赋值给b,即b=a;这样的赋值只是给对象[1,2,3]增加了一个引用,即a和b都指向对象[1,2,3]的地址;若b.append(4),则b=[1,2,3,4],且a=[1,2,3,4]
>>> a=[1,2,3]
>>> b=a
>>> b.append(4)
>>> print b
[1, 2, 3, 4]
>>> print a
[1, 2, 3, 4]
a.append(5)
>>> print b
[1, 2, 3, 4, 5]
>>> print a
[1, 2, 3, 4, 5]
- 浅拷贝copy.copy()
对于复合对象而言,浅拷贝会新开辟一块地址存放复制来的数据,但浅拷贝只能复制原变量最外层对象的数据,对于深层的对象,只能复制其地址,不能复制其数据
>>> c = [6,7,8]
>>> d = [9,10,c]
>>> print d
[9, 10, [6, 7, 8]]
>>> e = copy.copy(d) #浅拷贝
>>> print d
[9, 10, [6, 7, 8]]
>>> print e
[9, 10, [6, 7, 8]]
# 外层对象的修改,互不影响
>>> d[0]=11
>>> e[0]=12
>>> print d
[11, 10, [6, 7, 8]]
>>> print e
[12, 10, [6, 7, 8]]
>>> print id(d)
4400860696
>>> print id(e)
4400861056
#d, e共用深层对象c的地址,所以c被修改后,d,e都会被修改
>>> c.append(13)
>>> print d
[11, 10, [6, 7, 8, 13]]
>>> print e
[12, 10, [6, 7, 8, 13]]
- 深拷贝 copy.deepcopy()
复制原变量的所有数据,原变量与被拷贝变量各自完全独立,对一个变量的修改不会影响另一个变量
>>> f=copy.deepcopy(d) # f完全拷贝d的所有数据
>>> print d
[11, 10, [6, 7, 8, 13]]
>>> print f
[11, 10, [6, 7, 8, 13]]
#子对象的修改不影响新变量
>>> c.append(14)
>>> print d
[11, 10, [6, 7, 8, 13, 14]]
>>> print f
[11, 10, [6, 7, 8, 13]]
代码瘦身
import copy
class SequencePattern(object):
def __init__(self, sequence, frequent):
self.sequence = copy.deepcopy(sequence)
self.frequent = copy.deepcopy(frequent)