Python 核心数据类型
第5版第四章
引言:这些核心数据类型是在Python语言中高效创建的。所有人都该了解他们。
Python 核心数据类型
这部分我只会给出一些便于查询的表格和简介,更多内容请查看之后的章节。
内置对象
对象类型 | 例子 常量/创建 |
---|---|
数字 | 1234, 3.1415, 3+4j, 0b111, Decimal(), Fraction() |
字符串 | 'spam', "guido's", b'a\xolc', u'sp\xc4m' |
列表 | [1, [2, 'three'], 4], list(range(10)) |
字典 | {'food': 'spam', 'taste': 'yum'}, dict(hours=10) |
元组 | (1, 'spam', 4, 'U'), tuple('spam'), namedtuple |
文件 | open('eggs.txt'), open(r'C:\ham.bin', 'wb') |
集合 | set('abc'), |
其他类型 | 类型、None、布尔型 |
编程单元类型 | 函数、模块、类 |
与实现相关的类型 | 编译的代码,堆栈跟踪 |
变量
message = "Hello World"
print(message)
Hello World
这里message为一个变量,与字符串“Hello World”关联在一起。
- 变量名只能包含字母、数字和下划线,变量名可以字母或下划线开头,但不能以数字开头。
- 变量名不能包含空格,但可以使用下划线分隔其中单词。
- 不能将Python关键字和函数名用作函数名。
- 变量名应既简短又具有描述性。
- 慎用小写字母l和大写字母O。
Python中有三个主要类型(以及操作)的分类:
- 数字(整数、浮点数、二进制、分数等)
支持加法和乘法等。 - 序列(字符串、列表、元组)
支持索引、分片和合并等。 - 映射(字典)
支持通过键的索引等。
Python中主要核心类型划分为如下两类:
- 不可变类型:数字、字符串、元组、不可变集合
- 可变类型:列表、字典、可变集合
下面我将简短介绍将会遇到的一些Python的有用特性,带你先行了解一下,在Python学习过程中,会遇到哪些出色的功能
数字类型
Python中的数字类型支持一般的数学运算.下面是对照表
符号 | 示意 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
** | 幂运算 |
见下面的示例 |
123+222
345
1.5*4
6.0
2**100
1267650600228229401496703205376
注意这个浮点数示例,python的浮点数在显示上存在着 全精度
和 用户友好
两种形式。
当你把浮点数用在运算上时,它是全精度的。(3.1415*2
=6.2830000000000004)
而当你把它print
出来就又变为用户友好的了(自动省略了靠后位的数值)
这是由计算机存储浮点数的方式所决定的。已经超过了本门课程的涉猎范围。
print(3.1415*2)
6.283
序列操作
字符串是由单个字符的串
组成的序列,
其他更一般的序列还包括列表和元组(后面章节介绍)
字符串支持序列相关的操作。
例如反向索引、切片、求字符串长度、数组下标操作等等
基本操作
S = 'Spam'
len(S)
4
S[0]
'S'
S[1]
'p'
这里涉及到了两个知识点
- 如何把字符串赋值给变量
S
- Python的变量不需要提前声明,当给一个变量赋值的时候就创建了它
在Python中,可以给一个变量赋值任何类型的对象。并且当变量出现在表达式中时,会用它的值去替换它本身。
- 在使用一个变量的值之前必须对其赋值。
- 我们需要把一个对象的值赋值给一个变量以便保存它供随后使用
反向索引
所有序列对象,在Python中都支持反向索引的特性。
具体来说,就是索引从序列的最后一个元素开始计算。
S[-1]
'm'
S[-2]
'a'
S[-3]
'p'
下面的两个操作是等效的。
S[-1]
'm'
S[len(S)-1]
'm'
但要注意,后一种写法是危险的,它容易数组下标越界.
S[len(S)]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-14-934aa1daad62> in <module>
----> 1 S[len(S)]
IndexError: string index out of range
S[len(S)-1]
切片操作
Python的序列支持切片操作。
一般形式为:X[I:J]
表示在X中,从偏移量(下标)I开始,直到偏移量(下标)为J-1的内容。
结果是返回一个新的对象。
例如下面的代码
S
S[1:3]
在字符串S中,从偏移1到2(从1到3-1)的所有字符作为一个新的字符串。
在一个分片中,左边界默认为0,右边界默认为分片序列的长度。所以有下面的常用用法:
S[1:]
S
S[0:3]
S[:-1]
S[:]
字符串的拼接和重复
Python的字符串支持使用加号进行拼接
S
S+'xyz'
这里的加号,实际上是Python的多态性。
多态的特性使得Python代码带来了很大的简洁性和灵活性。
字符串支持重复操作:
S
S*8
不可变性
Python中的字符串具有不可变性。这意味着所有对字符串进行拼接、重复、分片的操作,本质上都是生成了一个新的字符串对象。
- 字符串具有不可变性:字符串在创建过后不能在原位置(in place)改变。
- 你永远不能覆盖不可变对象的值。
但是你完全可以建立一个新的字符串对象,并用同一个变量名(如变量S)对其赋值
S
S[0] = 'z' # 不可变对象不能呗改变
S='z'+S[1:] # 但我们可以制造一个新的对象赋值给它
S
- 不可变对象:数字、字符串、元组
- 可变对象:列表、字典、集合
在原位置改变基于文本的数据
虽然字符串是不可变对象,但有变通的方法。
在过去,你可以将它扩展成一个由独立字符构成的列表,这样就可以不加入其他字符的情况下将它重新拼接起来。
S='shrubbery'
L=list(S)
L
L[1]='c'
''.join(L)
在Python3中,可以使用新增的bytearray类型。
B=bytearray(b'spam')
B.extend(b'eggs')
B
B.decode()
- bytearray支持文本的原位置转换,但仅仅用于字符编码至多8位宽(例如ASCII)的文本。其他所有的字符串依然是不可变的。
bytearray具有不可变的字节字符串特性,即b'…'的语法,它在Python3.X是必须的,而在Python2.X则是可选的
bytearray还融合了可变列表的特性(可变列表用[]
编写和显示)
这部分内容将放在Unicode中深入理解。
字符串的独有方法
find 和replace
字符串的find方法是一个基本的子字符串查找的操作,
它将返回一个传入子字符串的偏移量,没有找到的情况下返回 -1
S='Spam'
S.find('pa')
S
字符串的replace方法会对全局进行搜索和替换
S.replace('pa',"xyz")
S
这两种操作都依赖于被调用的对象,且都针对这些被调用的对象进行
split、upper、isIt()方法
split方法可以根据指定的分割符来拆分子字符串
line='aaa,bb,ccccc,dd'
line.split(',')
S='spam'
S.upper()
S.isalpha() # 是否是字母
S.isdigit() # 是否是数字
line='aaa,bb,ccccc,dd\n'
line.rstrip() # 去除右侧的空白字符
line.rstrip().split(',') # 连用两种方法处理
line.split(',').rstrip() # 字符串处理成list后就不可使用字符串的独有方法
格式化输出
现在Python常用的三种格式化输出:
'%s, eggs, and %s'%('spam','SPAM!') # all Python ver.
'{0}, eggs, and {1}'.format('spam','SPAM!') # (2.6+,3.0+)
'{}, eggs, and {}'.format('spam','SPAM!') # (2.7+,3.1+)
这丰富的字符串格式化输出形式,对于打印输出格式化数值报告十分重要:
'{:,.2f}'.format(296999.2567)
'%.2f|%+05d'%(3.14159,-42)
- Python的工具库是呈现层级分布的,
- 可作用于多种类型的通用操作是以内置函数或者表达式的形式出现的(如len(X),
X[0]
) - 特定类型可以的操作是以方法调用形式出现的(如'hello'.upper())
帮助命令dir
使用内置函数dir来列出,在调用者作用域内,形式参数的默认值。
dir(S)
然后将其传递给函数help()
help(S.replace)
help(dir(S))
help(S)
字符串编程的奇淫技巧
字符串还支持使用反谢谢转义序列来表现特殊的字符,如换行符、tab
S='A\nN\tC'
S
len(S)
ord('\n') # 查看对应的ASCII码,换行符在ASCII码中编号为10
S='A\0N\0C' # '\0'是二进制0字节符号,不是终止符
S
len(S)
Python的单引号与双引号作用相同。并且允许字符串被包括在单引号或者双引号中。
Python还允许在三个引号(无论单引号还是双引号)中包括多行字符串字面量。
这会在每一行的末尾增加换行符
msg="""
aaa
bb'''bbbBBBbbbb"bbbbbb""bb'bb
cccccccccccccccccc
"""
msg
Python还支持原始(raw)字符串字面量,即去掉反斜线转义机制。这样的字符串字面量用字母'r'开头。
用来表示Windows下的文件路径时,十分有用。
r'C:\text\new'
Unicode字符串
这部分内容涉及到国际化字符文本处理。会在之后章节专门讲解。
模式匹配
Python的模式匹配,需要使用一个名为re的包来实现
import re
match = re.match('hello[ \t]*(.*)world','hello Python world')
match.group(1) # 正则表达式的内容 这里$1代表(.*)
re.split('[/:]','/usr/home/:lumberjack') # 还支持分片操作等其他复杂操作
列表
列表是Python提供的最通用的序列,它是可变的。
与C语言不同的是,列表会进行边界检查
L=[123,'spam','NI']
L
[123, 'spam', 'NI']
L[99]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-16-456cf771d009> in <module>
----> 1 L[99]
IndexError: list index out of range
L[99]=1
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-17-29cb710440ca> in <module>
----> 1 L[99]=1
IndexError: list assignment index out of range
想要扩充可变列表,请使用append等方法。
嵌套
Python的核心数据类型之间,支持任意的嵌套。这是十分优秀的特性。在处理跨设备数据传输时,会经常使用到这个特性。
M={
"name" : {
"first" : "anna",
"last" : "haha"
},
"add":{
"city" : "foshan",
"town" : "shanshui"
}
}
M
{'name': {'first': 'anna', 'last': 'haha'},
'add': {'city': 'foshan', 'town': 'shanshui'}}
martix=[
[1,2,3],
[4,5,6],
[7,8,9]
]
martix
[1, 2, 3], [4, 5, 6], [7, 8, 9](1, 2, 3], [4, 5, 6], [7, 8, 9)
martix[1]
[4, 5, 6]
martix[1][2]
6
推导
处理序列的操作和列表的方法中,Python支持列表推导表达式
.
从而提供了一种处理像矩阵这样结构的工具。
col2=[row[1] for row in martix]
col2
[2, 5, 8]
martix
[1, 2, 3], [4, 5, 6], [7, 8, 9](1, 2, 3], [4, 5, 6], [7, 8, 9)
[row[1]**2 for row in martix]
[4, 25, 64]
[row[1]**2 for row in martix if row[1]%2 == 0]
[4, 64]
diag=[martix[i][i] for i in [0,1,2]] # 对角线元素
diag
[1, 5, 9]
doubles=[c*2 for c in 'spam'] # 处理字符串内元素
doubles
['ss', 'pp', 'aa', 'mm']
# list操作
list(range(4))
[0, 1, 2, 3]
list(range(-6,7,2)) # 从-6开始,打印7个元素,步长为2
[-6, -4, -2, 0, 2, 4, 6]
# 多值处理
[[x**2,x**3] for x in range(4)]
[0, 0], [1, 1], [4, 8], [9, 27](0, 0], [1, 1], [4, 8], [9, 27)
[[x/2,x**2,x**3] for x in range(-6,7,2) if x>0] # 增加过滤器 "if"
[1.0, 4, 8], [2.0, 16, 64], [3.0, 36, 216](1.0, 4, 8], [2.0, 16, 64], [3.0, 36, 216)
# Python 3.3+ 列表推导可以用来创建生成器
G=(sum(row) for row in martix) # 生成器
next(G)
6
next(G)
15
next(G)
24
list(sum(row) for row in martix)
[6, 15, 24]
Python2.x中,使用map也可以实现类似功能
list(map(sum,martix))
[6, 15, 24]
在Python2.7和3.X中,推导语法还可以用来创建集合和字典
{sum(row) for row in martix} # 集合
{6, 15, 24}
{i:sum(martix[i]) for i in range(3)} # 字典
{0: 6, 1: 15, 2: 24}
总结: 在Python2.7和3.X中,列表,集合,字典和生成器都可以用推导来创建
[sum(row) for row in martix] # 列表list
[6, 15, 24]
{sum(row) for row in martix} # 集合
{6, 15, 24}
{i:sum(martix[i]) for i in range(3)} # 字典
{0: 6, 1: 15, 2: 24}
G=(sum(row) for row in martix) # 生成器
for i in range(3):
print(next(G))
6
15
24
字典 dict
Python中的字典不是序列,它本质是一种映射(mapping),即map
字典是一个其他对象的集合,通过键值对的方式存储对象(<key,value>
)
字典是无序的,它只是简单的将key和值对应起来,相互映射。
字典是可变的。
{i:sum(martix[i]) for i in range(3)} # 字典
{0: 6, 1: 15, 2: 24}
映射操作
前文说到,字典是一种映射,这里举例说明它的特性:
D={'food':'spam','quantity':4,'color':'pink'}
D
{'food': 'spam', 'quantity': 4, 'color': 'pink'}
D["food"] #通过key查找对应的value
'spam'
D["quantity"] +=1 # 字典的可变性
D
{'food': 'spam', 'quantity': 5, 'color': 'pink'}
创建字典的流程
D={}
D['name'] = 'Bob'
D['job'] ='dev'
D['age'] =40
D
{'name': 'Bob', 'job': 'dev', 'age': 40}
print(D['name'])
Bob
你还可以使用zip函数完成等价的操作
bob1 = dict(name='Bob',job='dev',age=40)
bob1
{'name': 'Bob', 'job': 'dev', 'age': 40}
bob2= dict(zip(['name','job','age'],['Bob','dev',40]))
bob2
{'name': 'Bob', 'job': 'dev', 'age': 40}
字典与嵌套
字典常常与嵌套配合,完成数据的格式化工作,例如编写一个json格式文本,不过最后将文本转换成json对象时一般比较繁琐。
垃圾回收 GC
Python具有自动垃圾回收机制(GC),例如:
bob2=1 # 这时之前的对象dict(zip(['name','job','age'],['Bob','dev',40]))会被回收掉,它被赋予一个新值 1
bob2
1
测试键是否存在:if测试
我们可以用if语句来测试一个键是否在字典内。
迭代和优化
Python的对象只要遵守迭代协议,就认为它是可迭代的。
迭代协议:在响应next之前先用一个对象对内置函数iter
做出反应,并在结束时触发一个异常。
任何一个从左到右扫描一个对象的Python工具都满足迭代协议。所以它们都是可迭代的,例如字典是可迭代的,我们就可以用next来返回后续的键。生成器也是可迭代的。
元组 tuple
元组对象(tuple,发音为"toople"或者"tuhple")
元组是序列,但它是不可变的。与字符串类似
在功能上,元组被用来表示确定元素的集合,类似于Java中的enum
语法上,元组通常被编写在圆括号中而不是方括号中。它支持任意类型、任意嵌套。还支持常见的序列操作。
T=(1,2,3,4)
len(T)
4
T+(5,6)
(1, 2, 3, 4, 5, 6)
T
(1, 2, 3, 4)
T[0]
1
Python2.6+和3.0+后,元组有两个专有的可调用方法。
T.index(4)
3
T.count(4)
1
元组是不可变的,它一经创建就不能再改变。
T[0]=2
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-044687bb86e2> in <module>
----> 1 T[0]=2
TypeError: 'tuple' object does not support item assignment
只含一个元素的元组需要一个逗号结尾。
新建一个元组
T=(2,)+T[1:]
T
(2, 2, 3, 4)
元组是不可变的,所以虽然它支持任意的嵌套,但不能增长或者缩短。
T='spam',3.0,[11,22,33]
T[1]
3.0
T[2]
[11, 22, 33]
T[2][1]
22
T.append(4) # 'tuple' object has no attribute 'append'
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-14-6d45fc78ad1f> in <module>
----> 1 T.append(4)
AttributeError: 'tuple' object has no attribute 'append'
元组是不可变的。在实际运用中,它经常和Java中的enum一样用法,使用在大型项目中。
元组提供一个确定元素的集合,并且提供了完整性约束。
文件
Python支持对文件的读写操作,使用r
w
r+
等控制字符
f=open('dataTest.txt','w')
f.write('hello\n')
6
f.write('world\n')
6
f.close() # 关闭磁盘的输出缓冲区
f=open('dataTest.txt') # 默认使用 read-only 'r'
text=f.read()
text
'hello\nworld\n'
print(text)
hello
world
text.split()
['hello', 'world']
在Python中,读取一个文件的最好方式是不读它,而是使用文件提供的迭代器(iterator),在for循环或者其他上下文中自动逐行读取:
for line in open('dataTest.txt'):
print(line)
hello
world
dir(f)
['_CHUNK_SIZE',
'__class__',
'__del__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__enter__',
'__eq__',
'__exit__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__lt__',
'__ne__',
'__new__',
'__next__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'_checkClosed',
'_checkReadable',
'_checkSeekable',
'_checkWritable',
'_finalizing',
'buffer',
'close',
'closed',
'detach',
'encoding',
'errors',
'fileno',
'flush',
'isatty',
'line_buffering',
'mode',
'name',
'newlines',
'read',
'readable',
'readline',
'readlines',
'reconfigure',
'seek',
'seekable',
'tell',
'truncate',
'writable',
'write',
'write_through',
'writelines']
help(f.seek)
Help on built-in function seek:
seek(cookie, whence=0, /) method of _io.TextIOWrapper instance
Change stream position.
Change the stream position to the given byte offset. The offset is
interpreted relative to the position indicated by whence. Values
for whence are:
* 0 -- start of stream (the default); offset should be zero or positive
* 1 -- current stream position; offset may be negative
* 2 -- end of stream; offset is usually negative
Return the new absolute position.
集合
集合不是映射也不是序列,它是不可变的对象的无序集合
X=set('sapam')
Y={'h','a','m'}
X,Y
({'a', 'm', 'p', 's'}, {'a', 'h', 'm'})
X&Y
{'a', 'm'}
集合常被用做过滤重复对象,分离集合间差异,以及进行非顺序的等价判断等任务
list(set([1,2,1,3,1]))
[1, 2, 3]
set('spam')-set('ham')
{'p', 's'}
set('spam')==set('asmp')
True
集合还支持in函数的成员测试操作
'p' in set('spam') ,'p' in 'spam', 'ham' in ['eggs','spam','ham']
(True, True, True)
其他数值类型
Python还新增了一些新的数值类型,十进制数、分数。 它们被用来解决浮点数的局限性和内在的不确定性。
type函数
内置函数type能够告知其他对象类型的对象。在Python3.X中,这有些改变。因为Python3.X中的类型(type)已经和类(class)合并起来了
L=[1,2,3,4]
type(L)
list
type(type(L))
type
type函数可以用来作为代码的类型检查。但在Python中并不推荐这么做,因为这破坏了Python的代码类型灵活转换的特性。
应当只在必要的时候,使用type函数检查类型。
类
Python的类中,self关键字实际上只是约定俗成标准,你大可使用类似this这类词汇替换它
class Worker:
def __init__(self,name,pay):
self.name=name
self.pay=pay
def getLastname(self):
return self.name.split(".")[-1]
worker=Worker('张三.wang.san',30)
print(worker.getLastname())
san