由于没有系统的学习python,所以用的时候有时候会走入坑中。例如今天写代码遇到两个问题:
- 在类的方法中引用了类的成员变量给方法中的变量赋值,而这个成员变量是字典类型,结果发现
修改方法中的变量时,将类的成员变量值一并修改了。
class A(object):
r={}
def __init__(self):
self.d = {"k":"aaa"}
def A1(self):
d2 = self.d
d2['k'] = 'bbb'
if __name__ == "__main__":
a = A()
a.A1()
print a.d
'''
输出:{"k":"bbb"}
'''
可以看到,其实我只是修改了,方法中的变量d2,但是成员d的值也被修改了。
- 以变量形式向列表添加字典,修改列表中元素的值,原字典也改变了
if __name__ == "__main__":
d={'k':''}
l = []
l.append(d)
l[0]['k'] = 'aaa'
l.append(d)
print d
print l
'''
其实不仅是列表,变量赋值也一样:
d1 = {"k":""}
d2 = d1
d2["k"] = 123
print d1 #{"k",123}
'''
输出:
d={'k':'aaa'}
[{'k':'aaa'},{'k':'aaa'}]
可以看到我只是修改了列表的元素,但是字典的值也变了。
而第二次append(d)后,并没有对l[2]修改,但是由于d变了,
导致添加后的列表l[1]['k']
的值已经不是字典d开
始的值了。
通过几组测试,发现列表和字典在python底层,使用地址形式存储,而使用等号相当于只是做
了浅拷贝,在底层仍然是用的是指针的方式,所以可以使用深拷贝解决问题。关于深浅拷贝,简单的来说就是,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存
demo:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import copy
class A(object):
r={}
def __init__(self):
self.x = 0
self.l = []
self.s = "sss"
self.d = {"k":"aaa"}
def A1(self):
x2 = self.x
x2 = 2 ##int数 x2 修改后 类的成员self.x不变
def A3(self):
s2 = self.s
s2 = "abc" ##字符串 s2修改后 类的成员self.s不变
def A2(self):
l2 = self.l
l2.append(self.x) ##列表 l2 修改后 类的成员self.s的值-->跟随l2改变
l2[-1] = 2
def A4(self):
d2 = self.d
r2 = self.r
d2['k']="bbb" ##字典 d2 修改后 类的成员self.d的值-->跟随d2改变
r2['k']="bbb" ##同上
def A5(self):
l2 = []
x2 = 0
s2 = ""
l2.append(x2) ## 以变量形式向列表添加 int数和字符串
l2.append(s2)
print "l2:",l2
print "x2:", x2
print "s2:",s2
l2[0] = '123' ## 修改列表中对应元素的值
l2[1]= "bbb"
print "l2:", l2
print "x2:", x2 ## 原int数、字符串的值不变
print "s2:", s2
def A6(self):
l2 = []
l3 = []
d3 = {'k':''}
l2.append(d3) ## 以变量形式向列表添加 列表和字典
l2.append(l3)
print "l2:",l2
print "l3:", l3
print "d3:",d3
l2[0]['k'] = 'bbb' ## 修改列表中对应元素的值
l2[1].append("bbb")
#--------------------------------------------------------
# 这里用append()会使原列表l3变化,但如果是l2[1]=["bbb"]则不会
# l2.append(l3)相当于将l2的末尾节点指向了l3内存空间,
# 而l2[1].append("bbb")相当于向这个内存空间存储“bbb”,
# l2[1] = ['bbb']则是将l2的末尾节点重定向到了['bbb']
#--------------------------------------------------------
print "l2:",l2
print "l3:", l3 ##原列表、字典的值都变化,
print "d3:",d3
### 字典的深拷贝
def A_dep(self):
print "self.d",self.d
print "self.r",self.r
d_cp = copy.copy(self.d)
r_dpcp = copy.deepcopy(self.r)
d_cp['k'] = 'ccc'
r_dpcp['k'] = 'ccc'
print "d_cp",d_cp
print "r_dpcp",r_dpcp
print "self.d",self.d ## 使用两种深拷贝,在内存中重新开辟了空间,而不是指针指向的方式
print "self.r",self.r
ll = []
ll2 = []
ll.append(copy.copy(self.d))
ll2.append(copy.deepcopy(self.r))
ll[0]['k'] = "ccc"
ll2[0]['k'] = "ccc"
print "ll:",ll
print "ll2:", ll2
print "self.d", self.d ## 以变量形式向列表添加字典,也是一样
print "self.r", self.r
if __name__ == "__main__":
a=A()
print "___测试修改类中的成员:int数___"
a.A1()
print "self.x:",a.x
print "___测试修改类中的成员:字符串___"
a.A3()
print "self.s:", a.s
print "___测试修改类中的成员:列表___"
a.A2()
print "slef.l:",a.l
print "self.x:",a.x
print "___测试修改类中的成员:字典___"
a.A4()
print "self.d",a.d
print "self.r",a.r
print "___测试以变量方式向列表添加int数、字符串,然后修改列表中int数、字符串的值,原int数、字符串是否变化___"
a.A5()
print "___测试以变量方式向列表添加列表字典,然后修改列表中列表、字典元素的值,原列表、字典是否变化___"
a.A6()
print "___测试字典深拷贝____"
a.A_dep()
'''
/usr/bin/python2.7 /home/zhanglu/PycharmProjects/log_parsing/test_01.py
___测试修改类中的成员:int数___
self.x: 0
___测试修改类中的成员:字符串___
self.s: sss
___测试修改类中的成员:列表___
slef.l: [2]
self.x: 0
___测试修改类中的成员:字典___
self.d {'k': 'bbb'}
self.r {'k': 'bbb'}
___测试以变量方式向列表添加int数、字符串,然后修改列表中int数、字符串的值,原int数、字符串是否变化___
l2: [0, '']
x2: 0
s2:
l2: ['123', 'bbb']
x2: 0
s2:
___测试以变量方式向列表添加列表字典,然后修改列表中列表、字典元素的值,原列表、字典是否变化___
l2: [{'k': ''}, []]
l3: []
d3: {'k': ''}
l2: [{'k': 'bbb'}, ['bbb']]
l3: ['bbb']
d3: {'k': 'bbb'}
___测试字典深拷贝____
self.d {'k': 'bbb'}
self.r {'k': 'bbb'}
d_cp {'k': 'ccc'}
r_dpcp {'k': 'ccc'}
self.d {'k': 'bbb'}
self.r {'k': 'bbb'}
ll: [{'k': 'ccc'}]
ll2: [{'k': 'ccc'}]
self.d {'k': 'bbb'}
self.r {'k': 'bbb'}
进程完成,退出码 0
'''