第三章:数据类型

本文是Python通用编程系列教程,已全部更新完成,实现的目标是从零基础开始到精通Python编程语言。本教程不是对Python的内容进行泛泛而谈,而是精细化,深入化的讲解,共5个阶段,25章内容。所以,需要有耐心的学习,才能真正有所收获。虽不涉及任何框架的使用,但是会对操作系统和网络通信进行全局的讲解,甚至会对一些开源模块和服务器进行重写。学完之后,你所收获的不仅仅是精通一门Python编程语言,而且具备快速学习其他编程语言的能力,无障碍阅读所有Python源码的能力和对计算机与网络的全面认识。对于零基础的小白来说,是入门计算机领域并精通一门编程语言的绝佳教材。对于有一定Python基础的童鞋,相信这套教程会让你的水平更上一层楼。

一 数字类型

1. 数字类型 int和float

在第一章用户交互我们给大家介绍了一下基本的数据类型,这一章主要是介绍不同数据类型的使用方法和深入研究

数字类型即变量的值,如age=18,18则是我们保存的数据。
变量的是用来反映/保持状态以及状态变化的,毫无疑问针对不同的状态就应该用不同类型的数据去标识

数字类型只能存一个值,是不可变类型(不可变类型可以哈希,后面章节会讲解哈希)

#int整型
定义:age=10  # age=int(10)
用于标识:年龄,等级,身份证号,qq号,个数
#float浮点型
定义:salary=3.1 #salary=float(3.1)
用于标识:工资,身高,体重,

2. int类型常用的方法

# 常用操作+内置的方法
print(bin(3)) #十进制转成二进制,0b11
print(oct(8)) #十进制转成八进制,0o10
print(10) #10
print(hex(16)) #十进制转成十六进制,0x10

在进行用户交互程序的时候我们常用 .isdigit()这个判断用户输入是不是数字,来进行下一步操作,这样就避免了程序出错,但是需要注意的是用户输入的内容默认是字符串,判断一个字符串是否是数字,我们使用这个方法。

age = input(your age>>:)
if age.isdigit():
    age = int(age)
    age +=1 
print(age)

3. Python其他数字类型(了解)

#int(整型)
在32位机器上,整数的位数为32位,取值范围为-2**31~2**31-1,即-2147483648~2147483647
在64位系统上,整数的位数为64位,取值范围为-2**63~2**63-1,即-9223372036854775808~9223372036854775807
#long(长整型)
跟C语言不同,Python的长整数没有指定位宽,即:Python没有限制长整数数值的大小,但实际上由于机器内存有限,我们使用的长整数数值不可能无限大。
注意,自从Python2.2起,如果整数发生溢出,Python会自动将整数数据转换为长整数,所以如今在长整数数据后面不加字母L也不会导致严重后果了。
注意:在Python3里不再有long类型了,全都是int
>>> a= 2**64
>>> type(a)  #type()是查看数据类型的方法
<type 'long'>
>>> b = 2**60
>>> type(b)
<type 'int'>
#complex复数型
>>> x=1-2j
>>> x.imag
-2.0
>>> x.real
1.0

二 字符串类型

1. 字符串类型介绍

在python中,加了引号的字符就是字符串类型,用于标识:描述性的内容,如姓名,性别,国籍,种族,定义形式:

name='Albert' # name=str('Albert') 

字符串格式化:

name = input('请输入名字>>:')
print('你好,%s' % name)

2. 单引号,双引号和三引号的区别

#那单引号、双引号、多引号有什么区别呢? 让我大声告诉你,单双引号木有任何区别,只有下面这种情况 你需要考虑单双的配合
msg = "My name is Albert , I'm 18 years old!"
#多引号什么作用呢?作用就是多行字符串必须用多引号
msg = 
'''
今天我想写首小诗,
歌颂我的同桌,
你看他那乌黑的短发,
好像一只炸毛鸡。
'''
print(msg)
# 三引号里面写多行内容

3. 字符串的拼接

