python--collections

namedtuple

from collections import namedtuple

girl = namedtuple("aaa", ["name", "age", "gender", "anime"])

girl = girl(name="satori", age=18, gender="f", anime="东方地灵殿")
print(girl)  # aaa(name='satori', age=18, gender='f', anime='东方地灵殿')

print(girl.name)  # satori
print(girl.age)  # 18
print(girl.anime)  # 东方地灵殿

  

from collections import namedtuple

girl = namedtuple("aaa", ["name", "age", "gender", "anime"])

t = ("satori", 18, "f", "东方地灵殿")

# 也可以不指定列名,直接按照顺序传入参数
girl = girl(*t)
print(girl)  # aaa(name='satori', age=18, gender='f', anime='东方地灵殿')


# 也可以传入一个字典
d = {
    "name": "satori",
    "age": 18,
    "gender": "f",
    "anime": "东方地灵殿"
}
girl = namedtuple("aaa", ["name", "age", "gender", "anime"])
girl = girl(**d)
print(girl)  # aaa(name='satori', age=18, gender='f', anime='东方地灵殿')

  

defaultdict

# 如果是一般的字典的话,当我们想要统计次数的话
l = ["a", "b", "a", "c", "c", "a", "a"]
d = {}

for i in l:
    if i not in d:
        d[i] = 1
    else:
        d[i] += 1

print(d)  # {'a': 4, 'b': 1, 'c': 2}

# 这段代码有什么问题呢?其实没什么问题,就是当数据量大了时候,会很麻烦
# 这时候defaultdict就出现了

  

from collections import defaultdict

# 里面要传入一个可调用的对象,什么意思呢?
default_dict = defaultdict(int)

# 当我访问一个不存在的值
print(default_dict["a"])  # 0

default_dict = defaultdict(str)
print(default_dict["a"])  # ""

default_dict = defaultdict(tuple)
print(default_dict["a"])  # ()

default_dict = defaultdict(list)
print(default_dict["a"])  # []

default_dict = defaultdict(set)
print(default_dict["a"])  # set()

default_dict = defaultdict(dict)
print(default_dict["a"])  # {}

# 看到这应该就明白了,如果访问一个不存在的key,那么会首先创建该key,然后value对应defaultdict里面传入的类型的初始值

l = ["a", "b", "a", "c", "c", "a", "a"]
default_dict = defaultdict(int)
for i in l:
    # 首先没有key会创建,然后value初始化为0,然后执行+=1
    # 注意:在没有相应的key的时候,这行代码表示执行两个步骤
    # 先执行default_dict[i] = 0
    # 然后default_dict[i] += 1
    # 当key存在的时候,直接执行+=1操作
    default_dict[i] += 1
    # 这样操作就大大简便了
    # 普通的列表的话,也可以使用setdefault,但是还是这个简单

print(default_dict)  # defaultdict(<class 'int'>, {'a': 4, 'b': 1, 'c': 2})
print(type(default_dict))  # <class 'collections.defaultdict'>

# 也可以直接转化为字典
print(dict(default_dict))  # {'a': 4, 'b': 1, 'c': 2}

# 那么defaultdict是如何实现的呢?主要用到了__missing__这个魔法函数
class A(dict):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def __missing__(self, key):
        return key
# 必须继承dict
a = A(name="satori", age=19)
# 可以看到a中只有name和age这两个属性
print(a["name"])  # satori
print(a["age"])  # 19
# 当我访问一个不存在的属性
print(a["mmp"])  # mmp
# __missing__的作用就在于此,当然这个魔法方法只能用在dict的子类当中。要是普通的类,可以用__getattr__

# 来模拟一下defaultdict
class Satoridict(dict):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def __missing__(self, key):
        self[key] = 0
        return self[key]

    def __getitem__(self, item):
      #  return self[item],不可以return self[item]
      #  为什么?因为调用__getitem__,return self[item],然后又执行__getitem__,又return self[item],从而无限递归
      #  那么怎么获取值呢?return item的话会不报错,但获取的只是key,得不到value啊
      #  我们可以调用父类的方法

        value = super().__getitem__(item)
        # 会先执行__getitem__方法,在执行super().__getitem__的时候
        # 如果没有__missing__方法,会报错,KeyError。
        # 如果有__missing__那么会执行__missing__方法,设置self[key]=0,返回self[key]
        return value


