深入浅出理解运用python的collection模块

Python中自带的collections模块给我们提供了便于使用同时高性能数据结构,利用这些我们可以使我们编写的代码的可读性、性能更好,不应在学习Python的过程中被忽视。

collections 模块包含数据结构抽象基类,本文我们主要介绍其中的数据结构,包括tuple、namedtuple、defaultdict、deque、Counter、OrderedDict、ChainMap。

抽象基类模块collections.abc在本文不做介绍。

首先我们介绍Python中的tuple的功能,然后再深入collections模块中的数据结构

一、tuple功能

tuple即元组,其特性如下:

  1. 不可变,是一个iterable(可迭代可重复)的对象。
  2. 拆包(将一个n元组拆开赋值给n个对象变量)
#拆包特性
user_info = ("Paul",29,178)
name,age,height = user_info
print(name,age,height)         #-->bobby 29 175

user_info = ("bobby", 29, 175, "beijing")
name, *other = user_info       #*other是用来接受任意多个参数并将其放在一个元组中
print(name, other)             #-->bobby [29, 175, "beijing"]
  1. tuple的不可变不是绝对的,比如元组元素是一个数组,但一般不建议将可变元素放入元组中
#元组的不可变不是绝对的
user_info = ("bobby1", [29, 175])
user_info[1].append(22)
print(user_info)               #-->("bobby1", [29, 175, 22])

tuple相比list存在的优点:
immutable(不可改变的)的重要性

  1. 线程安全
  2. 性能优化—tuple会作为常量在编译时确定,显著提升性能速度
  3. 拆包特性
  4. 可以作为dict的key,因为 dict的key要求是可哈希的
#tuple是不可变的数据类型 = 是可哈希的,可以当做dict的key;而数组list不可以
user_info_dict = {}       #字典dict
user_info_dict[user_info] = "bobby"       #对key键user_info赋值

如果要用C语言来类比,tuple相当于struct结构,list相当于array数组。

二、namedtuple功能详解

class创建类用法:

class User(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
user1 = User(name = "Paul",age = 20)
print(user1.name,user1.age)

而使用namedtuple就可以创建一个类,这种做法的好处就是使用 namedtuple是节省class中会创建的很多变量的空间,同时代码简洁,创建的这个类是tuple的子类,十分适用于创建一些简单的对象和数据处理。

#namedtuple
from collections import namedtuple
User = namedtuple("User", ["name", "age", "height"])  #创建class“User”类,并传递属性"name", "age", "height"]
user = User(name="bobby", age=29, height=175)         #对user初始化,也可使用下面两种方式进行初始化
print(user.age, user.name, user.height)               #像使用类一样
#使用tuple进行初始化
user_tuple = ("bobby", 29, 175)
user = User(*user_tuple)      #加*代表依次传递tuple(*args:未指明变量名)

#使用dict进行初始化
user_dict = {"name":"bobby", "age":29, "height":175}
user = User(**user_dict)       #加**代表依次传递dict(**kwargs:指明变量名(key)和值(value))

#也可使用_make函数省去*和**,_make函数支持可迭代iterable的对象:list、tuple、dict。缺点就是元素个数必须一致
user = User._make(user_tuple)
user = User._make(user_list)
user = User._make(user_dict)

_asdict方法:
返回一个OrderDict,以key的首字母排序

user_info_dict = user._asdict() 
#-->user_info_dict = OrderDict([("name","Paul"),("age",20),("height",178),("edu","master")])

三、defaultdict(default是默认的意思)功能详解

defaultdict是用C语言写的一个类,性能是比较高的。
可以用来更高性能的实现默认值初始化和简单统计

user_dict = {}
users = ["bobby1", "bobby2", "bobby3", "bobby1", "bobby2", "bobby2"]

#第一种形式
for user in users:
    if user not in user_dict:
        user_dict[user] = 1
    else:
        user_dict[user] += 1
        
#第二种形式
for user in users:
    user_dict.setdefault(user, 0)      #若user键不存在,设为默认值0
    user_dict[user] += 1
  
#第三种形式
from collections import defaultdict

default_dict = defaultdict(int)         #在键不存在的时候,调用传递对象名称int,默认传递0
for user in users:
    default_dict[user] += 1

defaultdict()中必须为可调用的对象

#如果生成嵌套的dict   
from collections import defaultdict

def gen_default():
    return {"name":"", 
    "nums":0}
default_dict = defaultdict(gen_default)
default_dict["group1"]            #没有group1时传递gen_default函数

四、deque(双端队列)功能详解

pop是对尾部进行操作

user_list = ["bobby", "bobby2"]
user_name = user_list.pop()        #pop只能对队尾进行操作
print(user_name, user_list)       #-->bobby2 ["bobby"]
 

deque双端队列:对队列两端进行操作,尽量保存相同类型数据

from collections import deque

user_tuple = deque(("bobby1", "bobby2")) 
user_list = deque(["bobby1", "bobby2"])
user_dict = deque({"bobby1":28, "bobby2":29})         #以上三种打印结果一样:deque(['bobby1', 'bobby2'])

copy方法是浅复制,只是复制了列表中每个元素指向的位置,而不会拷复制如可变对象的所有内容
深复制:将复制的数据和数据的类型都复制
extend方法:是在原对象上进行扩容,没有返回值

注意:deque是线程安全的,而list不是,可以在多线程时应用这一特性

五、Counter功能详解

Counter是dict的一个子类,能实现统计,Counter()中传入的必须是可迭代对象

from collections import Counter
users = ["bobby1", "bobby2", "bobby3", "bobby1", "bobby2", "bobby2"]
user_counter = Counter(users)
print(user_counter)                     #打印出dict并按键值大小顺序排列:Counter({"bobby2":3,"bobby1":2,"bobby3":1})
 
user_counter = Counter("adgdfcdg")      #传递字符串,统计每个字符的次数

#update方法可以传递Counter,也可以传递可迭代对象
user_counter.update("djgidg")           #传递字符串(可迭代对象)合并统计

user_counter2 = Counter("djgidg")
user_counter.update(user_counter2)      #传递Counter,合并统计

利用most_common方法可以实现top n的问题,即统计出现次数最多的前n个元素

#可以实现top n 的问题 ,利用的是堆这种数据结构
user_counter.most_common(2)       #统计出现次数最多的前2个元素 -->[('d',4),('s',3)]

六、OrderDict功能详解

OrderDict是dict的一个子类
Python3中OrderDict和dict的初始化都是有序的(按照添加的顺序),而Python2中dict是无序的,OrderDict是有序的

from collections import OrderDict  

popitem方法;实现将尾部的键值对pop出来,pop则需要提供key参数

move_to_end方法:实现将指定的key的键值对放到尾部去

七、ChainMap功能详解

实现对多个dict的访问,相当于对一个dict的访问

from collections import ChainMap

user_dict1 = {"a":1}
user_dict2 = {'b":2}

new_dict = ChainMap(user_dict1,user_dict2)
然后就可以在new_dict上实现对user_dict1和user_dict2的共同操作

总结

常用的是namedtuple、deque和defaultdict三个数据结构,熟悉使用collections模块可以使我们的代码更简洁可读和性能更加优化。collections中还包括抽象基类这一重要部分,后续继续一起学习…

阅读更多精彩内容,请关注微信公众号:大众学python
在这里插入图片描述

你可能感兴趣的:(Python)