#数字可以进行加减乘除等运算,字符串呢?让我大声告诉你,也能?what ?是的,但只能进行"相加"和"相乘"运算。
>>> name='albert'
>>> age='18'
>>> name+age #相加其实就是简单拼接
'albert18'
>>> name*5 
'albertalbertalbertalbertalbert'
#注意1:
字符串1+字符串3,并不会在字符串1的基础上加字符串2,而是申请一个全新的内存空间存入字符串1和字符串3,相当字符串1与字符串3的空间被复制了一次,
#注意2:只能字符串加字符串,不能字符串加其他类型
字符串拼接(只能在字符串之间进行,且只能相加或相乘)

字符串类型只能存一个值,是不可变类型,可以哈希。

4. 字符串类型常用的方法

(1) 按照索引取值

字符串是不可变类型,并不能改变字符串的值,取值时最多可以有三个参数,分别是起始位置,结束为止和步长,可以正向取值,反向取值(起始位置大于结束位置或者没有起始位置与结束位置,步长为-1表示从最后一个开始,步长为负数)

hobbies = "music basketball"
print(hobbies[0])
print(hobbies[1])
print(hobbies[5])
print(hobbies[0:5])
print(hobbies[:5])
print(hobbies[0:5:2])
print(hobbies[0:5:-2])
print(hobbies[11:5:-2])
print(hobbies[-1])
print(hobbies[-2])

(2) 长度运算

print(len('name'))

(3) 成员运算

print('a' in 'Albert')
# False
print('a' in not 'Albert')
# True

(4) 移除空白

print('   name'.lstrip())  # 移除左边空白
print('name  '.rstrip())  # 移除右边空白
print('  name  '.strip())  # 移除两边空白

(5) 切分

print('n a me'.split(','))
print('n,a me'.split(','))
print('n,/a /me'.split('/',1)) # 数字表示切割次数,默认全部切割
print('n,a /me'.split('/'))
print('a|b|c'.rsplit('|',1)) # 从右边开始切割

(6) 组合

print('a'.join('1234'))
print('a'.join('bcde'))
tag = ' '
print(tag.join(['I', 'say', 'hello', 'world']))  # 可迭代对象必须都是字符串

(7) 替换

print('abc name id'.replace('a', 'card')) 
name = 'albert say :i have a dream,my name is albert'
# 注意此时name原来的值并没有改变,而是产生了一个替换之后新的值
print(name.replace('albert', 'Albert', 1))   

(8) 字符串其他操作

# find,rfind,index,rindex,count
name='albert say hello'
print(name.find('o',1,3))  # 顾头不顾尾,找不到则返回-1不会报错,找到了则显示索引
# print(name.index('e',2,4))  # 同上,但是找不到会报错
print(name.count('e',1,3))  # 顾头不顾尾,如果不指定范围则查找所有
# center,ljust,rjust,zfill
name='albert'
print(name.center(30,'-'))
print(name.ljust(30,'*'))
print(name.rjust(30,'*'))
print(name.zfill(50))  # 用0填充

# expandtabs
name='albert\thello'
print(name)
print(name.expandtabs(1))

# captalize,swapcase,title
print(name.capitalize())  # 首字母大写
print(name.swapcase())  # 大小写翻转
msg='albert say hi'
print(msg.title())  # 每个单词的首字母大写

# is数字系列
# 在python3中
num1=b'4'  # bytes
num2=u'4'  # unicode,python3中无需加u就是unicode
num3='四'  # 中文数字
num4='Ⅳ' #罗马数字

# isdigit:bytes,unicode
print(num1.isdigit())  # True
print(num2.isdigit())  # True
print(num3.isdigit())  # False
print(num4.isdigit())  # False

# isdecimal:uncicode
# bytes类型无isdecimal方法
print(num2.isdecimal())  # True
print(num3.isdecimal())  # False
print(num4.isdecimal())  # False

# isnumberic:unicode,中文数字,罗马数字
# bytes类型无isnumberic方法
print(num2.isnumeric())  # True
print(num3.isnumeric())  # True
print(num4.isnumeric())  # True

# 三者不能判断浮点数
num5='4.3'
print(num5.isdigit())
print(num5.isdecimal())
print(num5.isnumeric())

'''
总结:

    最常用的是isdigit,可以判断bytes和unicode类型,这也是最常见的数字应用场景

    如果要判断中文数字或罗马数字,则需要用到isnumeric
'''

