38、使用cpoy模块深拷贝对象
浅拷贝(shallow copy):构造一个新的复合对象,并将从原对象中发现的引用插入新对象中。
深拷贝(deep copy):构造一个新的复合对象,但遇到引用时,会继续递归拷贝其指向的具体内容,也就是说,他会针对引用所指向的对象继续拷贝,因此产生的对象不受其它引用对象操作的影响。
深拷贝需要依赖copy模块中的deepcopy函数。
在包含引用的数据结构中,浅拷贝“仅仅拷贝了引用,而不是引用所指向的具体内容”,深拷贝不仅拷贝引用,也拷贝引用所指向的对象,深拷贝得到的对象和原对象是完全相互独立的。
参考以下代码:
import copy
#定义Pizza类
class Pizza(object):
def __init__(self, name, size, price):
self.name = name
self.size = size
self.price = price
def get_pizza_info(self):
#获取pizza相关信息
return self.name, self.size, self.price
def show_pizza_info(self):
#显示pizza信息
print ('Pizza name: {}'.format(self.name))
print ('Pizza size: {}'.format(self.size))
print ('Pizza price: {}'.format(self.price))
def change_size(self, size):
self.size = size
def change_price(self, price):
self.price = price
#定义订单类
class Order(object):
def __init__(self, name):
self.customer_name = name
self.pizza_list = []
self.pizza_list.append(Pizza('Mushroom', 12, 30))
def order_more(self, pizza):
self.pizza_list.append(pizza)
def change_name(self, name):
self.customer_name = name
def get_order_detail(self):
print ("customer name: " + self.customer_name)
for pizza in self.pizza_list:
pizza.show_pizza_info()
def get_pizza(self, number):
return self.pizza_list[number]
#客户1的订单
customer1 = Order('Zhang')
customer1.order_more(Pizza('seafood', 9, 40))
customer1.order_more(Pizza('fruit', 12, 35))
print ("customer1 order information: ")
customer1.get_order_detail()
print ('-' * 30)
#客户2的订单
#先用浅拷贝
customer2 = copy.copy(customer1)
print ("order 2 customer name: {}".format(customer2.customer_name))
customer2.change_name('Li')
customer2.get_pizza(2).change_size(9)
customer2.get_pizza(2).change_price(30)
print ('customer2 order information: ')
customer2.get_order_detail()
print ('-' * 30)
#再回头检查客户1的订单信息
print ("custome1 order information: ")
customer1.get_order_detail()
浅拷贝输出如下:
customer1 order information:
customer name: Zhang
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 12
Pizza price: 35
------------------------------
order 2 customer name: Zhang
customer2 order information:
customer name: Li
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 9
Pizza price: 30
------------------------------
custome1 order information:
customer name: Zhang
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 9
Pizza price: 30
改用深拷贝:
#deep copy
customer2 = copy.deepcopy(customer1)
输出结果如下:
customer1 order information:
customer name: Zhang
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 12
Pizza price: 35
------------------------------
order 2 customer name: Zhang
customer2 order information:
customer name: Li
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 9
Pizza price: 30
------------------------------
custome1 order information:
customer name: Zhang
Pizza name: Mushroom
Pizza size: 12
Pizza price: 30
Pizza name: seafood
Pizza size: 9
Pizza price: 40
Pizza name: fruit
Pizza size: 12
Pizza price: 35
39、使用Counter进行计数
首先介绍三种传统计数方法:
- 使用dict
some_data = ['a', '2', 2, 4, 5, '2', 'b', 4, 7, 'a', 5, 'd', 'a', 'z']
count_frq = dict()
for item in some_data:
if item in count_frq:
count_frq[item] += 1
else:
count_frq[item] = 1
print (count_frq)
#输出结果如下
'a': 3, '2': 2, 2: 1, 4: 2, 5: 2, 'b': 1, 7: 1, 'd': 1, 'z': 1}
- 使用defaultdict
from collections import defaultdict
some_data = ['a', '2', 2, 4, 5, '2', 'b', 4, 7, 'a', 5, 'd', 'a', 'z']
count_frq = defaultdict(int)
for item in some_data:
count_frq[item] += 1
print (count_frq)
#输出结果如下
defaultdict(<class 'int'>, {'a': 3, '2': 2, 2: 1, 4: 2, 5: 2, 'b': 1, 7: 1, 'd': 1, 'z': 1})
- 使用set和list
some_data = ['a', '2', 2, 4, 5, '2', 'b', 4, 7, 'a', 5, 'd', 'a', 'z']
count_set = set(some_data)
count_list = []
for item in count_set:
count_list.append((item, some_data.count(item)))
print (count_list)
#输出结果如下
[('b', 1), (2, 1), (4, 2), (5, 2), (7, 1), ('2', 2), ('z', 1), ('d', 1), ('a', 3)]
- 更优雅的更pythonic的方法:使用colletcions.Counter函数
from collections import Counter
some_data = ['a', '2', 2, 4, 5, '2', 'b', 4, 7, 'a', 5, 'd', 'a', 'z']
print (Counter(some_data))
#输出结果如下
Counter({'a': 3, '2': 2, 4: 2, 5: 2, 2: 1, 'b': 1, 7: 1, 'd': 1, 'z': 1})
划重点:相关知识介绍
- set()函数
set函数创建一个无序不重复的集合,参数为可迭代对象,返回一个新的集合对象。
setname = set(iteration)
添加有两种方法:add()和update(),add是整个添加,update是拆分添加
>>> a = set('Wheel')
>>> a
set(['h', 'e', 'l', 'W'])
>>> a.add('Witch')
>>> a
set(['h', 'Witch', 'e', 'l', 'W'])
>>> a.update('007')
>>> a
set(['e', '7', 'h', 'l', '0', 'Witch', 'W'])
- defaultdict类
python中,访问一个不存在的字典中的键,会产生KeyError异常:
>>> dict = {'Name':'Bob', 'Age':30}
>>> dict['Name']
'Bob'
>>> dict['Title']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Title'
使用collections.defaultdict类
注:下面的文字来自python中defaultdict方法的使用
defaultdict类就好像是一个dict,但是它是使用一个类型来初始化的:
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> dd
defaultdict(<type 'list'>, {})
defaultdict类的初始化函数接受一个类型作为参数,当所访问的键不存在的时候,可以实例化一个值作为默认值:
>>> dd['foo']
[]
>>> dd
defaultdict(<type 'list'>, {'foo': []})
>>> dd['bar'].append('quux')
>>> dd
defaultdict(<type 'list'>, {'foo': [], 'bar': ['quux']})
需要注意的是,这种形式的默认值只有在通过dict[key]或者dict.getitem(key)访问的时候才有效。
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> 'something' in dd
False
>>> dd.pop('something')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'pop(): dictionary is empty'
>>> dd.get('something')
>>> dd['something']
[]
defaultdict类除了接受类型名称作为初始化函数的参数之外,还可以使用任何不带参数的可调用函数,到时该函数的返回结果作为默认值,这样使得默认值的取值更加灵活。下面用一个例子来说明,如何用自定义的不带参数的函数zero()作为defaultdict类的初始化函数的参数:
>>> from collections import defaultdict
>>> def zero():
... return 0
...
>>> dd = defaultdict(zero)
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {})
>>> dd['foo']
0
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {'foo': 0})
利用collections.defaultdict来解决最初的单词统计问题,代码如下:
from collections import defaultdict
strings = ('puppy', 'kitten', 'puppy', 'puppy',
'weasel', 'puppy', 'kitten', 'puppy')
counts = defaultdict(lambda: 0) # 使用lambda来定义简单的函数
for s in strings:
counts[s] += 1
或者:
from collections import defaultdict
strings = ('puppy', 'kitten', 'puppy', 'puppy',
'weasel', 'puppy', 'kitten', 'puppy')
counts = defaultdict(int)
for s in strings:
counts[s] += 1
- Counter类
Counter类,存在于collections包内,用于跟踪值出现的次数,是一个无序的容器类型,以字典的键值对的形式存储。
- 创建方式:
from collections import Counter
c = Counter() #空的Counter类
c = Counter('gallahad') #从一个可迭代对象创建
c = Counter({'a':4, 'b':2}) #从字典创建
c = Counter(a=4, b=2) #从键值对创建(关键字实参)
当访问的键值不存在时,返回0,而不是keyError,否则返回它的计数。
- 更新:update()
可使用一个可迭代对象或另一个Counter对象更新键值。
from collections import Counter
>>> c = Counter('Which')
>>> c
Counter({'h': 2, 'i': 1, 'c': 1, 'W': 1})
>>> c.update('Witch')
>>> c
Counter({'h': 3, 'i': 2, 'c': 2, 'W': 2, 't': 1})
>>> c['h']
3
>>> d = Counter('witch')
>>> d
Counter({'i': 1, 'h': 1, 'c': 1, 't': 1, 'w': 1})
>>> c.update(d)
>>> c
Counter({'h': 4, 'c': 3, 'i': 3, 't': 2, 'W': 2, 'w': 1})
>>> c['h']
4
- 减少:subtract()
更多关于Counter的信息,可以参考阅读:collections模块—— Counter