目录
为什么使用内置类型
Python的核心数据类型
1.数字
2.字符串
2.1序列的 *** 作
2.1.1位置顺序
2.1.2分片 *** 作
2.1.3使用加号进行合并
2.2不可变性
2.3类型特定的方法
2.4寻求帮助
2.5编写字符串的其他方法
2.6模式匹配
3.列表
3.1序列 *** 作
3.2类型特定的 *** 作
3.3边界检测
3.4嵌套
3.5列表解析
4.字典
4.1映射 *** 作
4.2重坊嵌套
4.3键的排序:for循环
4.4迭代和优化
4.5不存在的键:if测试
5.元组
为什么要用元组
6.文件
其他文件类工具
7.其他核心类型
7.1如何破坏代码的灵活性
7.2用户定义的类
7.3剩余的内容
本章习题:
Python程序可以分解为模块、语句、表达式以及对象,如下所示:
- 程序由模块组成。
- 模块包含语句。
- 语句包含表达式。
- 表达式建立并处理对象。
- 内置对象使程序更容易编写。
- 内置对象是扩展的组件。
- 内置对象往往比定制的数据结构更有效率。
- 内置对象是语言的标准的一部分。
换句话说,内置对象类型不仅使编程更加简单,而且也更强大、更高效。
Python的核心数据类型对象类型 | 例子 常量/创建 |
数字 | 1234,3.1415,3+4j,Demical,Fraction |
字符串 | 'span',"guido's" |
列表 | [1,[2,three],4] |
字典 | {'food':'span','taste':'yum'} |
元组 | (1,'span',4,'u') |
文件 | myfile = open('eggs','r') |
集合 | set('abc),{'a','b','c'} |
其他类型 | 类型、none、布尔型 |
编程单元类型 | 函数、模块、类 |
与实现相关的类型 | 编译的代码堆栈跟踪 |
Python的核心对象集合包括常规的类型:整数、浮点数以及更为少见的类型(有虚部的复数、固定精度的十进制数、带分子和分母的有理分数以及集合等)
- Python中的数字支持一般的数学运算,+,-,*,/,**(乘方)
- 和Python一起分发的还有一些常用的数学模块。模块只不过是我们导入以供使用的一些额外的工具包。
import math print(math.pi) #3.141592653589793 print(math.sqrt(85)) #9.219544457292887
- Python的math模块包含更为高级是数学工具,如函数,二random模块可以最为随机数字的生成器和随机选择器。
import random print(random.random()) #0.2118188853750318 print(random.choice([1, 2, 3, 4])) #4
- Python中还包含了更为少见的类型(有虚部的复数、固定精度的十进制数、带分子和分母的有理分数以及集合等)
字符串是用来记录文本信息的,它们作为Python中的序列,序列中的元素包含了从左到右的顺序——序列中的元素根据它们的相对位置进行存储和读取。从严格意义上,字符串是单个字符的字符串的序列,其他类型的序列还包括列表和元组。
2.1序列的 *** 作 2.1.1位置顺序作为序列,字符串支持假设其中各个元素包含位置顺序的 *** 作。
在Python中,(正向)索引(从左边开始)是按照从最前面的偏移量进行编码的,即从0开始,第一项索引为0,第二项索引为1,以此类推。
Python还支持反向索引(从右边开始计算)
s = "span"
l = len(s) #4
v0 = s[0] #s,the first item in s from the left
v1 = s[1] #p,the second item in s from the left
v2 = s[2] #a,the third item in s from the left
u1 = s[-1] #n, the first item in s from the right
u2 = s[-2] #a, the second item in s from the right
2.1.2分片 *** 作
序列也支持所谓的分片 *** 作(slice),这是一种一步就能提取整个分片的方法。
X[I:J]表示:“取出在X中从偏移量为I,直到但不包括偏移量为J的内容”。结果返回一个新的对象。
s = "Spanish"
print(s[1:3]) #pa
在一个分片中,左边界默认为0,并且右边界默认为分片序列的长度。
s = "Span"
v1 = s[1:] # pan,everything past the first(1:len(s))
v2 = s # Span, s itself has not changed
v3 = s[0:3] # Spa, everything but the last
v4 = s[:3] # Spa,same as s[0:3]
v5 = s[:-1] # Spa,everything but the last again,but simpler(0:-1)
v6 = s[:] # Span,all of s as a top-level copy(0:len(s))
2.1.3使用加号进行合并
作为序列,字符串支持使用加号进行合并(将两个字符串合并为一个新的字符串),或者重复(通过在重复一次创建一个新的字符串)。
注意:对于字符串而言加号是合并,对于整型而言加号是数学运算。
s = "Span" # Span
new_s = s +"xyz" # Spanxyz
s*8 #SpanSpanSpanSpanSpanSpanSpanSpan
2.2不可变性
字符串在Python中具有不可变性,即在创建后不能就地改变。虽然不能通过对其某一个位置进行赋值而改变字符串,但是可以通过建立一个新的字符并以同一个变量名对其进行赋值(Python在运行过程中会清理旧的对象)。
在Python中的每一个对象都可以分为不可变性或可变性。在核心类型中,数字、字符串和元组是不可变的;列表和字典是可变的(即可以完全自由地改变)。在其他地方,这种不可变性可以用来保证在程序中保持一个对象固定不变。
s = "Span"
s[0] = "z" # immutable objects cannot be changed
...error text omitted
s = s + "z" #Spanz (we can run expressions to make new objecs)
2.3类型特定的方法
字符串的find方法是一个基本的子字符串查找的 *** 作(返回一个传入字符串的偏移量,或者在没有找到的情况下返回-1),而字符串的replace方法将会对全局进行搜索和替换。
s = "Span"
v1 = s.find("pa") # 1,查找子字符串的偏移量
v2 = s.replace("pa","XYZ") # SXYZn,用另一个子字符串替换出现的子字符串
虽然这些字符串方法的命名有改变的含义,但并不会改变原始的字符串,而是会创建一个新的字符串作为结果——因字符串具有不可变性。字符串方法是Python中文本处理的头号工具。其他方法还能够实现通过分隔符将字符串拆分为子字符串、大小写变化、测试字符串的内容(数字、字母或其他)、去掉字符串后的空格字符。
line = "aaaa,bbbb,cccc,dddd"
v1 = line.split(",")
# ['aaaa', 'bbbb', 'cccc', 'dddd'] 在分隔符上拆分为子字符串列表
s = "Span"
v2 = s.upper() # SPAN,将内容大写(相应的小写为lower)
v3 = s.isalpha() # True,检查字符串是否仅由字母组成,返回布尔值
#内容测试:isalpha,isdigit,isdecimal,etc
msg = "aaaa,bbbb,cccc,dd\n" # 换行
v4 = msg.rstrip() # vaaaa,bbbb,cccc,dd 删除右侧的空白字符
# msg.strip() 删除空白字符; msg.lstrip() 删除左侧的空白字符
字符串还支持高级替代 *** 作——格式化,可以以一个表达式的形式(最初的)和一个字符串方法调用形式使用。
- %(最早)
name = "amber" age = 18 text_1 = "我的名字叫%s,今年18岁了" % name # 我的名字叫amber,今年18岁了 text_2 = "我的名字叫%s,今年%s岁了" % (name, age) # 我的名字叫amber,今年18岁了 text_3 = "%(friend)s你什么时候过来啊?我爸妈%(time)s不在家" % {"friend": "abby","time": "今天"} # abby你什么时候过来啊?我爸妈今天不在家
model = "我的名字叫%s,今年%s岁了" text_1 = model %("amber",18) # 我的名字叫amber,今年18岁了 text_2 = model %("abby",15) # 我的名字叫abby,今年15岁了
补充:一旦字符串格式化的内容存在百分比的形式就需要打两个百分号(%%)
model = "这个电影我已经下载了90%可是居然断网了" text = "这个%s我已经下载了90%%可是居然断网了" % "电影"
- format(推荐使用)
text_1 = "我叫{0},今年{1},我的真实姓名是{0}".format("amber", 18) # 我叫amber,今年18,我的真实姓名是amber text_2 = "我叫{},今年{}".format("amber", 18) # python会自动加上序号,可以理解为按照位置对应 text_3 = "我叫{},今年{},我的真实姓名是{}".format("amber", 18) # 这种情况就无法像第一个例子那样对应 text_4 = "我叫{name},今年{age},我的真实姓名是{name}".format(name="amber", age=18) data = "我叫{name},今年{age},我的真实姓名是{name}" data_1 = data.format(name="amber", age=18) data_2 = data.format(name="abby", age=15)
-
f
text_1 = f"Alex的小猫叫{'喵喵'},今年3岁了" # f表示要格式化,而花括号{}则表示占位,花括号里面的内容表示占位的内容 name = "喵喵" text_2 = f"Alex的小猫叫{name},今年3岁了" age = 3 text_3 = f"Alex的小猫叫{name},今年{age}岁了"
f还支持表达式
name = "喵喵" text_1 = f"Alex的小猫叫{name},今年{19 + 2}岁了" # Alex的小猫叫喵喵,今年21岁了 text_2 = f"Alex的小猫叫{name},今年{19+2=}岁了" # Alex的小猫叫喵喵,今年19+2=21岁了
进制转换
v1 = f"Alex今年{18}岁" # Alex今年18岁 v2 = f"Alex今年{18:#b}岁" # 其中是:#b是指将18转换为二进制进行显示 # Alex今年0b10010岁 v3 = f"Alex今年{18:#o}岁" # 其中是:#b是指将18转换为八进制进行显示 # Alex今年0o22岁
理解
v1 = f"我是{'Alex'},我爱大铁锤" # 我是Alex,我爱大铁锤 name = "Alex" v2 = f"我是{name},我爱大铁锤" # 我是Alex,我爱大铁锤 v3 = f"我是{name.upper()},我爱大铁锤" # .upper()的作用是将name的内容大写 # 我是ALEX,我爱大铁锤
简明法则:
可作用于多种类型的通用型 *** 作都是以内置函数或表达式的形式出现的【例如,len(X), X(0)】,但是类型特定的 *** 作是以方法调用的形式出现的【例如,astring.upper()】
2.4寻求帮助dir和help是Python文档中寻求帮助的首要选择。
关于类型特定的各种方法的更多细节,可以调用内置的dir函数,将会返回一个列表,其中包含了对象的所有属性。
s = "string"
dir(s)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
'__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit',
'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper',
'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix',
'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip',
'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper',
'zfill']
列表里有些变量名中含有下划线,它们代表了字符串对象的实现方式,并支持定制。一般来说,以双下划线开头并结尾的变量名是用来表示Python实现细节的命名模式。这个列表中没有下划线的属性是字符串对象是能够调用的方法。
dir函数简单地给出了方法的名称,可将其传递给help函数来查询它们具体功能。(help是一个随Python一起分发的面向系统代码的接口)
s = "string"
help(s.replace)
Help on built-in function replace:
replace(old, new, count=-1, /) method of builtins.str instance
Return a copy with all occurrences of substring old replaced by new.
count
Maximum number of occurrences to replace.
-1 (the default value) means replace all occurrences.
If the optional argument count is given, only the first count occurrences are
replaced.
Help on built-in function replace:
replace(old, new, count=-1, /) method of builtins.str instance
Return a copy with all occurrences of substring old replaced by new.
count
Maximum number of occurrences to replace.
-1 (the default value) means replace all occurrences.
If the optional argument count is given, only the first count occurrences are
replaced.
None
进程已结束,退出代码0
2.5编写字符串的其他方法
- 反斜杠转义序列表示特殊的字符
S1 = 'A\nB\tC' """ \n表示换行,\t表示一个Tab(四个空格) A B C """ len(S1) # 5,每个代表一个字符 ord('\n') # 10 ,\n表示ascii 中二进制值为 10 的字节 'A
msg = """aaaaaaaaaaaa bbb'''bbbbbbbbbb'""bbbbbb'bbbb cccccccccccccc""" msg = '\naaaaaaaaaaaa\nbbb\'\'\'bbbbbbbbbb'""bbbbbb\'bbbb\ncccccccccccccc'
Bimport re match = re.match('Hello[\t]*(.*)world', 'Hello Python world') # group()用来提出分组截获的字符串 match.group(1) # 'Python' """这个例子的目的是搜索字符串,这个字符串以“Hello,”开始, 后面跟着零个或几个制表符或空格符,接着有任意字符将其保存到匹配的group中, 最后以“world.”结尾。如果找到了这样的子字符串, 与模式中括号包含的部分匹配的子字符串的对应部分保存为组。"""
C' # A B C,二进制零字节,不终止字符串
- Python允许字符串包括在单引号或双引号当中(二者无区别)。也允许在单个引号中包括多行字符串常量(所有的行都合并在一起,且在最后以后的末尾增加换行符)。
import re match = re.match('/(.*)/(.*)/(.*)','/usr/home/lumberjack') match.groups() # ('usr', 'home', 'lumberjack') # 取出三个被斜线所分割的组
字符串对象的方法能够支持基于模式的文本处理。在Python中进行模式匹配需要导入一个名为re的模块。这个模块包含了类似搜索、分割、替换等调用(使用模式去定义字符串更通用)。
re.match() 从开始位置开始往后查找,返回第一个符合规则的对象,如果开始位置不符合匹配队形则返回None。
L = [123,'spam','1.23'] # 三个不同类型对象的列表
v1 = len(L) # 3,列表中的项目数
v2 = L[0] # 123,通过位置索引
v3 = L[:-1] # [123, 'spam'],对列表进行切片,返回一个新列表
v4 = L +[4,5,6] # [123, 'spam', '1.23', 4, 5, 6]连接创建一个新列表,不改变原始列表
L = [123, 'spam', 1.23] # 三个不同类型对象的列表
v1 = L.append('NI')
# 列表的append方法扩充了列表的大小且在列表的尾部插入一项
print(v1) # None
print(L) # [123, 'spam', 1.23, 'NI']
v2 = L.pop(2) # 1.23
# 列表的pop方法(等效于del语句)移除给定偏移量的一项,从而让列表减小
print(L) # [123, 'spam', 'NI']
print(v2)
3.列表
列表是一个任意类型的对象的位置相关的有序集合,它没有固定是大小(字符串的大小是可变的)。通过对偏移量进行赋值以及其他各种列表的方法进行调用,可以修改列表的大小。
3.1序列 *** 作列表也是序列的一种,故列表支持所有在字符串中讨论过的序列 *** 作,唯一的区别就是其结果是列表而不是字符串。
M = ['box', 'airport', 'zero']
M.sort()
print(M) # ['airport', 'box', 'zero']
M.reverse()
print(M) # ['airport', 'box', 'zero']
3.2类型特定的 *** 作
列表没有固定类型的约束,可以包含不同类型的对象。此外,列表没有固定大小,能够按照需要增加或减小列表大小,来响应其特定的 *** 作。(直接对列表进行了改变)
- 列表的append方法扩充了列表的大小并在列表的尾部插入一项;列表的pop方法(等效于del语句)移除给定偏移量的一项,从而让列表减小。
M = ['box', 'airport', 'zero'] M.insert(1, '我爱河东狮') print(M) # ['box', '我爱河东狮', 'airport', 'zero'] M.remove('zero') print(M) # ['box', '我爱河东狮', 'airport']
- sort(默认按照升序对列表进行排序);reverse(对列表进行翻转)
M = ['box', 'airport', 'zero'] v1 = M[99] print(v1) # list index out of range M[99] = 1 print(M) # list assignment index out of range
- insert(在任意位置插入元素);remove(按照值移除元素)
M = [[1, 2, 3], # 如果括起来,代码可以跨行 [4, 5, 6], [7, 8, 9]] print(M) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # M作为一个嵌套列表,是一个3x3矩阵 print(M[1]) # [4, 5, 6]获取第2行 print(M[1][2]) # 6 获取第2行第3项
虽然列表没有固定的大小,Python不允许引用不存在的元素。超过列表末尾之外的索引会报错,对列表末尾范围之外的赋值也会报错。
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
col2 = [row[1] for row in M] # 收集第2列中的项目
print(col2) # [2, 5, 8]
print(M) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 矩阵本身并没有被改变
给列表边界之外的元素赋值会报错。在Python中并不是默默地增大列表作为响应,而是会报错。为了让列表增大,可以调用append这样的列表方法。
3.4嵌套Python核心数据的一个重要特性就是它们支持任意的嵌套。能够以任意的组合对其进行嵌套,且可以多个层次进行嵌套(例如,可以让一个列表包含一个字典,并在这个字典中包含另一个列表)。嵌套的一个直接应用就是实现矩阵,或者Python中的“多维数组”。一个嵌套的列表能够完成这个基本的 *** 作。
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
a = [row[1] + 1 for row in M] # 把收集到的元素都加1
print(a) # [3, 6, 9]
b = [row[1] for row in M if row[1] % 2 == 0]
# 使用if条件语句,通过%求余表达式过滤了结果中的奇数
print(b) # [2, 8]
串联起索引 *** 作可以逐层深入地获取嵌套的对象结构(这种矩阵结构适用于小规模的任务,但是对于更重要的数值运算,会使用Python数值扩展包里的工具,如Numpy系统)。
3.5列表解析Python的列表解析表达式提供了一种处理像矩阵这样结构的强大工具。
假设我们需要从给定矩阵中取出第二列,因为矩阵是按行进行储存的,所以通过简单的索引即可获取行,使用列表解析同样可以简单地获得列。(并没有改变矩阵本身)
列表解析源自集合的概念,通过对列表中的每一项运行一个表达式来创建一个新的列表,每次一个,从左到右。列表解析是创建在方括号中的,由使用了同一个变量名的表达式(此例中是row)和循环结构组成。此例中的列表解析表达式含义为:把矩阵M的每个row中的row[1]取出来,创建一个新列表。
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
diag = [M[i][i] for i in [0, 1, 2]]
print(diag) # [1, 5, 9]
doubles = [c * 2 for c in "span"]
print(doubles) # ['ss', 'pp', 'aa', 'nn']
实际应用中列表解析可能更复杂
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
G = (sum(row) for row in M)
print(next(G)) # 6, 创建行和生成器
print(next(G)) # 15, 运行迭代协议
print(next(G))
a = list(map(sum, M))
print(a) # [6, 15, 24]
列表解析创建了新的列表作为结果,但是能够在任何可迭代的对象上进行迭代。
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
a = {sum(row) for row in M} # 创建一组行总和
print(a) # {24, 6, 15}
b = {i: sum(M[i]) for i in range(3)} # 创建行总和的键/值表
print(b) # {0: 6, 1: 15, 2: 24}
列表解析是一个可选的特性,在实际应用中比较方便,且具有处理速度上的优势,此外能在Python的任何序列类型(甚至一些不属于序列的类型)中发挥作用。
在Python中,括号里的解析语法也可以用来创建产生所需结果的生成器(如内置的sum函数,按一种顺序汇总各项;内置的map函数,产生对各项运行一个函数的结果,将其包装到列表中,使其返回所有值)
a = [ord(x) for x in 'span']
print(a) # [115, 112, 97, 110]
b = {ord(x) for x in 'span'}
print(b) # {112, 97, 115, 110}
c = {x: ord(x) for x in 'span'}
print(c) # {'s': 115, 'p': 112, 'a': 97, 'n': 110}
解析语法也可用来创建集合与字典。
D = {'food': 'Spam', 'quantity': 4, 'color': 'pink'}
# (键分别为"food","quantity","color")
a = D['food']
print(a) # Spam
D['quantity'] += 1
print(D) # {'food': 'Spam', 'quantity': 5, 'color': 'pink'}
(在Python3.0中)用解析可以创建列表、集合和字典。(ord函数主要用来返回对应字符的ASCII码)
D = {}
D['name'] = 'Bob'
D['job'] = 'dev'
D['age'] = 40
print(D) # {'name': 'Bob', 'job': 'dev', 'age': 40}
4.字典
Python中的字典是一种映射。映射是一个其他对象的集合,它们是通过键(而不是相对位置)来存储的。实际上,映射并没有任何可靠的从左至右的顺序。它们简单地将键映射到值。字典是Python核心对象集合中的唯一的一种映射类型,具有可变性(可以就地改变),且可以随需求增大或减小。
4.1映射 *** 作作为常量编写时,字典编写在大括号中,并包含一系列的“键:值”对。字典在需要将键与一系列值相关联时很有用。可以通过键对字典进行索引来读取或改变键所关联的值。字典的索引 *** 作使用的是和序列相同的语法,但是方括号里的元素是键而不是相对位置。
rec = {'name':{'first name':'Bob','last name':'Smith'},
'job':['dev','mgr']
'age':45}
虽然可以用大括号这种常量形式,但是还有其他创建字典的方法。开始创建一个空的字典,每次以一个键来填写它。与列表中禁止边界不同,对一个新字典的键赋会创建该键。通过键索引一个字典是Python中编写搜索的最快方法。
rec = {'name':{'first name':'Bob','last name':'Smith'},
'job':['dev','mgr'],
'age':45}
a = rec['name'] # name是一个嵌套字典
print(a)
# {'first name': 'Bob', 'last name': 'Smith'}
b = rec['name']['last name'] # 索引嵌套字典
print(b)
# Smith
c = rec['job'] # job是一个嵌套列表
print(c)
# ['dev', 'mgr']
d = rec['job'][-1] # 索引嵌套列表
print(d)
# mgr
rec['job'].append('janitor') # 就地扩展职位描述
print(rec)
""" {'name': {'first name': 'Bob', 'last name': 'Smith'},
'job': ['dev', 'mgr', 'janitor'],
'age': 45}"""
4.2重坊嵌套
在上面的例子中我们使用字典去描述一个假设的人物,用了三个键(key)。假设信息更为复杂,名字包括姓(first name)和名(last name),且有多个工作(job)的头衔。这就产生了Python对象嵌套的应用。
D = {'a':1,'b':2,'c':3}
print(D) # {'a': 1, 'c': 3 'b': 2,}
在顶层再次使用了三个键的字典(分别是name、job、age),但是值的情况更为复杂:一个嵌套的字典作为name的值,支持了多个部分,且用一个嵌套的列表作为job的值从而支持多个角色和未来的扩展。
for x in 'span':
print(x.upper())
"""
输出结果:
S
P
A
N
"""
Python核心数据类型具有灵活性,嵌套允许直接并轻松地建立起复杂的信息结构。在Python中,当最后一次引用对象后,这个对象所占用的内存空间将会自动清理掉。从技术上来讲,Python具有垃圾收集的特性,在程序运行时可以清理不再使用的内存,不必再管理代码。在Python中,一旦一个对象的最后一次引用被移除,空间就会立即回收。
4.3键的排序:for循环作为映射字典仅支持通过键获得元素,但通过调用方法,字典也支持类型特定的 *** 作。字典不是序列,它们并不包括任何可靠的从左到右的顺序,也就是说,如果建立起一个字典并将其打印出来,它的键可能会与我们输入时的顺序不同。
a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c', 'd', 'e']
zip(a, b)
for i in zip(a, b):
print(i)
"""
(1, 'a')
(2, 'b')
(3, 'c')
(4, 'd')
(5, 'e')
"""
new_list = list(zip(a, b))
print(new_list)
# [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
for j in zip(*new_list):
print(j)
"""
(1, 2, 3, 4, 5)
('a', 'b', 'c', 'd', 'e')
"""
在一个字典的元素中,想要强调某种顺序时,通过字典的keys方法收集一个键的列表,使用列表的sort方法进行排序,然后使用Python的for循环逐个进行显示结果。
D = {'a': 1, 'b': 2, 'c': 3}
Ks = list(D.keys()) # .keys()返回字典中所有键组成的一个可迭代序列
print(Ks) # ['a', 'b', 'c']
Ks.sort() # 按升序对列表进行排序并返回 None。即排序的键列表
print(Ks) # ['a', 'b', 'c']
for key in Ks:
print(key, '=>', D[key])
"""
a => 1
b => 2
c => 3
"""
在Python的最新版本中,通过使用最新的sorted内置函数可以一起完成。sorted内置函数可以一步完成。sorted调用返回结果并对各种对象类型进行排序。
D = {'a': 1, 'b': 2, 'c': 3}
for key in sorted(D):
print(key, '=>', D[key])
"""
a => 1
b => 2
c => 3
"""
for循环是遍历一个序列中的所有元素并按顺序对每一元素运行一些代码的简单并有效的一种方法,一个用户定义的循环变量(此例中是key)用作每次运行过程中当前元素的参考量。(这个例子中的实际效果是打印这个自身是无序的字典的键和值,以排好序的键的顺序输出)。
D = {'a':1,'b':2,'c':3,'d':4}
value=D.get('b',0)
print(value) # 2
data = D.get('x',0)
print(data) # 0
Python的while循环是一种更为常见的排序循环工具,它不仅限于遍历序列:
x = 4
while x >0:
print('span'*x)
x-=1
"""
输出结果为:
spanspanspanspan
spanspanspan
spanspan
span
"""
4.4迭代和优化
for循环和之前的列表循环都是真正的通用迭代工具,都能够工作于遵守迭代协议的任意对象。
>>> squares = [x**2 for x in [1,2,3,4,5]]
>>> squares
[1, 4, 9, 16, 25]
D = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
value = D['x'] if 'x' in D else 0
print(value) # 0
data = D['c'] if 'c' in D else 0
print(data) # 3
编写一个等效的for循环,通过在运行时手动增加列表来创建最终的列表:
>>> squares = []
>>> for x in [1,2,3,4,5]:
... squares.append(x**2)
...
>>> squares
[1, 4, 9, 16, 25]
列表解析和相关的函数编程工具,如map和filter,通常运行得比for循环快:这是对大数据集合的程序有重大影响的特性之一。在python中性能测试是一个很难应付的任务,因为它在反复地优化。
Python的一个主要原则:首先为了简单和可读性去编写代码,在程序可以工作,并证明了确实有必要考虑性能后再考虑该问题。
4.5不存在的键:if测试获取一个不存在的键值会报错。但一般情况下并不知道当前存在什么键,在这种情况下为避免系统报错,技巧就是首先进行测试。in关系表达式允许我们查询字典中的一个键是否存在,并可以通过使用Python的if语句对结果进行分支处理:
>>> D = {'a':1,'b':2,'c':3,'d':4}
>>> D['f'=99]
File "", line 1
D['f'=99]
^
SyntaxError: invalid syntax
>>> D['f']=99
>>> D
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 99}
>>> D['h']
Traceback (most recent call last):
File "", line 1, in
KeyError: 'h'
>>> 'h' in D
False
>>> if not 'h' in D:
... print('missing')
...
missing
>>>
有其他方法来创建字典并避免获取不存在的字典键:get方法、try语句、if/else表达式
D.get(‘key’,‘value’):如果字典中存在关键字key,则返回关键字对应的值;如果字典d中不存在关键字key,则返回value的值,一般默认为None,也可以返回指定的value值。
模式
5.元组描述
元组对象就像一个不可改变的列表。就像列表一样,元组是序列,但是它具有不可变性,和字符串类似。从语法上讲,它们编写在圆括号里,支持任意类型、任意嵌套以及常见的序列 *** 作。
>>> T =(1,2,3,4)
>>> len(T)
4
>>> T+(5,6)
(1, 2, 3, 4, 5, 6)
>>> T[0]
1
>>> T.index(4)
3 # 4出现在偏移量为3的位置
>>> T.count(4)
1 # 4出现了一次
>>>
元组真正的不同之处在于一旦创建就不可改变,即元组是不可变的序列。
>>> T =(1,2,3,4)
>>> T[2]=0
Traceback (most recent call last):
File "", line 1, in
TypeError: 'tuple' object does not support item assignment
>>>
为什么要用元组
元组在实际应用中并不像列表常见,但它的关键之处在于不可变性。如果在程序中以列表的形式传递一个对象的集合,它可能在任何地方改变;如果使用元组则不能改变。即,元组提供了一种完整的约束,有利于编写更大型的程序。
6.文件t | 文本模式 (默认)。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
U | 通用换行模式(不推荐)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
文件对象是Python代码对电脑上外部文件的主要接口,文件虽然也是核心类型,但它的特殊之处在于:没有特定的常量语法创建文件。要创建一个文件对象,需调用内置的open函数以字符串的形式传递给它一个外部的文件名以及一个处理模式的字符串。例如,创建一个文本输出文件,可以传递其文件名以及“w”处理模式字符串以写数据:
>>> f = open('data.txt','w') # 在输出模式下创建一个新文件
>>> f.write('Hello\n') # 向其写入字节字符串
6
>>> f.write('World\n') # 向其写入字节字符串
6
>>> f.close() # 关闭已打开文件
这样就在当前文件夹下创建了一个文件,并向它写入文本。为了读出刚才所写内容,重新以“r”处理模式打开文件,读取输入。之后将文件的内容读至一个字符串并显示它。对于脚本而言,无论包含的数据是什么类型,文件的内容总是字符串。
>>> f = open('data.txt')
>>> text = f.read()
>>> text
'Hello\nWorld\n'
>>> print(text)
Hello
World
>>> text.split()
['Hello', 'World']
>>>
想要快速预览文件内容,可以在任意打开的文件上运行一个dir调用并在返回的任何方法名上调用一个help:
>>> dri(f)
Traceback (most recent call last):
File "", line 1, in
NameError: name 'dri' is not defined
>>> 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.
>>>
Python3.0中的文件在文本和二进制数据之间划分清楚。文本文件将内容显示为字符串,且自动执行Unicode编码和解码;而二进制文件把内容显示为一个特定的字节字符串类型,且允许不修改地访问文件。
其他文件类工具open函数能够实现在Python编码中编写的绝大多数文件处理,但Python还有额外的类文件工具:管道、先进先出队列、套接字、通过键访问文件、对象持久、基于描述符的文件、文件数据库、面向对象数据库接口等。
描述文件支持文件锁定和其他的底层工具,而套接字提供网络和进程间通信的接口。
7.其他核心类型集合是才被添加到Python语言的类型,它不是映射也不是序列,集合是唯一的不可变的对象的无序集合。集合可以通过调用内置set函数而创建,或使用集合常量和表达式创建,且支持一般的数学集合 *** 作(集合更像是一个无值的字典的键)
>>> X = set('spam') # 从一个序列中创建一个集合
>>> Y ={'h','a','m'} # 用新的集合文字制作一个集合
>>> X,Y
({'m', 'a', 's', 'p'}, {'h', 'a', 'm'})
>>> X&Y # 并集
{'m', 'a'}
>>> X|Y # 交集
{'m', 'a', 'p', 'h', 's'}
>>> X-Y # 差别(X减去二者之间的公共部分)
{'s', 'p'}
>>> {x**2 for x in [1,2,3,4]}
{16, 1, 4, 9}
>>>
Python中还添加了新的数值类型:十进制数(固定精度浮点数)、分数(一个分子一个分母的有理数),它们都用来解决浮点数学的局限性和内在的不精确性。
Python中还添加了布尔值(True 、False),以及长期以来一直支持的特殊的占位符对象None(通常用来初始化名字和对象)
7.1如何破坏代码的灵活性Python中type是一个内建的获取变量类型的函数。type()函数有两个用法,当只有一个参数的时候,返回对象的类型;当有三个参数的时候返回一个类对象。(类型本身也是一种对象)
>>> L=[1,2,3,4]
>>> type(L) # L是一种列表对象
>>> type(type(L))
# 类型也是一种对象
>>>
type函数不仅运行交互地探讨对象,且允许编写代码来检查它所处理的对象的类型。
>>> L=[1,2,3,4]
>>> if type(L)==type([]): # 类型测试,if you must...
... print('yes')
...
yes
>>> if type(L)==list: # 使用类型名称
... print('yes')
...
yes
>>> if isinstance(L,list): # 面向对象测试
... print('yes')
...
yes
>>>
通过后续的学习会知道在Python程序中这样做是错误的:在代码中检验了特定的类型,实际上破坏了它的灵活性,即限制它只能使用一种类型工作;如果没有这样的检测代码可能使用整个范围的类型工作。不关注于特定的类型意味着代码会自动地适应它们中的很多类型:不管他是什么对象类型,任何具有兼容接口的对象均能够工作。
7.2用户定义的类【定义函数使用def关键字】:①在这个关键字之后是标识函数的名字;②是在一对括号中可以附上一些变量名;③最后在行的末尾是冒号。④接下来是语句块--函数的一部分。
【__init__()函数】初始化新创建对象的状态,在一个对象被创建以后会立即调用。①带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问。②init函数(方法)支持带参数的类的初始化 ,也可为声明该类的属性。③init函数(方法)的第一个参数必须是self(self为习惯用法,也可以用别的名字),后续参数则可以自由指定,和定义函数没有任何区别。
类定义了新的对象类型,扩展了核心类型,但python中没有这样特定的核心类型。类定义与函数定义(def语句)一样:只有在被执行才会起作用。
这个类定义了一个新的对象的种类,有name和pay两个属性(称之为“信息状态”),也有两个小的行为编写为函数(称之为“方法”)的形式。像函数那样去调用类,会生成新类型的示例,且类的方法调用是,类的方法字典获取被处理的实例(self参数)。
隐含的“self”对象是我们把这叫做面向对象模型的原因,即一个类中的函数总有一个隐含的对象。一般来说,基于类的类型是建立在并使用了核心类型的。在这个例子中。用户定义的Worker对象 ,是一个字符串和数字(分别为name和pay)的集合,附加了用来处理这两个内置对象的函数。
类的特性及其继承机制使Python支持软件层次,使其可以通过扩展进行定制。我们可以通过编写新的类来扩展软件而不是改变目前工作的类。类是Python可选的一个特性,且与用户编写的类相比,列表和字典等更好。
7.3剩余的内容Python脚本中能够处理的所有事情都是某种类型的对象,而这里介绍的对象却是不完整的。即使在Python中的每样东西都是一个“对象”,只有我们目前所见的那些对象类型才被认为是Python核心类型集合中的一部分。其他Python中的类型有的是与程序执行相关的对象(如函数、模块、类和编译过的代码),;有的是由导入的模块函数而不是语言语法实现的。
我们所学过的对象仅仅是对象而已,并不一定是面向对象。面向对象是一种要求有继承和Python类声明的概念。
本章习题:1.列举Python核心数据类型的名称。
数字、字符串、列表、字典、元组、文件和集合一般被认为是Python的核心数据类型。类、None和布尔值有时也被定义在这样的分类中。还有多种数字类型和多种字符串类型。
2.为什么把它们称之为核心数据类型?
它们被称为是“核心”数据类型是因为它们是Python语言本身的一部分,并且总是有效的;为了建立其他对象,通常必须导入模块的函数。大多数核心数据类型都有特定的语法去生成其对象。(如:‘spam’是一个创建的字符串的表达式,而且决定了可以被应用的 *** 作的集合。)正是因为这一点,核心类型与Python的语法紧密相连。与之相比较,必须调用内置的open函数去创建一个文件对象。
3.“不可变性”代表什么?哪三种Python核心数据类型被认为是具有不可变性?
一个具有“不可变性”的对象是一个在其创建之后就不能改变的对象。Python中的数字、字符串和元组都属于这个分类。尽管无法就地改变一个不可变的对象,但是可以通过运行一个表达式创建一个新的对象。
4.“序列”是什么意思?有哪些Python的核心数据类型被认为是这个分类中的?
一个“序列”就是一个对位置进行排序的对象的集合。字符串、列表和元组是Python中所有的序列。它们共同拥有一般的序列 *** 作,如:索引、合并及分片,但又有各自类型特定的方法调用。
5.“映射”是什么意思?哪种Python的核心类型是映射?
“映射”表示键与相关值相互关联映射的对象。Python的字典是其核心类型集中唯一的映射类型。映射没有从左至右的位置顺序;它们支持通过键获取数据,并包括了类型特定的方法调用。
6.什么是“多态”我们为什么要关心多态?
“多态”意味着一个 *** 作符的意义取决于被 *** 作的对象,这是用好Python的关键思想:不要把代码限制在特定的类型上,让代码自动适应于多种类型。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)