深入理解py特性 その四 (内置数据类型)

这其实是数的第五章内容

此时的我早已经通读此书, 总的来说没啥子收获,我想了解一些可以出去装B的东西, 很不巧, 这会本书,,

 第五章主要讲的是py内置的数据结构

字典结构

1 OrderedDict 能记住字典顺序的字典

其实,现在也没啥子用处了。从py3.6开始,字典就是能记住顺序的,这里说的是插入顺序。

import collections

d = collections.OrderedDict(one=1, two=2, three=3)
print(d)   # OrderedDict([('one', 1), ('two', 2), ('three', 3)])
d['four'] = 4
print(d)    # OrderedDict([('one', 1), ('two', 2), ('three', 3), ('four', 4)])
print(d.keys()) # odict_keys(['one', 'two', 'three', 'four'])

2 defaultdict    为缺失的键返回默认值

这个还是有些用处的。

default_factory 接收一个工厂函数作为参数, 例如int str list set等.

from collections import defaultdict


dd = defaultdict(list)
dd['dogs'].append("Rufus")
dd['dogs'].append("Kathrin")
dd['dogs'].append("Mr Sniffles")
print(dd['dogs'])
# ['Rufus', 'Kathrin', 'Mr Sniffles']
from collections import defaultdict


dd = defaultdict(set)
dd['dogs'].add("Rufus")
dd['dogs'].add("Kathrin")
dd['dogs'].add("Mr Sniffles")
print(dd['dogs'])
# {'Mr Sniffles', 'Kathrin', 'Rufus'}

3 ChainMap      搜索多个字典

将多个字典分组到一个映射中,在查找时逐个搜索底层映射,直到找到一个符合条件的键。对ChainMap进行插入、更新和删除操作,只会作用于其中第一个字典。

感觉有点东西, 虽然不知道有啥用

from collections import ChainMap


dict1 = {'one': '1', 'two': 2}
dict2 = {'three': 3, 'four': 4}
chain = ChainMap(dict1, dict2)
print(chain)    # ChainMap({'one': '1', 'two': 2}, {'three': 3, 'four': 4})
print(chain['four'])  # 4
chain['six'] = "6"
print(chain)    # ChainMap({'one': '1', 'two': 2, 'six': '6'}, {'three': 3, 'four': 4})
# 对ChainMap  进行插入、更新和删除操作,只会作用于其中的一个字典。

4 collection.Counter       多重集合

就是两个字典键相同, 合并值, 如果值是数字类型就直接相加,字符串类型就直接拼接。

from collections import Counter


inventory = Counter()
loot = {'sword': 1, 'bread': 3, 'aki': 'de'}
inventory.update(loot)
print(inventory)    # Counter({'sword': 1, 'bread': 3, 'aki': 'de'})

more_loot = {'sword': 1, 'apple': 1, 'aki': 'sky'}
inventory.update(more_loot)
print(inventory)   # Counter({'sword': 2, 'bread': 3, 'aki': 'skyde', 'apple': 1})

 

元组类型

元组没啥说的,主要是下面这种写法,第一次见到过。

arr = 'one', 'twp', 'th'
print(arr)   # ('one', 'twp', 'th')

1 nametuple

没啥好说的,nametuple 和tuple 占用的空间是一样的, 是不可变的

from collections import namedtuple
from sys import getsizeof


p1 = namedtuple("Point", 'x y z')(1, 2, 3)    # 注意'x y z' 相当于【‘x', 'y', 'z'】 内部通过空格把字符串转成列表
p2 = (1, 2, 3)
print(getsizeof(p1))    # 72
print(getsizeof(p2))    # 72
from collections import namedtuple


Car = namedtuple('Car', 'color, mileage automatic')
car1 = Car('red', 123344, True)
print(car1)   # Car(color='red', mileage=123344, automatic=True)
print(car1.mileage)

2 typing.NameTuple   改进版的nametuple

它是3.6才加进来的, 和namedtuple 极为类似, 不过它是类的写法

from typing import NamedTuple


class Car(NamedTuple):
    color: str
    mileage: float
    automatic: bool


car1 = Car('red', 1234, True)
print(car1)           # Car(color='red', mileage=1234, automatic=True
print(car1.mileage)   # 1234
# car1.mileage = 555555   会报错, 因为是不可变对象

3 types.SimpleNamespace     花哨的属性访问

SimpleNamespace实例将其中的所有键都公开为类属性,因此访问属性时可以使用obj.key这样的点式语法。

from types import SimpleNamespace


car1 = SimpleNamespace(color='red', mileage='1234', automatic=True)
print(car1)   # namespace(automatic=True, color='red', mileage='1234')
print(car1.mileage)  # 1234
# 属性式可变的
car1.mileage = '666'
print(car1.mileage)

 

数组类型

列表我就不多BB了

1 array.array     基本类型数组