satori = Satoridict(name="Satori", age=18, gender="f")
print(satori["name"])  # Satori
print(satori["age"])  # 18

# 访问一个不存在的值
print(satori["aaa"])  # 0

  

  

deque

# 先来看看queue
from queue import Queue

q = Queue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())  # 1
print(q.get())  # 2
print(q.get())  # 3

# 默认的队列,只能append,而且取的时候只能从头开始取

  

from collections import deque

# 双端队列,可以从两段插入,也可以从两段取值

q = deque(("a", "b", "c"))
q.append(1)
q.appendleft(2)
print(q)  # deque([2, 'a', 'b', 'c', 1])
# 也可以通过索引取值
print(q[1])  # a
# 通过pop取值
print(q.pop())  # 1
print(q.popleft())
print(q)  # deque(['a', 'b', 'c']), 可以看到和list一样,pop之后q的元素减少了

# deque的绝大部分api和list是一致的,只是deque多了appendleft,popleft,extendleft
# 对list如何操作,对deque也如何操作就行了,会list就会deque,这里的一些方法不赘述了
# 最重要的一点,deque和queue一样也是线程安全的,是由GIL这把超级大锁保护的


# 和queue相比,deque还有一个重要的地方
import queue

q1 = queue.Queue(maxsize=3)
q2 = deque(maxlen=3)
# 当q1塞满三个元素之后,再想塞第四个就塞不进去为了
# 但是对q2来说,塞多少个都没问题,我们来打印一下
q2.append(1)
q2.append(2)
q2.append(3)
print(q2)  # deque([1, 2, 3], maxlen=3)
q2.append(4)
print(q2)  # deque([2, 3, 4], maxlen=3)
q2.append(5)
print(q2)  # deque([3, 4, 5], maxlen=3)
q2.append(6)
print(q2)  # deque([4, 5, 6], maxlen=3)

# 可以看到最多容纳三个,再添加的话那么,会被挤掉。可以用来制作历史记录,最多查看多少次等等
try:
    q2.insert(1, "satori")
except Exception as e:
    print(e)  # deque already at its maximum size
# 另外在满了的时候,不可以通过insert插入值

# 那么appendleft可以吗?我们来试试
q2.appendleft("satori")
print(q2)  # deque(['satori', 4, 5], maxlen=3)
# 6没有了
# 可以看到,当从后面插入的时候(o(*////▽////*)q),那么前面的会被挤掉
# 从前面插入的时候(o(*////▽////*)q),后面会被挤掉

# extend呢?
q2.extend(["mashiro", "miku"])
print(q2)  # deque([5, 'mashiro', 'miku'], maxlen=3)
# 可以看到,satori和4没有了,说明extend也是可以的
# 同理extendleft也可以使用,这里不再试了

  

Counter

from collections import Counter

# 在defaultdict的时候,我们统计了列表里面的值的个数
# Counter可以做的更方便
l = ["a", "b", "a", "c", "c", "a", "a"]

c = Counter(l)
print(c)  # Counter({'a': 4, 'c': 2, 'b': 1})
# 结果直接统计出来了
# 而且Counter对象是dict的一个子类,说明字典的api,Counter也可以使用
print(c["a"])  # 4
# 当然也可以转化为字典
print(dict(c))  # {'a': 4, 'b': 1, 'c': 2}

# 不仅是list,只要是可迭代对象都是可以的
s = "aaaabbbccd"
c2 = Counter(s)
print(c2)  # Counter({'a': 4, 'b': 3, 'c': 2, 'd': 1})

# 上面也说了,Counter是dict的一个子类
# 那么Counter也可以使用update方法,而且更强大
c2.update("abcd")
print(c2)  # Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2})
# 可以看到将abcd和上面的s进行一个合并的统计
# 你以为强大就强大在这里吗?
c2.update(["a", "b", "c", "d", "古明地盆"])
print(c2)  # Counter({'a': 6, 'b': 5, 'c': 4, 'd': 3, '古明地盆': 1})
# 我还可以update一个列表,那么列表里面的元素会作为(古明地盆)一个整体统计