# is其他
print('===>')
name='alb123ert'
print(name.isalnum())  # 字符串由字母或数字组成
print(name.isalpha())  # 字符串只由字母组成
print(name.isidentifier())
print(name.islower())
print(name.isupper())
print(name.isspace())
print(name.istitle())

三 列表

1. 列表类型基本介绍

在[]内用逗号分隔,可以存放n个任意类型的值,用于标识:存储多个值的情况,比如一个人有多个爱好,定义格式示例:

students=['albert','james','kd',] 
# 或者students=list(['albert','james','kd',]) 

列表可以存储多个值,是有序的,是可变类型,不可以哈希。

2. 列表类型常用的方法

(1) 添加元素

append方法 在列表最后追加元素

l1 = ['a', 'b', 'c', 'd', ]
l1.append('e')
print(l1)
print(l1.append('e'))
# 在队尾追加,没有返回值

# ['a', 'b', 'c', 'd', 'e']
# None

insert方法 在列表中插入元素

l1 = ['a', 'b', 'c', 'd', ]
l1.insert(3,'x') # 3 指定插入索引3这个位置,就是“d”,这个位置,把‘d’ 顶到了后面
print(l1)

# insert可以指定插入的位置

# ['a', 'b', 'c', 'x', 'd']

extend方法 在列表中同时插入多个元素,extend方法使用以及与append方法的区别
append是整体添加

l1 = [1, 2, 3, 4, 5, ]
l1.append([6, 7, 8, 9, ])
# l1.append(*[6, 7, 8, 9, ])  # 会报错
print(l1)
l1.extend([6, 7, 8, 9])
print(l1)

只能接收一个参数,如果出现打散的情况,还是会被识别成多个参数,因为程序执行执行是从左到右,从上倒下执行的,当出现时这个列表已经被打散了,因而,会被程序识别成被传入了多个参数。

extend是逐个添加

l1 = [1, 2, 3, 4, 5, ]
l1.extend([6, 7, 8, 9])
print(l1)
l1.extend('abc')
print(l1)
l1.extend('a')  # 也是可迭代对象
print(l1)
# l1.extend(1)  # 报错,不可迭代
print(l1)

extend在执行添加的时候,被传入的参数必须是可迭代对象,这样通过迭代就解决了同时传入多个参数的问题,如果你还不知道可迭代对象,放心,你很快就会知道的。<br />

(2) 删除元素

pop删除,有返回值,默认删除列表中最后一个,指定删除索引值

l1 = [1, 2, 3, 4, 5, 6, ]
print(l1.pop())  # 这个是有返回值的,因为这是一个可迭代类型和我们前面的extend一类
print(l1)
print(l1.pop(2))  # 2指定是列表中的索引值
print(l1)

remove 删除 没有返回值,没有默认值,指定被删除的元素

l1 = [1, 2, 3, 4, 5, 6, ]
print(l1.remove(2))  # 注意这个2 是真的2,不是索引值
# print(l1.remove())  # 报错
print(l1)

clear 删除 保留列表名称,清空里面的值

l1 = ['a', 'b', 'c', 'd', 'e', 'b', 'c']
l1.clear()
print(l1)

del 删除 通用删除 但是一般不用

l1 = [1, 2, 3, 4, 5, 6, ]
del l1[2]  # 按索引
print(l1)
l1 = [1, 2, 3, 4, 5, 6, ]
del l1  # 在内存中删除l1 相当于没有定义l1
# print(l1)  # 报错

(3) 更改元素

注意与insert插入的不同,都是以原来的为位置为参照,insert是挤开,本质是添加,而这里是替换

l1 = [1, 2, 3, ]
l1[2] = 4
print(l1)

(4) 查找元素

按照索引或者指定列表中的元素查找

l1 = ['a', 'b', 'c', 'd', 'e', 'b', 'c']
print(l1.index('a'))
print(l1.index('b',1,4))  # 两个数字分别对应起始位置和结束位置
print(l1[0:5])  # 按照索引取值和字符串的用法相同
print(l1[:5])
print(l1[0:5:2])
print(l1[:-1])
print(l1[:-2])
print(l1[5:1:-2])

把列表分段查找

l1 = ['a', 'b', 'c', 'd', 'e', 'b', 'c']
a = int(len(l1)/2)
print(l1[:a])  # 从中间位置开始,列出前面所有的元素
print(l1[a:])  # 从中间位置开始,列出后面所有的元素