Python的arr模块占用的空间较小,用于存贮C语言风格的基本数据类型。使用array.array 类创建的数组是可变的,行为于列表相似。但有一个重要的区别,这种数组是单一类型的“数组数组”。就是只能存一种统一的类型,这个类型还要提前通过参数设定。最大的优点就是节省空间。

Type code   C Type             Minimum size in bytes 
'b'         signed integer     1 
'B'         unsigned integer   1 
'u'         Unicode character  2 (see note) 
'h'         signed integer     2 
'H'         unsigned integer   2 
'i'         signed integer     2 
'I'         unsigned integer   2 
'l'         signed integer     4 
'L'         unsigned integer   4 
'q'         signed integer     8 (see note) 
'Q'         unsigned integer   8 (see note) 
'f'         floating point     4 
'd'         floating point     8 
import array


arr = array.array('f', (1.0, 2.5, 2.0, 2.5))
print(arr[1])

 

2 bytes   含有单字节的不可变数组

bytes对象是单字节的不可变序列,单字节为0-255范围内的整数,从概念上讲,bytes与str对象类似,可认为是不可变的字节数组。bytes是不可变对象。

>>> arr = bytes((0, 1, 2, 3))
>>> arr
b'\x00\x01\x02\x03'
>>> arr[1]
1
>>> bytes((0, 300))     # 范围是0-255
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: bytes must be in range(0, 256)
>>> arr[1] = 55         # 不可变
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment

3 bytearray     含有单字节的可变数组

bytearray类型是可变整数序列,包含0-255,bytearray 和bytes极为类似, 不过它是可变的。

>>> arr = bytearray((0, 1, 2, 3))
>>> arr[1]
1
>>> arr
bytearray(b'\x00\x01\x02\x03')
>>> arr[1] = 23    # bytearray是可变的
>>> arr[1]
23
>>> del arr[1]     # 可以删除指定位置的元素
>>> arr
bytearray(b'\x00\x02\x03')

 

集合类型

set类型式可变的。set没啥好说的。

1 frozenset     不可变集合

可以用作字典的键, 也可以放在另一个集合中。普通的可变集合做不到这一点。

vowels = frozenset({'a', 'e', 'i', 'o', 'u'})
vowels.add('p')
# 会报错, 因为fronzenset是不可变集合

下面就有些nB了

d = {frozenset({1, 2, 3}): 'hello'}
print(d[frozenset({1, 2, 3})])

 

 

栈类型

1 列表

用列表的append, pop方法, 把列表维护成栈, 效率还是很高的, 因为尾加尾删时间复杂度都是O(1)

2 collections.deque

双端队列, 内部是双向链表, 就不多BB了。

3 queue.LifoQueue   不知道有啥用

这个就是个官方的队列, 名字也很通俗, 后进先出队列。

from queue import LifoQueue


s = LifoQueue()
s.put('eat')
s.put('sleep')
s.put('code')
print(s)  # <queue.LifoQueue object at 0x0000025F88981550>
print(s.get())   # code
print(s.get())   # sleep
print(s.get())   # eat
# print(s.get())   # 多get一个也不报错  因为阻塞了
# print(s.get_nowait())  # 不阻塞,不没有了, 立即终止程序


 

队列结构

1 列表和双端队列做成队列, 不多说了, 不过列表效率太TM低了。

2 queue.Queue  跟上面的LifoQueue 是一个样子

from queue import Queue


s = Queue()
s.put('eat')
s.put('sleep')
s.put('code')
print(s)  # <queue.LifoQueue object at 0x0000025F88981550>
print(s.get())   # code
print(s.get())   # sleep
print(s.get())   # eat
# print(s.get())   # 多get一个也不报错  因为阻塞了
# print(s.get_nowait())  # 不阻塞,不没有了, 立即终止程序

3  multiprocessing.Queue

共享作业队列,允许多个并发worker并行处理队列中元素,能绕过GIL的性能的限制

from multiprocessing import Queue

s = Queue()
s.put('eat')
s.put('sleep')
s.put('code')
print(s)  # <queue.LifoQueue object at 0x0000025F88981550>
print(s.get())   # code
print(s.get())   # sleep
print(s.get())   # eat
# print(s.get())   # 多get一个也不报错  因为阻塞了

4 queue.PriorityQueue     优先队列

内部是二叉树的小根堆实现的, 所以前面的数越小, 优先级越高。注意里面是元组

from queue import PriorityQueue


q = PriorityQueue()
q.put((2, 'code'))     # 注意内部是元组
q.put((1, 'eat'))
q.put((3, 'sleep'))

print(q.get_nowait())  # (1, 'eat')
print(q.get())        # (2, 'code')

也可以至指定元素,元素只能是数字或字符串,类型还必须统一

from queue import PriorityQueue


q = PriorityQueue()
q.put("fds")    
q.put("as")
q.put("sd")

print(q.get_nowait())   # as
print(q.get())          # fds

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值