# 此外update还可以接受一个Counter
c3 = Counter("aaaaaaaaaaa")
print(c3)  # Counter({'a': 11})
c2.update(c3)
print(c2)  # Counter({'a': 17, 'b': 5, 'c': 4, 'd': 3, '古明地盆': 1})

# 还有一个最重要的方法
# 如果我们想要在c2中选出value最大的三个key该怎么办呢?
# 直接实现会很麻烦,可以使用heapq,当然Counter底层也是调用了heapq
import heapq
print(heapq.nlargest(3, c2, key=lambda x: c2[x]))  # ['a', 'b', 'c']
# 再来看看Counter
print(c2.most_common(3))  # [('a', 17), ('b', 5), ('c', 4)]
# 会将key,和key对应的最大的value按照顺序以列表嵌套元组的方式显示出来,非常的直观


# 你以为Counter就到此为止了,确实目前来说已经够用了
# 但是还有一些黑科技
print(c2)  # Counter({'a': 17, 'b': 5, 'c': 4, 'd': 3, '古明地盆': 1})
print(c3)  # Counter({'a': 11})
print(c2 + c3)  # Counter({'a': 28, 'b': 5, 'c': 4, 'd': 3, '古明地盆': 1})
# c2 + c3,表示将两者的结果进行组合,key相同,那么将对应的value相加
print(c2 - c3)  #Counter({'a': 6, 'b': 5, 'c': 4, 'd': 3, '古明地盆': 1})
# c2 - c3,表示如果c3中有c2的元素,就把该元素从c2当中减去,当然还有数量的问题

# 既然如此,那么Counter是否支持集合的操作呢?比如&|^等等
# 我们来看看
c4 = Counter("aabbbcc")
c5 = Counter("bbccdd")
print(c4)  # Counter({'b': 3, 'a': 2, 'c': 2})
print(c5)  # Counter({'b': 2, 'c': 2, 'd': 2})
# c4 & c5,和c4 + c5不同,这真的是在做交集,不会相加
# 并且key相同的话,选择value小的那一个
print(c4 & c5)  # Counter({'b': 2, 'c': 2})
# key相同,也不会将value相加,而是选择value较大的那一个
print(c4 | c5)  # Counter({'b': 3, 'a': 2, 'c': 2, 'd': 2})
'''
print(c4 ^ c5),Counter不支持^(也就是对称差集)的操作,也没什么意义
'''

# 以上就是我能想到的Counter的全部内容了,也许还有一些方法没有介绍到
# 但是你会字典的那些方法的话,也肯定会Counter的那些方法
# Counter最主要的概念和用法就说到这里,个人认为应该就是够用了

  

OrderedDict

from collections import OrderedDict

# 从字面理解就知道是一个排好序的dict
# 继承自dict,所以dict有的api,它都有

d = OrderedDict()
d["a"] = 1
d["e"] = 2
d["c"] = 3
print(d)  # OrderedDict([('a', 1), ('e', 2), ('c', 3)])
# 显然和我们添加顺序是一样的

# 除此之外再介绍一个api,move_to_end
d.move_to_end("a")  # 从名字也可以理解出,把a移到最后
print(d)  # OrderedDict([('e', 2), ('c', 3), ('a', 1)])
# 其他的和字典类似,就不介绍了。

  

ChainMap

from collections import ChainMap

d1 = {"a": 1, "b": 2}
d2 = {"c": 2, "d": 2}
d = ChainMap(d1, d2)
for k, v in d.items():
    print(k, v)
'''
c 2
d 2
a 1
b 2
'''
# 因此ChainMap的作用就是将多个字典组合成一个字典

# 如果多个字典,key重合了会怎么样?
d3 = {"a": 1, "b": 2}
d4 = {"b":3, "c": 4}
d = ChainMap(d3, d4)
for k, v in d.items():
    print(k, v)
'''
a 1
b 2
c 4
'''
# 可以看到即使value不一样,还是只打印了第一个

# 这个方法比较像chain
from itertools import chain
a = [1, 2, 3]
b = "abc"
c = {1, 2, 3}
d = {"name": "satori", "age": 15}
for i in chain(a, b, c, d):
    print(i)
'''
1
2
3
a
b
c
1
2
3
name
age
'''

  

猜你喜欢

转载自www.cnblogs.com/traditional/p/9383979.html