使用enumerate对列表枚举

l1 = ['a', 'b', 'c', 'd', 'e']
for i, x in enumerate(l1, 100):  # 100指定枚举开始的数字
    print(i, x)

(5) 统计长度

print(len([1,2,3,4,]))

(6) 统计元素个数

print(['a','b'].count('a'))

(7) 排序
reverse 反序排序

l1 = ['a', 1, 'b', 'c', 'd', 'e', 'b', 'c']
l1.reverse()
print(l1)

sort 按照ascii码来进行排序

l1 = ['a', '1', 'b', 'c', 'd', 'e', 'b', 'A', 'Z', 'c']
l1.sort()
print(l1)
l1.sort(reverse=True)
print(l1)

(7) 复制列表

l1 = ['a', '1', 'b', 'c', 'd', 'e', 'b', 'A', 'Z', 'c']
print(l1.copy())

(8) Python中的赋值,浅拷贝与深拷贝区别
赋值
对于复制的操作,最简单的就是赋值,指的是新建一个对象的引用,新建目标对象与原来的目标对象指向同一个内存地址,因而,始终保持一致。

list1 = [1, 2, 3, 4, 5, [6, 7, 8, ]]
list2 = list1
list1.append(9)
print(list1)
print(list2)
list1[5][0] = 10
print(list1)
print(list2)
list1[5] = 10
print(list1)
print(list2)

浅拷贝
浅拷贝顾名思义就是拷贝的比较浅,我们可以把赋值认为是新建了一个对象的引用,把原来被对象内存空间的数据指向新的变量,这时同一块内存空间指向两个变量。浅拷贝与赋值不同,既然是拷贝,那么就是要开辟一块新的内存空间,复制的是原来被拷贝对象内多个元素对象的引用,有几个元素对象就赋值几个元素对象的引用。因此,被浅拷贝对象内的元素改变,会引起浅拷贝对象内元素的改变;被拷贝对象添加元素,拷贝对象不再添加元素(因为没有一个新的引用);被拷贝对象删除元素,拷贝对象也删除元素(元素都已经删了,虽然引用存在,但是并没有什么卵用)。

import copy


list1 = [1, 2, 3, 4, 5, [6, 7, 8, ]]
list2 = copy.copy(list1)
print(list1)
print(list2)

list1[5].append(9)
print(list1)
print(list2)

list1.append(6)
print(list1)
print(list2)

list1.pop()
print(list1)
print(list2)

深拷贝
深拷贝其实与浅拷贝有本质的区别,它不会复制任何的引用,对象内的所有元素,子元素,孙子元素,重孙元素,曾孙元素的数据都是由复制而来。它的实现原理就是递归,只要任意元素内仍然有子元素,就会复制子元素的数据放到新的内存地址。既然这样,在使用深拷贝后,被拷贝对象的改变,不会引起拷贝对象的任何改变。

import copy


list1 = [1, 2, 3, 4, 5, [6, 7, 8, ]]
list2 = copy.deepcopy(list1)
print(list1)
print(list2)

list1[5].append(9)
print(list1)
print(list2)

list1.append(6)
print(list1)
print(list2)

list1.pop()
print(list1)
print(list2)

复制与深浅拷贝总结:

  • 赋值:新建一个原来对象内存地址的引用,不开辟新的内存空间;
  • 浅拷贝:新建多个原来对象内一级子元素内存地址的引用,开辟新的内存空间;
  • 深拷贝:复制原来对象内的所有N级子元素的数据,开辟新的内存空间。

四 元组

与列表类型相比,非常类似只不过[]换成(),作用:用于存储多个值,对比列表来说,元组不可变(是可以当做字典的key的),不可更改,主要是用来读。

age=(11,22,33,44,55)
# 本质age=tuple((11,22,33,44,55))

元组可以存储多个值,是有序的,是不可变类型,可以哈希。元组常用的方法,请参考列表常用方法,需要注意的是,元组只能取值,而不能改变元组的值

五 字典

1. 字典类型基本介绍

字典用于存放一个人的信息:姓名,性别,年龄,很明显是多个值,既然是存多个值,我们完全可以基于刚刚学习的列表去存放,如下:

# 既然如此,我们我们为何还要用字典?
info=['albert','male',18]
# 定义列表的目的不单单是为了存,还要考虑取值,如果我想取出这个人的年龄,可以用
info[2]
# 但这是基于我们已经知道在第3个位置存放的是年龄的前提下,我们才知道索引2对应的是年龄,即:
#      # name, sex, age
info=['albert','male',18]
"""
而这完全只是一种假设,并没有真正意义上规定第三个位置存放的是年龄,
于是我们需要寻求一种,即可以存放多个任意类型的值,又可以硬性规定值的映射关系的类型,
比如key=value,这就用到了字典
"""

字典用于标识存储多个值的情况,每个值都有唯一一个对应的key,可以更为方便高效地取值,字典的定义格式如下:

# 在{}内用逗号分隔,可以存放多个key:value的值,key一般是字符串,value可以是任意类型
info={'name':'albert','age':18,'sex':18} 
# info=dict({'name':'albert','age':18,'sex':18})

字典可以存储多个值,是无序的,是可变类型,不可哈希。

2. 字典类型常用的方法

(1) 增加元素

通过键值对的方式

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male'
}
l1['hobbies'] = "music"
print(l1)

用fromkeys构造一个字典

"""
第一个参数迭代循环的字典的key,第二个参数表示value,
可以多个key循环对应这个value,也可以只有一个key,也可以没有value
"""
a = l1.fromkeys(l1,'I am Albert') 
print(a)

b = dict.fromkeys('name')  # 必须有一个可迭代类型,作为字典的key
print(b)

b = dict.fromkeys('e')  # 也可以迭代
print(b)
# b = dict.fromkeys(1) #报错 数字类型不可迭代

b = dict.fromkeys([1,2,3,])
print(b)

(2) 删除元素

del 通过字典的key删除

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male'
}

del l1['name']
print(l1)

pop 或者popitem删除

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male'
}

res = l1.pop('name')  # 删除指定key的value,并拿到一个返回值
print(res)
print(l1)

res2 = l1.popitem()  # 随机返回并删除字典中的一对键和值(一般删除末尾对)。
# 如果字典已经为空,却调用了此方法,就报出KeyError异常。
print(res2)
print(l1)

(3) 更改元素

通过键值对的方式

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male','3':3,
}

l1['name'] = '马一特'
print(l1)

通过setdefault 或者update操作,两者使用和区别如下:
setdefault只添加不修改

d1 = {
    'name': 'albert',
    'age': 18,
}

d1.setdefault('name', 'Albert')
d1.setdefault('gender', 'male')
print(d1)

update既添加也修改

d1 = {
    'name': 'albert',
    'age': 18,
}

d1.update({'name': 'Albert', 'gender': 'male'})  # 注意传参方式的不同
print(d1)

(4) 查找元素

通过键值对查找

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male'
}

a = l1['name']
print(a)

通过get方法查找

l1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male'
}

a = l1.get('hobbies')   # 找不到不报错
print(a)

通过enumerate 枚举

d1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male',
    '3':3,
}

for a in enumerate(d1):
    print(a)

通过.keys(),.values(),.items()等方法

d1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male',
    '3':3,
}

a = d1.keys()
print(a)
print(list(a)[0])

a = d1.values()
print(a)
print(list(a)[0])

a = d1.items()
print(a)
print(list(a)[0])

通过for循环遍历

d1 = {
    'name': 'albert',
    'age': 18,
    'gender': 'male',
    '3':3,
}

for k,v in d1.items():
    print(k,v)

(5) 成员运算与长度运算

参考列表的运算方法,成员运算的依据是字典的key,而不是value,长度运算都可以作为参考的依据

六 集合类型

花括号内,多个元素用逗号分割,用来存储多个值,并且是无序的,那么这多个值不能用来取值,但是我们可以使用它来进行去重和关系运算。

# 集合的元素遵循三个原则:
             1: 每个元素必须是不可变类型(可作为字典的key)
             2: 没有重复的元素
             3: 无序
# 注意集合的目的是将不同的值存放到一起,不同的集合间用来做关系运算,无需纠结于集合中单个值

集合类型可以存多个值,是无序的,是可变类型,不可以哈希。<br />关系运算练习

有如下两个集合,piano是报名钢琴课程的学员名字集合,violin是报名小提琴课程的学员名字集合
  piano={'albert','孙悟空','周星驰','朱茵','林志玲'}
  violin={'猪八戒','郭德纲','林忆莲','周星驰'}
  1. 求出即报名钢琴又报名小提琴课程的学员名字集合
  2. 求出所有报名的学生名字集合
  3. 求出只报名钢琴课程的学员名字
  4. 求出没有同时这两门课程的学员名字集合

参考答案

# 求出即报名钢琴又报名小提琴课程的学员名字集合
print(piano & violin)
# 求出所有报名的学生名字集合
print(piano | violin)
# 求出只报名钢琴课程的学员名字
print(piano - violin)
# 求出没有同时这两门课程的学员名字集合
print(piano ^ violin)

七 布尔类型

计算机俗称电脑,即我们编写程序让计算机运行时,应该是让计算机无限接近人脑,或者说人脑能干什么,计算机就应该能干什么,人脑的主要作用是数据运行与逻辑运算,此处的布尔类型就模拟人的逻辑运行,即判断一个条件成立时,用True标识,不成立则用False标识。

#布尔值,一个True一个False
>>> a=3
>>> b=5
>>> a > b #不成立就是False,即假
False
>>> a < b #成立就是True, 即真
True
# 接下来就可以根据条件结果来干不同的事情了:
if a > b:
   print(a is bigger than b )
else:
   print(a is smaller than b )
# 上面是伪代码,但意味着,计算机已经可以像人脑一样根据判断结果不同,来执行不同的动作。

布尔类型的重点知识

#所有数据类型都自带布尔值
1、None,0,空(空字符串,空列表,空字典等)三种情况下布尔值为False
2、其余均为真

可变类型与不可变类型(重点)

# 1.可变类型:在id不变的情况下,value可以变,则称为可变类型,如列表,字典
# 2. 不可变类型:value一旦改变,id也改变,则称为不可变类型(id变,意味着创建了新的内存空间)

八 collections容器数据类型

1. namedtuple 命名元组

from collections import namedtuple
# 创建一个命名元组对象
point = namedtuple('p', ['x', 'y'])  # p代表名称,"x"和"y"为内容
p = point(1, 2)
print(p)
print(p.x)  # 1
print(p.y)  # 2

2. deque 超级列表

from collections import deque
# 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
d = deque('abcd')
for i in d:
    print(i)
print(d[0])
print(d[1])
d.append('e')  # 从右边加入
print(d)
d.appendleft('x')  # 从左边加入
print(d)
d.pop()  # 从右侧弹出
print(d)
d.popleft()  # 从左侧弹出
print(d)
deque(reversed(d))  # 反转顺序
print(d)
# d = list(d)  # 转化成list
# d = list(reversed(d))
# print(d)
d.extend('xyz')  # 从右侧添加
print(d)
d.extendleft('nba')  # 从左侧添加
print(d)
d.rotate(1)  # 把最右边的元素挪到最左边
print(d)
d.rotate(-1)  # 把最左边的元素挪到最右边
print(d)
d.clear()  # 清空
# d.pop()  # 报错

3. ChainMap 链映射

from collections import ChainMap
"""
一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。
它通常比创建一个新字典和多次调用 update() 要快很多。
这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用。
"""
# 链映射的用法
dict1 = {'name': 'Albert', 'age': 18}
dict2 = {'weight': 65, 'height': 180}
res = list(ChainMap(dict1, dict2))
print(res)

4. Counter 计数字典

from collections import Counter
# 计数
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
    cnt[word] += 1
print(cnt)
# Counter({'blue': 3, 'red': 2, 'green': 1})
# 数学运算
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
print(c + d)  # 相同的部分相加
# Counter({'a': 4, 'b': 3})
print(c - d)  # 相同的部分相减
# Counter({'a': 2})
print(c & d)  # 相同的部分取最小
# Counter({'a': 1, 'b': 1})
print(c | d)  # 相同的部分取最大
# Counter({'a': 3, 'b': 2})

Collections容器类型一共有9种,除了上面介绍的4种之外还有OrderedDict,defaultdict,UserDict,UserList,UserString,他们的用法不是完全相同,但是使用起来并不复杂,更多Collections容器类型数据结构详见官方文档:Collections容器数据类型

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容