史上最全Python学习笔记(基于《Python学习手册(第4版)》)——Part2 Python基本类型

文章目录

  • Chap04 介绍Python对象类型
    • 数字
      • 数学模块
      • random模块
    • 字符串
      • 序列的操作
      • 可变对象与不可变对象
      • 类型特定的方法
      • 编写字符串的其他方法
      • 模式匹配
    • 列表
      • 序列操作
      • 类型特定的操作
      • 边界检查
      • 嵌套
      • 列表的解析
    • 字典
      • 映射操作
      • 重访嵌套
      • 键的排序:for循环
      • 迭代和优化
      • 不存在的键:if测试
    • 元组
      • 元组拆包和具名元组
      • 为什么要使用元组
      • 元组和列表的对比
    • 文件
      • 读取文件的最佳方式
      • 其他文件类工具
    • 其他核心类型
      • 集合
        • 集合的专有运算
        • 集合的解析
      • 新的数值类型
        • 十进制数和分数
          • decimal模块
          • fractions模块
        • 布尔值
    • 用户定义的类
  • Chap05 数字和集合
    • Python的数字类型
      • 数字常量
          • 整数和浮点数常量
          • Python3.0中的整数:一个单独的类型
          • 十六进制数、八进制和二进制常量
          • 复数
          • 编写其它的数字类型
      • 内置数学工具和扩展
    • 在实际应用中的数字
      • 变量和基本的表达式
      • 数字显示的格式
          • str和repr显示格式
      • 比较:一般的和连续的
      • 除法:传统除法、Floor除法和真除法
          • 支持两个版本
          • Floor除法VS截断除法
          • 为什么截断很重要
      • 整数精度
      • 复数
      • 十六进制、八进制和二进制记数
      • 位操作
      • 其他的内置数学工具
      • 其他数字类型
        • 小数数字
          • 基础知识
          • 设置全局精度
          • 小数上下文管理器
        • 分数类型
          • 基本知识
          • 数值精度
          • 转换和混合类型
    • 集合
      • 集合基础知识
        • 集合的创建
        • 集合的运算
        • 集合对象的相关操作方法
      • 不可变限制和冻结集合
      • Python3.0中集合的解析
      • 为什么使用集合
    • 布尔型
  • Chap06 动态类型简介
    • 缺少类型声明语句的情况
      • 变量、对象和引用
      • 类型属于对象,而不是变量
      • 对象的垃圾收集
    • 共享引用
      • 共享引用和在原处修改
      • 共享引用与相等
    • 动态类型随处可见
  • Chap07 字符串
    • 字符串常量
      • raw字符串抑制转义
    • 实际应用中的字符串
      • 基本操作
      • 索引与分片
        • 扩展分片
        • 为什么要在意:分片
      • 字符串转换工具
        • 字符串代码转换
    • 字符串方法
      • 方法实例:修改字符串
      • 方法实例:文本解析
    • 字符串格式化表达式
      • \*的使用
      • 基于字典的字符串格式化
    • 字符串格式化调用方法
      • 基础知识
      • 添加键、属性和偏移量
      • 添加具体格式化
    • 正则表达式入门
  • Chap08 列表与字典
    • 列表
      • 引言
      • 实际应用中的列表
        • 列表迭代和解析
        • 索引、分片和矩阵
        • 原处修改列表
          • 列表方法的调用
    • 字典
      • 引言
      • 字典的基本操作
        • 其他字典方法
      • 语言表
      • 字典用法注意事项
        • 使用字典模拟灵活的列表
        • 字典用于稀疏数据结构
        • 避免missing-key错误
        • 使用字典作为“记录”
      • 创建字典的其他方法
      • Python3.0中的字典变化
        • 字典解析
        • 字典视图
        • 字典视图和几何
        • 排序字典键
        • 字典大小比较不再有效
        • has_key方法已死,in永生
  • Chap09 元组、文件及其他
    • 元组
      • 引言
      • 实际应用中的元组
        • 转换、方法以及不可变性
      • 为什么有了列表还要元组
    • 文件
      • 引言
      • 打开文件
      • 使用文件
      • 实际应用中的文件
        • Python3.0中的文本和二进制文件
        • 在文件中存储并解析Python对象
        • 用pickle存储Python的原生对象
        • 文件中打包二进制数据的存储与解析
      • 其他文件工具
    • 重访类型分类
    • 对象灵活性
    • 引用VS拷贝
    • 比较、相等性和真值
    • Python3.0的字典比较
    • Python中真和假的含义
    • Type对象

Chap04 介绍Python对象类型

从更具体的视角来看,Python程序可以分解成模块、语句、表达式以及对象。

  1. 程序由模块构成
  2. 模块包含语句
  3. 语句包含表达式
  4. 表达式建立并处理对象

为什么要使用内置类型

除非有内置类型无法提供的特殊对象要处理,最好总是使用内置对象而不是使用自己的实现。理由如下:

  1. 内置对象使程序更容易编写
  2. 内置对象是扩展的组件
    • 人工实现的对象往往建立在像列表和字典这样的内置类型的基础之上
  3. 内置对象往往比定制的数据结构更有效率
  4. 内置对象是语言的标准的一部分

数字

Python的核心对象集合包括常规的类型:整数、浮点数以及更为少见的类型(有虚部的复数、固定精度的十进制数、带分子和分母的有理分数以及集合等)。

Python中的数字支持一般的数学运算,例如:+(加法)、*(乘法)、**(乘方)。

数学模块

import math
print(math.pi)
print(math.sqrt(85))
3.141592653589793
9.219544457292887

random模块

random模块可以作为随机数字的生成器和随机选择器。

import random
print(random.random())
print(random.choice([1,2,3,4]))
0.9102182160999952
4

字符串

字符串是Python中作为序列(即一个包含其他对象的有序的集合)所提到的第一个例子。

序列中的元素包含了一个从左到右的顺序——序列中的元素根据它们的相对位置进行存储和读取。

从严格意义上来说,字符串是单个字符的字符串的序列,其他类型的序列还包括列表和元组。

序列的操作

# 通过内置函数len()验证字符串的长度并通过索引操作得到其各个元素
S = 'Spam'
print(len(S))
print(S[0]+"\n"+S[1])
4
S
p

在Python中,可以进行反向索引:

print(S[-1])
print(S[-2])
m
a

除了能简单地从未知进行索引,序列也支持一种所谓**分片(slice)**的操作,这是一种一步就能提取整个分片的方法。

例如:

print(S[1:3]) # Slice of S from offsets 1 through 2(not 3)
pa
# more examples of slice
print(S[1:])
print(S[0:3])
print(S[:-1])
print(S[:])
pam
Spa
Spa
Spam

作为一个序列,字符串也支持使用加号进行合并,或通过星号进行重复。

print(S+'xyz')
print(S)
print(S*8)
print(S-'a') # 不能运行减运算
spamxyz
spam
spamspamspamspamspamspamspamspam



---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
      2 print(S)
      3 print(S*8)
----> 4 print(S-'a') # 不能运行减运算


TypeError: unsupported operand type(s) for -: 'str' and 'str'

不可变性

字符串在Python中具有不可变性——在创建后不能就地改变。例如不能通过对其某一位置进行赋值而改变字符串,但可以通过建立一个新的字符串并以同一个变量名对其进行赋值。

S[0]='z' # Immutable objects cannot be changed
print(S[0])

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
----> 1 S[0]='z' # Immutable objects cannot be changed
      2 print(S[0])
      3 S='z'+S[1:]
      4 print(S)


TypeError: 'str' object does not support item assignment
S='z'+S[1:]
print(S) # But we can run expressions to make new objects
zpam

可变对象与不可变对象

Python中的每一个对象都可以分为不可变形或者可变形。在核心类型中,数字、字符串和元组是不可变的;列表和字典不是这样(它们可以完全自由地改变)。在其他方面,这种不可变形可以保证在程序中保持一个对象固定不变。

类型特定的方法

除了一般的序列操作,字符串还有独有的一些操作作为方法存在

# find()
print(S.find('pa'))
# replace()
#尽管该方法有改变字符串的含义,但是并不会改变原始的字符串,而是会创建一个新的字符串作为结果,因为字符串具有不可变形性
print(S.replace('pa','XYZ'))
# split()
line='aaa,dbbb,ccccc,dd'
print(line.split(','))
# upper()
S='spam'
print(S.upper())
# isalpha()
print(S.isalpha())
# rstrip() --Remove whitespace characters on the right side
line='aa,bb,cc,dd      '
print('length:',len(line))
line=line.rstrip()
print('length after rstrip:',len(line))
# 字符串支持格式化的高级替代操作
print('%s,egges,and %s'%('spam','SPAM!'))
print('{first},eggs,and {second}'.format(first='spam',second='SPAM!'))
1
sXYZm
['aaa', 'dbbb', 'ccccc', 'dd']
SPAM
True
length: 17
length after rstrip: 11
spam,egges,and SPAM!
spam,eggs,and SPAM!
# 可以通过调用dir(Object)的方法来查看对象所包含的所有属性(包括函数)
dir(S)
# 可以通过调用help(Obj.method)的方法来查看一个对象的具体函数的作用
help(S.replace)

编写字符串的其他方法

Pyton允许字符串包括在在单引号或双引号中(它们代表着相同的东西)。它也允许在三个引号(单引号或双引号)中包括多行字符蹋常量。当采用这种形式的时候,所有的行都合并在一起,并在每一行的末尾增加换行符。这是一个微妙的语陆上的便捷方式,但是在Python脚本中嵌入像HTML或XML这样的内容时,这是很方便的。

msg="""aaaaaaaaa
bbb'''bbbbbbbbbbb""bbbbbb'bbbbb
ccccccccccccccc"""
msg
'aaaaaaaaa\nbbb\'\'\'bbbbbbbbbbb""bbbbbb\'bbbbb\nccccccccccccccc'

模式匹配

为了进行模式匹配,需要导入一个名为re的模块。这个模块包含了类似搜索、分割和替换等调用,但是因为使用模式去定义子字符串,可以更通用一些:

import re
match=re.match('Hello[\t]*(.*)world','Hello    Python world')
match.group(1)
'    Python '
match=re.match('/(.*)/(.*)/(.*)','/user/home/lumberjack')
match.groups()
('user', 'home', 'lumberjack')

列表

列表是一个任意类型的对象的位置相关的有序集合,它段有固定的大小。不像字符串,其大小是可变的,通过对偏移量进行赋值以及其他各种列表的方法进行调用,确实能够修改列表的大小。


序列操作

L=[123,'spam',1.23]
print(len(L))
print(L[0])
print(L[:-1])
print(L+[4,5,6])
print(L) # We're not changing the original list
3
123
[123, 'spam']
[123, 'spam', 1.23, 4, 5, 6]
[123, 'spam', 1.23]

类型特定的操作

列表没有固定类型的约束。

列表没有固定大小,也就是说能够按照需要增加或减小列表的大小,来响应其特定的操作:

# append()
L.append('NI')
print(L)
# pop()
print(L.pop(2))
print(L)
# insert()
L.insert(0,'abc')
print(L)
# remove()
L.remove('abc')
print(L)
# sort()
M=['bb','aa','cc']
M.sort()
print(M)
# reverse()
M.reverse()
print(M)
N=sorted(M)
print(N)
[123, 'spam', 'NI', 'NI']
NI
[123, 'spam', 'NI']
['abc', 123, 'spam', 'NI']
[123, 'spam', 'NI']
['aa', 'bb', 'cc']
['cc', 'bb', 'aa']
['aa', 'bb', 'cc']

边界检查

超出列表末尾之外的索引总是会导致错误,对列表末尾范围之外的赋值也是如此。


嵌套

Python核心数据类型的一个优秀的特性就是它们支持任意的嵌套。能够以任意的组合对其进行嵌套,并可以多个层次进行嵌套。这种特性的一个直接的应用就是实现矩阵,或Python中的“多维数组”。

M=[[1,2,3],
   [4,5,6],
   [7,8,9]]
print(M)
print(M[1])
print(M[1][2])
print(M[0][4])
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[4, 5, 6]
6



---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

 in ()
      5 print(M[1])
      6 print(M[1][2])
----> 7 print(M[0][4])


IndexError: list index out of range

列表的解析

处理序列的操作和列表的方法中,Python还包括了一个更高级的操作,称作列表解析表达式,从而提供了一种处理像矩阵这样结构强大的工具。

列表解析是一个可选的特性,在实际应用中比较方便,并常常具有处理速度上的优势。它们也能够在Python的任何的序列类型中发挥作用,甚至一些不属于序列的类型。

col2=[row[1] for row in M] # 把矩阵M中的每个row中的row[1]放在一个新的列表中
print(col2)
print(M) # The matrix is unchanged
[2, 5, 8]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[row[1] +1 for row in M] # Add 1 to each item in column 2
[3, 6, 9]
[row[1] for row in M if row[1]%2==0] # Filter out odd items
[2, 8]
# 使用列表解析去步进坐标的一个硬编码列表和一个字符串
diag1=[M[i][i] for i in [0,1,2]]
print(diag1)
doubles=[c*2 for c in 'spam']
print(doubles)
[1, 5, 9]
['ss', 'pp', 'aa', 'mm']
# 使用列表解析生成九九乘法表
print('\n'.join([''.join(['%d*%d=%-4d'%(y,x,x*y) for y in range(1,x+1)])for x in range(1,10)]))
1*1=1   
1*2=2   2*2=4   
1*3=3   2*3=6   3*3=9   
1*4=4   2*4=8   3*4=12  4*4=16  
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25  
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36  
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49  
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64  
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81  

在最近的Python版本中,括号中的解析语法可以用来创建产生所需结果的生成器:

M=[[1,2,3],
   [4,5,6],
   [7,8,9]]

# Create a generator of row sums
G=(sum(row) for row in M)
for i in range(0,len(M)):
    print(next(G))
6
15
24
# Map sum over items in M
for i in range(0,len(M)):
    print(list(map(sum,M))[i])
6
15
24

在Python3.0中,解析语法也可以用来创建集合和字典:

# Create a set of row sums
print({
     sum(row) for row in M})
# Create key/value table of row sums
print({
     i+1:sum(M[i]) for i in range(3)})
{24, 6, 15}
{1: 6, 2: 15, 3: 24}

字典

Python中的字典是完全不同的东西,它们不是序列,而是一种映射(mapping)。映射是一个其他对象的集合,但是它们通过键而不是相对位置来存储。

字典是Python核心对象集合中唯一的一种映射类型,也具有可变性——可以就地改变,并可以随需求增大或减小,就像列表那样。


映射操作

作为常量编写时,字典编写在大括号中,并包含一些列的“键:值”对。

在我们需要将键与一系列值相关联(例如为了表述某物的某属性)的时候,字典是很有用的。

D={
     'food':'Spam','quantity':4,'color':'pink'}
print(D)
{'food': 'Spam', 'quantity': 4, 'color': 'pink'}

我们可以通过键对这个字典进行索引来读取或改变键所关联的值。字典的索引操作使用的是和序列相同的语法,但是在方括号中的元素是键,而不是相对位置。

print(D['food'])
print(D['quantity'])
Spam
4
# 对键对应的值进行修改
D['quantity']+=1
print(D)
{'food': 'Spam', 'quantity': 5, 'color': 'pink'}
# 另一种创建字典的方法
D={
     }
D['name']='Bob'
D['job']='dev'
D['age']=40
print(D)
print(D['name'])
{'name': 'Bob', 'job': 'dev', 'age': 40}
Bob

重访嵌套

rec={
     
    'name':{
     
        'first':'Bob','last':'Smith'
    },
    'job':['dev','mgr'],
    'age':40.5
}
print(rec)
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr'], 'age': 40.5}
print(rec['name'])
print(rec['name']['last'])
print(rec['job'])
print(rec['job'][-1]) #'job'的值是一个列表,可以用偏移量来索引
rec['job'].append('janitor')
print(rec)
{'first': 'Bob', 'last': 'Smith'}
Smith
['dev', 'mgr']
mgr
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr', 'janitor'], 'age': 40.5}

在Python中,当最后一次引用对象后(例如,将这个变量的其他的值进行赋值),这个对象所占用的内存空间将会自动清理掉。

rec=0 # Now the objcet is reclaimed

从技术来说,Pyhton具有一种叫做垃圾收集的特性,在程序运行时可以清理不再使用的内存,并将你从必须管理代码中这样的细节中解放出来。在Python中,一旦一个对象的最后一次引用被移除,空间将会立即回收。


键的排序:for循环

作为映射,字典仅支持通过键获取元素。尽管这样,在各种常见的应用场合,通过调用方法,它们也支持类型特定的操作。

字典不是序列,它们并不包含任何可靠的从左到右的顺序。者意味着如果我们建立一个字典,并将它打印出来,它的键也许会以与我们输入时不同的顺序出现:

D={
     'a':1,'b':2,'c':3}
print(D)
{'a': 1, 'b': 2, 'c': 3}

当确实需要以某种顺序进行排列时,一种常用的解决方法就是通过字典的keys方法收集一个键的列表,使用列表的sort方法或reverse方法进行排序,然后使用Python的for循环逐个进行展示结果。

Ks=list(D.keys())
print(Ks)
Ks.reverse()
print(Ks)
for key in Ks:
    print(key,'=>',D[key])
['a', 'b', 'c']
['c', 'b', 'a']
c => 3
b => 2
a => 1

上面的方法包含了三个步骤,然而在最近的版本中,可以通过使用最新的sorted内置函数以一步完成。sorted调用返回结果并对各种对象类型进行排序。

for key in sorted(D):
    print(key,'=>',D[key])
for key in sorted(D,reverse=1):
    print(key,'=>',D[key])
a => 1
b => 2
c => 3
c => 3
b => 2
a => 1

迭代和优化

Python中的一个主要的原则就是,首先为了简单和可读性去编写代码,在程序可以工作,并证明了确实有必要考虑性能后,再考虑该问题。更多的情况是代码本身就已经足够快了。如果确实需要提高代码的性能,那么Python提供了帮助你实现的工具,包括time以及timeit模块和profile模块。


不存在的键:if测试

继续学习之前还有另外一个要点:尽管我们能够通过给新的键赋值来扩展字典,但是获取一个不存在的键值仍然是一个错误。

print(D)
D['e']=99
print(D)
print(D['f']) # Referencing a nonexistent key is an error
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'b': 2, 'c': 3, 'e': 99}



---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

 in ()
      2 D['e']=99
      3 print(D)
----> 4 print(D['f']) # Referencing a nonexistent key is an error


KeyError: 'f'

但是在一些通用程序中,我们编写程序是并不总是知道当前存在什么键。在这种情况下,我们如何处理并避免这种错误发生呢?一个技巧就是首先进行测试。in关系表达式允许我们查询字典中一个键是否存在,并可以通过使用Python的if语句对结果进行分支处理(就像for一样)。

print('f' in D)
if not 'f' in D :
    print('missing')
False
missing

这里有其他的方法来创建字典并避免获取不存在的字典键:get方法(带有一个默认值的条件索引)、Python2.x的has_key方法(Py3.0中不可用)、try语句(一个捕获异常并从异常终回复的工具,第10章中会介绍)、以及if/else表达式。

下面是一些例子:

D={
     'a':123,'v':456}
value=D.get('x','null') # Index but with a default
print(value)
value=D['x'] if 'x' in D else 1 # if/else expression form
# Turns out even though we used get() earlier,it still not in D 
print(value)
null
1

元组

元组对象(tuple)基本基本类型就像一个不可改变的列表,即元组具有不可变性,和字符串类似。

元组支持任意类型、任意嵌套以及常见的序列操作:

T=(1,2,3,4)
len(T)
4
T+(5,6)
(1, 2, 3, 4, 5, 6)
T[0]
1

Py3.0中,元组还有两个专有的可调用的方法,但它的专有方法不像列表所拥有的那么多:

print(T.index(4)) # Tuple methodes: 4 appears at offset 3
print(T.count(4)) # 4 appears once
3
1
T=('samp',3.0,[11,22,33])
print(T[1])
print(T[2][1])
print(T.append(4)) # AttributeError:'tuple' object has no attribute 'append'
3.0
22



---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

 in ()
      2 print(T[1])
      3 print(T[2][1])
----> 4 print(T.append(4)) #


AttributeError: 'tuple' object has no attribute 'append'
dir(tuple)

元组拆包和具名元组

# 把元组作记录
xiaoming,xiaohua=(16,18)
print(xiaohua)
print(type(xiaoming))
students_info=[('xiaoming',16),('xiaohua',18),('lilie',20)]
for student in students_info:
    print('%s is %d years old.'%student)
18

xiaoming is 16 years old.
xiaohua is 18 years old.
lilie is 20 years old.

以上循环就是元组的拆包实例,实际上,元组的拆包可以运用到任何的迭代中去,唯一的硬性要求就是,被可迭代对象中宏的元素数量必须要跟接收这些元素的元组的空挡数一致,除非用*来表示忽略多余的元素。

为什么要使用元组

元组在实际中往往并不像列表这样常用,但是它的关键是不可变性。如果在程序中以列表的形式传递一个对象的集合,它可能在任何地方改变;如果使用元组的话,则不能。也就是说,元组提供了一种完整的约束,这对于比我们这里所编写的更大型的程序来说是方便的。

元组和列表的对比

区别 元组 列表
可变性 不可变 可变
方法 仅有两个 多,具有极强的灵活性

文件

文件对象是Python代码对电脑上外部文件的主要接口。虽然文件时核心类型,但是它有些特殊:没有特定的常量语法创建文件。要创建一个文件对象,需要调用内置的open函数以字符串的形式传递给它一个外部的文件名以及一个处理模式的字符串。

例如,创建一个文本输出文件,可以传递其文件名以及‘w’处理模式字符串以写数据:

f=open('data.text','w') # Make a new file in output mode
f.write('Hello\n') # Write strings of bytes to it
f.write('World\n')
f.close() # Close to flush output buffers to disk

这样,就在当前文件夹下创建了一个文件,并向它写入文本(文件名可以是完整的路径,如果需要读取电脑上其他位置的文件的话)。

为了读出刚才缩写的内容,重新以‘r’处理模式打开文件,读取输入(如果在调用时忽略模式的话,这将是默认的)。之后将文件的内容读至一个字符串,并显示它。对脚本而言,文件的内容总是字符串,无论文件包含的数据时什么类型:

f=open('data.text')
text=f.read()
print(text)
text.split() # File content is always a string
Hello
World






['Hello', 'World']

读取文件的最佳方式

如今读取文件的最佳方式就是根本不读它,文件提供了一个迭代器(iterator),它在for循环或其他环境中自动地一行一行地读取。(具体的内容将在以后的章节学习)

其他文件类工具

open函数能够实现在Python中白那些绝大多数文件处理。尽管这样,对于更高级的任务,Python还有额外的类文件工具:管道、先进先出队列、套接字、通过键访问文件、对象持久、基于描述符的文件、关系数据库和面向对象数据库接口等。

其他核心类型

集合是最近增加到这门语言中的类型,它不是映射也不是序列,相反,它们是唯一的不可变的对象的无序集合。集合可以通过调用内置函数set而创建,或者是使用Python3.0中新的集合常量和表达式创建,并且它支持一般的数学集合操作(Pyhton3.0中新的用于集合常量的{…}语法是有意义的,因为集合更像是一个无值的字典的键):

X=set('spam')
Y={
     'h','a','m'}
print(X)
print(Y)
{'a', 'p', 'm', 's'}
{'h', 'a', 'm'}

集合

集合的专有运算

# 交(&)运算
print(X&Y)
{'a', 'm'}
# 并(|)运算
print(X|Y)
{'h', 'p', 'a', 'm', 's'}
# 相对减(-)运算
print(X-Y)
print(Y-X)
{'p', 's'}
{'h'}
# 对称差分(^)运算
print(X^Y)
{'h', 'p', 's'}

集合的解析

{
     x** 2 for x in [1,2,3,4]}
{1, 4, 9, 16}

新的数值类型

十进制数和分数

Python最近新添加了一些数值类型:十进制数(固定精度浮点数)和分数(有一个分子和分母的有理数)。它们都用来解决浮点数学的局限性和内在的不精确性:

# 普通情况下进行运算
print(1/3)
print((2/3)+(1/2))
0.3333333333333333
1.1666666666666665
decimal模块

decimal模块提供了一个Decimal数据类型用于浮点数计算。相比内置的二进制浮点数实现float这个类型有助于金融应用和其它需要精确十进制表达的场合,控制精度,控制舍入,确保十进制数位精度,或者用户希望计算结果与手算相符的场合。Decimal重现了手工的数学运算,这就确保了二进制浮点数无法精确保有的数据精度。高精度使Decimal可以执行二进制浮点数无法进行的模运算和等值测试。

import decimal
d=decimal.Decimal('3.141')
d+1
Decimal('4.141')
decimal.getcontext().prec #默认全局精度为28位小数
28
decimal.getcontext().prec=2# 设置全局精度为2个小数位
print(decimal.getcontext().prec)
decimal.Decimal('1.00')/decimal.Decimal('3.00')
2





Decimal('0.33')
fractions模块

分子分母模块

from fractions import Fraction
f=Fraction(2,3) #(分子,分母)
f+1
Fraction(5, 3)
f+Fraction(1,2)
Fraction(7, 6)

布尔值

Python最近还添加了布尔值(预定义的True和False对象实际上是定制后以逻辑结果显示的整数1和0),以及长期以来一直支持的特殊的占位符对象None(它通常用来初始化名字和对象):

1>2,1<2
(False, True)
bool('spam')
True
X=None
print(X)
None
L=[None]*100 # Initialize a list of 100 Nones
L

用户定义的类

类的详细内容将会在第六章深入讲解,这里给出一个例子以供提前感受:

class Worker:
    def __init__(self,name,pay):
        self.name=name
        self.pay=pay
    def lastName(self):
        return self.name.split()[-1]
    def geveRaise(self,percent):
        self.pay *= (1.0+percent)

bob=Worker('Bob Smith',500000)
sue=Worker('Sue Jones',600000)
print(bob.lastName())
print(sue.lastName())
sue.geveRaise(0.10)
print(sue.pay)
Smith
Jones
660000.0

Chap05 数字和集合

在Python中,数据采用了对象的形式——无论是Python所提供的内置对象,还是使用Python的工具和像C这样的其他语言所创建的对象。

编写的所有Python程序的基础就是对象,因为对象是Python编程中的最基本的概念


Python的数字类型

Python数字类型的完整工具包括:

  • 整数和浮点数
  • 复数
  • 固定精度的十进制数
  • 有理分数
  • 集合
  • 布尔类型
  • 无穷的整数精度
  • 各种数字内置函数和模块

数字常量

基本类型中Python提供了:整数(正、负)和浮点数。

Python还允许使用十六进制、八进制、二进制常量来表示整数,提供了一个复数类型并允许整数具有无穷的精度(只要内存空间允许)。

八进制→以0o或0O开头

十六进制→以0x或0X开头

二进制→以0b或0B开头

复数常量→a+bj的形式

整数和浮点数常量

如果编写一个带有小数点或者幂的数字,Python会将它变成一个浮点数对象,并且当这个对象在表达式中时,将启动浮点数(而不是整数)的运算法则。

Python3.0中的整数:一个单独的类型

在Python3.0中,一般整数和长整数类型已经合二为一了,只有整数这一种,它自动地支持Python2.6的单独的长整数类型所拥有的无穷精度。因此整数在程序中将不再使用末尾的l或L来表示,并且整数也不会再显示出这个字符。

十六进制数、八进制和二进制常量

十六进制:以0x或0X开头,后接0-9,A-F,其大小写都可以。

八进制:以0O或0o开头(2.6中可以0开头,3.0及以后不行),后接数字0-7构成的字符串。

二进制:以0b或0B开头,后接二进制数字。

复数

复数常量写成实部+虚部的形式,以j或J结尾。从内部看来,复数都是通过一对浮点数来表示的,但是对复数的所有的数字操作都会按照复数的运算法则进行。也可以通过内置函数complex(real,imag)来创建复数。

编写其它的数字类型

python中还有以上没提到的数字类型,后续会提到


内置数学工具和扩展

表达式操作符及程序 说明
yield x 生成器函数发送协议
lambda args:expression 生成匿名函数
x if y else z 三元选择表达式
x or y 逻辑或(只有x为假,才会计算y)
x and y 逻辑与(只有x为真,才会计算y)
not x 逻辑非
x jin y,x not in y 成员关系(可迭代对象、集合)
x is y,x is not y 对象实体测试
xy,x>=y,x==y,x!=y 大小比较,集合子集和超集值相等性操作符
x|y 位或,集合并集
x^y 位异或,集合对称差
x&y 位与,集合交集
x<>y 左移或右移y位
x+y,x-y 加法/合并,减法,集合差集
x*y,x%y,x/y,x//y 乘法/重复,余数/格式化,除法:真除法或floor除法
-x,+x 一元减法,识别
~x 按位求补(取反)
x**y 幂运算
x[i] 索引(序列、映射及其它)点号取属性运算,函数调用
x[i:j:k] 分片
x.attr 属性引用
(…) 元组、表达式、生成器表达式
[…] 列表,列表解析
{…} 字典、集合、集合和字典解析
  • 以上操作符越靠后的优先级越高
  • 以上操作符位于同一行的变道时再组合的时候通常从左到右组合(除了幂运算,它时从右到左组合的,还有比较运算,是从左到右链接的)
  • 用括号包围的子表达式拥有最高优先级
  • 混合类型会自动升级为最复杂的数据类型,但仅仅在数字类型的混合中才适用
  • Python操作符可以通过Python的类或C扩展类型被重载(即实现)
  • 关于重载操作符,Python自身自动重载了某些操作符,能够根据所处理的内置对象的类型而执行不同的操作。这种特性通常称作多态。
内置数学函数名称 说明
公用模块名称 说明

尽管数字主要通过表达式、内置函数和模块来处理,它们如今也拥有很多特定于类型的方法,后续都会介绍到。如:浮点数拥有一个as_integer_ratio方法,它对于分数数字类型很有用;还有一个is_integer方法可以测试数字是否是一个整数。此外,集合既像一些集合一一昂也像一些数字一样,它支持者两者的方法和表达式。


在实际应用中的数字

变量和基本的表达式

在Python中:

  • 变量在它第一次赋值时创建。
  • 变量在表达式中使用将被替换为它们的值。
  • 变量在表达式中使用以前必须已赋值。
  • 变量像对象一样不需要在一开始进行声明。

在Python中,变量并不需要预先声明,但是在使用之前,至少要赋一次值。实际上,这意味着在对其进行加法运算时要计数器初始化为0,在列表后添加元素前,要首先初始化列表为一个空列表。

数字显示的格式

除了print和自动回显外,还有很多种方法显示计算机中的数字的位数:

num=1/3.0
print('%e'%num)
print('%4.2f'%num)
print('{0:4.2f}'.format(num))
3.333333e-01
0.33
0.33
str和repr显示格式

从技术上来说,默认的交互模式回显和打印的区别就相当于repr和str函数的区别。

这两个函数都会把任意对象变换成它们的字符串表示:repr(也就是默认的交互模式回显)产生的结果看起俩就好像它们是代码。str(也就是打印语句)转变为一种通常对用户更加友好的格式。一些对象两种方式都有:str用于一般用途,repr用于额外细节。这个概念将会为我们学习字符串以及类中的运算符重载做好铺垫,并且稍后会介绍这些内置函数的更多内容。

比较:一般的和连续的

一般的比较就像我们所期待的那样对数字起作用,它们比较操作数的相对大小,并且返回一个布尔类型的记过。

有趣的时,Python还允许我们把多个比较连续起来执行范围测试。连续的比较是更大的布尔表达式的缩写。加你而言之,Python允许我们把大小比较测试连接起来,成为诸如范围测试的连续比较。例如:表达式(A


X=2
Y=4
Z=6
X<Y<Z
True
1==2<3 # Same as:1==2 and 2<3
        # Not same as:False<3(which means 0<3,which is true)
False

除法:传统除法、Floor除法和真除法

有3种类型的除栓,有两种不同的除注操作符,其中一种操作符在Python 3.0中有了变化.

x/y:传统除法和真除法。在Python3.0版本中将会变成真除法(无论任何类型都会保持小数部分)。

x//y:Floor除法。这个操作不考虑操作对象的类型,总是会省略结果的小数部分,剩下最小的能整除的整数部分。

  • 在Python 3.0中, /现在总是执行真除法,不管操作数的类型,都返回包含任何余数的一个结果。//执行Floor除法,它截除掉余数并且针对整数操作数返回一个整数,如果有任何一个操作数是浮点类型,则返回一个浮点数。
  • 在Python 2.6中, /表示传统除怯,如果两个操作数都是整数的话,执行截断的整数 除法;否则,执行浮点除注(保留余数) 0 //执行Floor除法,并且像在Python 3中一样工作,对于整数执行截断除法,对于浮点数执行浮点除法。

注意,在Python3.0中,//的结果的数据类型总是以来操作数的类型:如果操作数中有一个是浮点数,结果就是浮点数;否则,结果是一个整数。此外,//作为向后兼容工具的一部分而提供,对于整数类型,它必须返回整数。

支持两个版本

/和//在2.6和3.0两个版本中都能使用

Floor除法VS截断除法

一个细微之处在于 : //操作符通常叫做截断除法,但是,更准确的说法是fLoor除法,它把结果向下截断到它的下层,真正结果之下的最近的整数。其直接效果是向下舍入,并不是严格地截断,并且这对负数也有效。你可以使用Python的math模块来自己查看其中的区别 (在使用模块中的内容之前,必须先导入模块;随后将更详细地介绍这些内容):

3.00//2
1.0
3//2
1
import math
math.floor(2.5)
2
math.floor(-2.5)
-3
math.trunc(2.5) # 直接去尾
2
math.trunc(-2.5)
-2

如果真的想要截断而不管符号,可以总是通过math.trunc来得到一个浮点除法结果,而不管是什么Python版本。

为什么截断很重要

因为C语言的遗留原有,很多程序员依赖于整数的截断除法,因此他们必须学习在这样的环境中使用//。


整数精度

Python3.0中将普通整数和长整数进行了合并,因此不需要再长整数的末尾加L,此外还可以使用无穷大整数(只要计算机内存足够大的话)。

复数

复数表示为两个浮点数(实部和虚部)并接再虚部增加了j或J的后缀。我们可以把非零实部的复数写成由+连接起来的两部分。下面是复数的一些运算的例子:

1j*1J
(-1+0j)
2+1j*3
(2+3j)
(2+1j)*3
(6+3j)

复数允许我们分解出它的实部和虚部作为属性,并支持所有一般的数学表达式,并且可以通过标准的cmath模块(复数版的标准数学模块)中的工具进行处理。复数通常在面向工程的程序中扮演重要的角色。它是高级的工具,查看Python语言的参考手册来获取更多的信息。

十六进制、八进制和二进制记数

Python默认使用十进制整数来显示其它的进制数:

0o1,0o20,0o377
(1, 16, 255)
0x01,0x10,0xFF
(1, 16, 255)
0b1,0b10000,0b11111111
(1, 16, 255)

但Python同时也提供了内置函数,允许我们把整数转换为其它进制的数字字符串:

oct(64),hex(64),bin(64)
('0o100', '0x40', '0b1000000')

另一种方式,内置的int函数会将一个数字的字符串变换成为一个整数,并可以通过定义的第二个参数来确定变换后的数字的进制:

int('64'),int('100',8),int('40',16),int('1000000',2)
(64, 64, 64, 64)
int('0x40',16),int('0b1000000',2)
(64, 64)

稍后介绍的eval函数也可以将字符串作为Python代码,具有以上和int类似的效果(但往往运行得更慢:它实际上会作为程序的一个片段编译并运行这个字符串,并且它假设你能够信任运行的字符串的来源)。

最后,还能够使用字符串格式化方法调用和表达式将一个整数转换成八进制和十六进制的字符串:

print('{0:o},{1:x},{2:b}'.format(64,64,64))
print('%o,%x,%X'%(64,255,255))
100,40,1000000
100,ff,FF

位操作

  • 按位与(&):比较两个数,返回一个新的数,这个数的每位取1的条件是比较的两个数对应位都为1.
  • 按位或(|):比较两个数,返回一个新的数,这个数的每位取1的条件是比较的两个数对应位至少有一个位1.
  • 按位异或(^):比较两个数,返回一个新的数,这个数的每位取1的条件是比较的两个数对应位的数不相同,若相同(同为0或同为1)则置为0.
  • 取反(~):对一个数进行操作,返回一个新的数,这个数的每位和被操作数的每位相反.
  • 按位左移(<<):将操作数的每位向左移动指定位数
  • 按位右移(>>):将操作数的每位向右移动指定位数

其他的内置数学工具

除了核心对象类型以外,Python还支持用于数字处理的内置函数和内置模块(如math、random模块)。例如:内置函数pow和abs,分别计算幂和绝对值。

其他数字类型

小数数字

小数是通过一个导入的模块调用函数后创建的,而不是通过运行常量表达式创建的。从功能上来说,小数对象就像浮点数,只不过它们有固定的位数和小数点,因此小数是有固定的精度的浮点值。

使用了小数对象,我们能够使用一个只保留两位小数位精度的浮点数。此外,我们能够定义如何省略和截断额外的小数数字。尽管它对平时的浮点数类型来说带来了微笑的性能损失,小数类型对表现固定精度的特性(例如,钱的总和)以及对实现更好的数字精度是一个理想的工具。

基础知识

我们能够通过调用decimal模块中的Decimal的构造函数创建一个小数对象,并传入一个字符串,这个字符串有我们希望再结果中显示的小数位数。当不同精度的小数再表达式中混编时,Python自动升级位小数位数最多的:

from decimal import Decimal
Decimal('.1')+Decimal('.1')+Decimal('.1')-Decimal('.3')
Decimal('0.0')
Decimal('.1')+Decimal('.10')+Decimal('.100')-Decimal('.3')
Decimal('0.000')
#在Python3.1中及以后,能够从一个浮点对象创建一个小数对象,通过decimal.Decimal.from_float(1.25)的形式调用,这一转换是精确的,但是有时候会产生较多的位数

f=1.25
Decimal.from_float(f)
Decimal('1.25')
设置全局精度

decimal模块中的其他工具可以用来设置所有小数数值的精度、设置错误处理等。例如,这个模块中的一个上下文对象允许指定精度(小数位数)和舍入模式(舍去、进位等)。该精度全局性地适用于调用线程中创建的所有小数:

import decimal
decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
decimal.getcontext().prec=4
decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1429')

这对于处理货币的应用程序特别有用,其中,美分表示为两个小数位数。在这个上下文里,小数实际上是手动舍入和字符串格式化的一种替代方式:

1999+1.33
2000.33
decimal.getcontext().prec=2
pay=decimal.Decimal(str(1999+1.33))
pay
Decimal('2000.33')
小数上下文管理器

可以使用上下文管理器来重新设置临时精度。在语句退出后,精度又重新设置为初始值:

import decimal
decimal.Decimal('1.00')/decimal.Decimal('3.00')
Decimal('0.33')
with decimal.localcontext() as ctx:
    ctx.prec=3
    print(decimal.Decimal('1.00')/decimal.Decimal('3.00'))
0.333
decimal.Decimal('1.00')/decimal.Decimal('3.00')
Decimal('0.33')

分数类型

分数类型,实现了一个有理数对象。它明确地保留一个分子和一个分母,从而避免了浮点数学的某些不精确性和局限性。

基本知识

分数是前面小节所介绍的已有的小数固定精度类型的"近亲",它们都可以通过固定小数位数和指定舍入或截断策略来控制数值精度。分数以类似于小数的方式使用,它也存在于模块中导入其构造函数并传递一个分子和一个分母就可以产生一个分数。下面的交互式例子展示了如何做到这一点:

from fractions import  Fraction
x=Fraction(7,3)
y=Fraction(1,7)
sum=x+y
d=sum.denominator
n=sum.numerator
if n>d:
    integer=n//d
    n-=integer*d
    print('%d %d/%d'%(integer,n,d))
else:
    print('%d/%d'%(n,d))
2 10/21

分数对象也可以从浮点数字符串来创建,这和小数很相似:

Fraction('.25')
Fraction(1, 4)
Fraction('1.25')
Fraction(5, 4)
Fraction('.25')+Fraction('1.25')
Fraction(3, 2)
数值精度

注意,这和浮点数类型的数学有所区别,那是受到浮点数硬件的底层限制的约束。相比较而言,这里与对浮点数对象执行的操作时相同的,注意它们有限的精度:

a=1/3.0
b=4/6.0
a,b 
(0.3333333333333333, 0.6666666666666666)

分数保持精确性,并且自动简化结果。

Fraction(6,12)
Fraction(1, 2)
转换和混合类型

为了支持分数转换,浮点数对象现在有一个方法,能够产生它们的分子和分母比,分数 有一个from_float方法,并且float接受一个Fraction作为参数。跟踪如下的交互看看这 是如何做到的:

(2.5).as_integer_ratio() # float object method
                         # a tuple
(5, 2)
f=2.5
z=Fraction(*f.as_integer_ratio()) # Convert float->fraction:two args
z 
Fraction(5, 2)
Fraction.from_float(1.75)
Fraction(7, 4)
Fraction(*(1.75).as_integer_ratio())
Fraction(7, 4)

警告:尽管可以把浮点数转换为分数,在某些情况下,这么做的时候会有不可避免的精度损失,因为这个数字在其最初的浮点形式下是不精确的。当需要的时候,我们可以通过限制最大分母值来简化这样的结果:

(4.0/3).as_integer_ratio()
(6004799503160661, 4503599627370496)
x
Fraction(1, 3)
a=x+Fraction(*(4.0/3).as_integer_ratio()) # 本应该是(5,3)
a
Fraction(22517998136852479, 13510798882111488)
22517998136852479/13510798882111488
1.6666666666666665
a.limit_denominator(2)
Fraction(3, 2)

集合

Python 2.4引入了一种新的类型——集合 (set) ,这是唯一的、不可变的对象的一个无序集合 (collection) ,这些对象支持与数学集合理论相对应的操作。根据定义, 一个项在集合中只能出现一次,不管将它添加了多少次。同样,集合有着广泛的应用,尤 其是在涉及数字和数据库的工作中。

因为它是其他对象的集合,因此,它具有列表和字典这样的对象的某些共同行为。

我们将会看到,一个集合的行为很像一个无值的字典的键,但是,它还支持额外的操作。

然而,由于集合是无序的,并且不会把键匹配到值,它们既不是序列也不是映射类型, 它们是自成一体的类型。此外,由于集合本质上具有基本的数学特性(它对于很多读者来说,可能更加学院派,并且比像字典这样更为普遍的对象用得要少很多),在这里,我们将介绍Python的集合对象的基本工具。

集合基础知识

集合的创建

x=set('abcde')
y=set('dgefz')
x 
{'a', 'b', 'c', 'd', 'e'}
y 
{'d', 'e', 'f', 'g', 'z'}

集合的运算

'e' in x
True
x-y
{'a', 'b', 'c'}
x|y
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'z'}
x&y 
{'d', 'e'}
x^y 
{'a', 'b', 'c', 'f', 'g', 'z'}
x>y,x<y # superset,subset
(False, False)

集合对象的相关操作方法

# add方法插入一个项目
# update方法按位置求并集
# remove方法根据值删除一个项目
# 在任何集合实例或者集合类型名上运行dir来查看所有可用的方法
z=x.intersection(y) # same as x&y
z 
{'d', 'e'}
z.add('spam') #注意是整个字符串作为一个项目加入到集合中
z
{'d', 'e', 'spam'}
z.update('spam') # obj in update() always a set type
z
{'a', 'd', 'e', 'm', 'p', 's', 'spam'}
z.update(set(['X','Y']))
z
{'X', 'Y', 'a', 'd', 'e', 'm', 'p', 's', 'spam'}

作为可迭代的容器,集合也可以用于len、for循环和列表解析这样的操作中。然而,由于它们都是无序的,所以不支持像索引和分片这样的操作。

for item in z :
    print((item+' ')*3)
a a a 
p p p 
s s s 
Y Y Y 
m m m 
d d d 
e e e 
spam spam spam 
X X X 

集合的表达式操作需要两个集合,但是集合的方法操作对任何可迭代的类型都有效

s=set([1,2,3])
s|set([3,4])
{1, 2, 3, 4}
s|[3,4] # error
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
----> 1 s|[3,4] # error


TypeError: unsupported operand type(s) for |: 'set' and 'list'
s.union([3,4]) # set methods allow any iterable
{1, 2, 3, 4}
s.intersection((1,3,5))
{1, 3}
s.issubset(range(-5,5))  #判断s是否为range(-5,5)的子集
True

Python3.0及以上可以用为字典所保留的花括号来创建。这样的语法是有意义的,因为集合基本上就像是无值的字典,集合的项时候无序的、唯一的、不可改变的,因此,它们的行为和字典的键很像。由于字典键列表在Python3.0中式视图对象,它支持像交集和并集这样的类似集合的行为,这种相似性甚至更加惊人。

s={
     1,2,3,4}
s
{1, 2, 3, 4}

Python中{}仍然是一个字典。

type({
     })
dict

不可变限制和冻结集合

集合是很强大而灵活的对象,但是它们在Python3.0和2.6中都有一个限制,我们需要铭记,很大程度上是由于其实现,集合智能包含不可变的(即可散列的)对象类型。因此,列表和字典不能嵌入到集合中,但是,如果你需要存储复合值的话,元组是可以嵌入的

s ={
     1,2,3,4}
s
{1, 2, 3, 4}
s.add((5,6,7))
s
{(5, 6, 7), 1, 2, 3, 4}
s|{
     (5,6,7),(1,2,3)}
{(1, 2, 3), (5, 6, 7), 1, 2, 3, 4}
(1,2,3) in s 
False
(5,6,7) in s 
True

Python3.0中集合的解析

除了常量,Python3.0还引入了一个集合解析构造,它类似于我们在第4章中介绍过的列表解析的形式,但是,编写在花括号中而不是方括号中,并且作用于集合而不是列表。

集合解析运行一个循环并在每次迭代时收集一个表达式的结果,通过一个循环变量来访问当前的迭代之以用于集合表达式中。结果是通过运行代码创建的一个新的集合,它具备所有一般的集合行为:

{
     x ** 2 for x in (1,2,3,4)}
{1, 4, 9, 16}
{
     'spam'}
{'spam'}
{
     x for x in 'spam'}
{'a', 'm', 'p', 's'}
{
     x * 2 for x in 'spam'}
{'aa', 'mm', 'pp', 'ss'}

当然关于解析的知识还不止这些,只是局限于当前所学,更底层的概念将在后续的章节中介绍。

为什么使用集合

集合操作有各种各样常见的用途,其中一些比数学更加实用。例如,由于项在集合中只能存储一次,集合(set)可以用来把重复项从其他集合(collection)中过滤掉。直接把集合(collection)转换为一个集合(set),然后再转换回来即可(因为集合是可迭代的,这里的list调用对其有效):

L=[1,2,3,4,1,2,3,5,6]
set(L)
{1, 2, 3, 4, 5, 6}
L=list(set(L))
L
[1, 2, 3, 4, 5, 6]

当遍历图形或其他的回环结构的时候,集合可以用来记录已经访问过的位置。

最后,在处理较大的数据集合的时候(例如,数据库查询结果),两个集合的交集包含了两个领域中共有的对象,并集包含了两个集合中的所有项目。为了说明,这里给出了集合操作的一些实际例子,这些操作应用于一个假定公司的人员的名单,使用Python3.0集合常量:

engineers={
     'bob','sue','ann','vic'}
managers={
     'tom','sue'}
'bob' in engineers
True
engineers & managers
{'sue'}

布尔型

Python如今正式地有了一种明确的布尔型数据类型,叫做bool。其值为True和False。并且其值True和False是预先定义的内置的变量名。在内部,新的变量名True和False是bool的实例, 实际上仅仅是内置的整数类型int的子类(以面向对象的观点来看)。True和False的行为和整数l和0是一样的, 除了它们有特定的显示逻辑:它们是作为关键 字True和False显示的,而不是数字1和0(从技术上来讲,bool为它的两个对象重新定义了str和repr的字符串格式)。

由于这个定制,布尔表达式在交互提示模式的输出就作为关键字True和False来显示,而不是曾经的1和0。此外,布尔型让真值更精确。例如,一个无限循环现在能够编写成 while True:而不是while 1:。类似地,通过使用f1ag=False。可以更清楚地设置标志位。

Chap06 动态类型简介


缺少类型声明语句的情况

在Python中,类型是在运行过程中自动决定的,而不是通过代码声明。这意味着没有必要事先声明变量 (只要记住,这个概念实质上对变量、对象和它们之间的关系都适用,那么这个概念也就很容易理解并掌握了)。

变量、对象和引用

变量在赋值的时候才创建,它可以引用任何类型的对象,并且必须在引用之前赋值。这意味着,不需要通过脚本声明所要使用的名字,但是,必须初始化名字然后才能更新它们。例如必须把计数器初始化为0,然后才能增加它。

刚入门时,如果清楚地将变量名和对象划分开来,动态类型是很容易理解的。

类型属于对象,而不是变量

【主要内容如题】

对象的垃圾收集

在Python中,每当一个变量名被赋予了一个新的对象,之前的那个对象占用的空间就会被回收,这种自动回收对象空间的技术叫做垃圾收集。

在内部,Python是这样来实现这一功能的:它在每个对象中保持了一个计数器,计数器记录了当前指向该对象的引用的数目。一但(并精确在同一时|司)这个计数器被设置为零,这个对象的内存空间就会自动回收。

了解更多内容,参考Python库手册中的gc模块的文档。

共享引用

共享引用——多个变量名引用了同一个对象。

对于“不可变的类型”,修改其对象不会对共享引用的其他对象产生影响:

a=3
b=a
a=a+2
print(b)
3

如上,虽然b和a共享了对象3,但改变a的同时并不会改变b,这是因为b指向的是对象3,而3是整数对象是不可变的,因此对a的操作并不会影响到b的指向。

共享引用和在原处修改

原处修改:例如,在一个列表中对一个偏移进行赋值确实会改变这个列表对象,而不是生成一个新的列表对象。

对于支持这种在原处修改的对象,共享引用时的确需要加倍的小心, 因为对一个变量名的修改会影响其他的变量。

L1=[2,3,4]
L2=L1
L1[0]=24
print(L1)
print(L2)
[24, 3, 4]
[24, 3, 4]
# 拓展一个copy方法
import copy
y={
     
    'name':{
     
        'first':'Bob','last':'Smith'
    },
    'job':['dev','mgr'],
    'age':40.5
}
x=copy.copy(y) # Make lop-Ievel "shallow" copy of any objecl Y 
print(x)
x=copy.deepcopy(y) # Make deep copy of ally objecl Y: copy allllesled parts 
print(x)
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr'], 'age': 40.5}
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr'], 'age': 40.5}

共享引用与相等

Python中有两种不同的方法去检查是否相等:

# == 测试两个被引用的对象是否有相同的值
# is 检查对象的同一性,如果两个变量名精确指向同一个对象,则返回True

L=[1,2,3]
M=L
print(L==M)
print(L is M)
M=[1,2,3]
print(L==M)
print(L is M)
True
True
True
False
# 拓展 sys.getrefcount方法 统计对象引用次数
import sys
sys.getrefcount(1)
2036

动态类型随处可见

在 Python中,任何东西看起来都是通过赋值和引用工作的,对这个模型的基本了解在不同的场合都是很有帮助的。

从最实际的角度来说,动态类型意味着你将写更少的代码。尽管这样,同等重要的是,动态类型也是Python中多态的根本。

Chap07 字符串

在Python中,字符串变成了一种强大的处理工具集,这一点与C语言不同。并且Python和像C这样的语言不一样,没有单个字符的这种类型,取而代之的是可以使用一个字符的字符串。

严格地说,Python的字符串被划分为不可变序列这一类别,意味着这些字符串所包含的字符存在从左至右的位置顺序,并且它们不可以在原处修改。实际上,字符串是我们将学习的从属于稍大一些的对象类别——序列的第一个代表。

以下是常见字符串常量和表达式:

操作 解释
s=’’ 空字符串
s=“spam’s” 双引号与单引号相同
S=‘s\np\ta\x00m’ 转义序列
s="""…""" 三重引号字符串块
s=r’\temp\spam’ Raw字符串
S=b’spam’ Python3.0中的字节字符串
s=u’spam’ 仅在Python2.6中使用的Unicode字符串
s1+s2,s*3 合并,重复
s[i],s[i:j] 索引,分片
len(s) 求长度
“a %s parrot”%kind 字符串格式化表达式
“a {0} parrot”.format(kind) Python2.6和3.0以上的 字符串格式化方法
s.find(‘pa’) 字符串方法调用:搜索
s.rstrip() 移除空格
s.replace(‘pa’,‘xx’) 替换
s.split(’,’) 用展位符分割
s.isdigit() 内容测试
s.lower() 短信息转换
S.endswith(‘spam’) 结束测试
‘spam’.join(strlist) 插入分隔符
S.encode(‘latin-1’) Unicode编码等
for x in S :print(x),‘spam’ in S,[c*2 for c in S],map(ord,S) 迭代,成员关系

字符串常量

Python没有字符会结束一个字符串。

raw字符串抑制转义

# 当尝试打开一个文件myflle = open('C:\new\text.dat', 'w') 时,会出现些问题,这是解决方法:
#myfile=open(r'C:\new\text.dat','w')
#myflle = open('C:\\new\\text.dat', 'w') 

除了在Windows下的文件夹路径. raw字符串也在正贝IJ表达式。

实际应用中的字符串

基本操作

in操作符和str.find()方法的区别:in返回的时一个布尔值,find则返回指定内容位于字符串的位置。

索引与分片

Python偏移量时从0开始的,而与C不同的是,Python还支持类似在字符串中使用负偏移量这样的方法从羞恶总获取元素。

S[:]实现了一个完全的顶层的序列对象的拷贝——一个有相同值,但是不同内存片区的对象。这个方法对于字符串这样的不可变序列并不是很有用,但对于可以在原地修改的对象来说却很实用,例如列表。

扩展分片

Ptyon2.3后增加了步进。

可以使用负步进,相当于反转序列:

S='abcdefghijklmnopqrstuvwxyz'
S[::-1]
'zyxwvutsrqponmlkjihgfedcba'

为什么要在意:分片

一个分片的典型应用:一个分片表达式能够返回除了第一项之外的所有元素的列表。

分片也常常用作清理输入文件的内容。如果知道一行将会以行终止字符 (\n换行字符标识)结束.你就能够通过一个简单的表达式,例如,line[:-1],把这行除去最后一个字符之外的所有内容提取出来。通常只在确定每一行都是以换行符结尾时使用。

字符串转换工具

在Python中,即使字符串内容看上去和数字十分相似,使用+合并两种不同类型也依然会报错。

因此需要使用转换工具对需要进行合并的数据进行预处理。

字符串代码转换

同样是转换,单个的字符也可以通过将其传给内置的ord函数转换为其对应的ASCII码——这个函数实际上返回的是这个字符在内存中对应的字符的二进制值。而chr函数将会执行相反的操作,获取ASCII码并将其转化为对应的字符:

ord('s')
115
chr(115)
's'

字符串方法

方法实例:修改字符串

除了使用+来合并或replace()方法外,介绍另外一种方式修改字符串:

S='spammy'
L=list(S)
L
['s', 'p', 'a', 'm', 'm', 'y']
L[3]='x'
L[4]='x'
L
['s', 'p', 'a', 'x', 'x', 'y']
S=''.join(L)
S
'spaxxy'

方法实例:文本解析

另外一个字符串常规角色是以简单的文本解析的形式出现的——分析结构并提取子串。为了提取固定偏移的子串,我们可以利用分片技术:

line='aaa bbb ccc'
col1=line[0:3]
col3=line[8:]
col1
'aaa'
col3
'ccc'

以上方法适用于有固定偏移量的字符串提取,而对于无固定偏移量的字符串提取,则使用split方法:

line='dasdSPAMasodifuSPAMdfaoeiSPAMdse'
cols=line.split('SPAM')
cols
['dasd', 'asodifu', 'dfaoei', 'dse']

字符串格式化表达式

*的使用

*可以用于指定通过计算得出width和precision:

'%f,%.2f,%.*f'%(1/3.0,1/3.0,4,1/3.0)
'0.333333,0.33,0.3333'

基于字典的字符串格式化

生成类似HTML和XML的程序往往利用这一技术。

直接通过举例来说明:

"%(n)d %(x)s"%{
     "n":1,"x":"spam"}
'1 spam'
reply="""
Greetings...
Hello %(name)s!
Your age squared is %(age)s
"""

values={
     'name':'Bob','age':'40'}
print(reply %values)
Greetings...
Hello Bob!
Your age squared is 40
# 与内置函数vars配合使用 
# 这个函数返回的字典包含了所有在本函数调用时存在的变量
food='spam'
age=40
vars()
"%(age)d %(food)s "%vars()
'40 spam '

字符串格式化调用方法

基础知识

# By position
template='{0},{1},{2}'
template.format('spam','ham','eggs')
'spam,ham,eggs'
# By keyword
template='{motto},{pork} and {food}'
template.format(motto='spam',pork='ham',food='eggs')
'spam,ham and eggs'
# By both
template='{motto},{0} and {food}'
template.format('ham', motto='spam',food='eggs')
'spam,ham and eggs'

就像%表达式和其他字符串方法一样,format创建并返回一个新的字符串对象,它可以立即打印或保存起来方便以后使用(别忘了,字符串是不可变的,因此,format必须创建一个新的对象)。

添加键、属性和偏移量

像%格式化表达式一样,格式化i周用可以变得更复杂以支持更多高级用途。

格式化字符串可以指定对象属性和字典键——就像在常规的Python语法中一样,方括号指定字典键,而点表示位置或关键字所引用的一项的对象属性。

import sys
'My {1[spam]} runs {0.platform}'.format(sys,{
     'spam':'laptop'})
'My laptop runs win32'
'My {config[spam]} runs {sys.platform}'.format(sys=sys,config={
     'spam':'laptop'})
'My laptop runs win32'

只有单个的正的偏移才能在格式化字符串的语放中有效。

和%表达式一样,要指定负的偏移或分片,或者使用任意表达式,必须在格式化字符串自身之外运行表达式:

somelist=list('SPAM')
somelist
['S', 'P', 'A', 'M']
'first ={0[0]},third={0[2]}'.format(somelist)
'first =S,third=A'
'first={0},last={1}'.format(somelist[0],somelist[-1])
'first=S,last=M'
parts=somelist[0],somelist[-1],somelist[1:3]
'first={0},last={1},middle={2}'.format(*parts)
"first=S,last=M,middle=['P', 'A']"

添加具体格式化

另一种和%表达式类似的是,可以在格式化字符串中添加额外的语站来实现更具体的层级。对于格式化方在去,我们在替缺目标的标识之后使用一个冒号,后面跟着可以指定字段大小、对齐方式和一个特定类型编码的格式化声明。如下是可以在一个格式字符串中作为替代目标出现的形式化结构:

{fieldname|conversionflag:formatspec}

在这个替代目标语法中:

  • fieldname是指定参数的一个数字或关键字,后面跟着可选的“.name”或“[index]”成分引用
  • Conversionflag可以是r,s,或者a分别是在该值上对repr,str或ascii内置函数的一次调用
  • Formatspec指定了如何表示该值,包括字段宽度、对齐方式、补零、小数点精度等细节,并且以一个可选的数据类型编码结束。

冒号后的formatspec组成形式上的描述如下(方括号表示可选的组成,并且不能编写为常量):

[[fill]align][sign][#][0][width][.precision][typecode]


align可能是〈、 〉、=或^,分别表示左对齐、右对齐、一个标记字符后的补充或居中对齐。 Formatspec也包含嵌套的、只带有{}的格式化字符串,它从参数列表动态地获取值(和格式化表达式中的*很相似)。

'{0:10}={1:10}'.format('spam',123.4566)
'spam      =  123.4566'
'{0:<10}={1:<10}'.format('spam',123.4567)
'spam      =123.4567  '
'{0.platform:>10} = {1[item]:<10}'.format(sys, dict(item='laptop')) 
'     win32 = laptop    '

正则表达式入门

学习地址:https://www.cnblogs.com/yyyg/p/5498803.html

import re
str='潘其威 35220319998564123x 男'
m='[0-9x]{18}'
print(re.findall(m,str))
['35220319998564123x']

Chap08 列表与字典

列表

引言

Python中的列表是:

  • 任意对象的有序集合
  • 可通过偏移量读取
  • 可变长度、异构以及任意嵌套
  • 属于可变序列的分类
  • 对象引用数组

常用列表常量和操作

操作 解释
L=[] 一个空列表
L=[0,1,2,3] 四项:索引为0到3
L=[‘abc’,[‘def’,‘ghi’]] 嵌套的子列表
L=list(‘spam’),L=list(range(-4,4)) 可迭代项目的列表,连续整数的列表
L[i],L[i][j],L[i:j],len(L) 索引,索引的索引,分片,求长度
L1+L2 合并
L*3 重复
for x in L: print(x)
3 in L
迭代、成员关系
L.append(4)
L.extend([5,6,7])
L.insert(1)
L.index(i)
L.Count(X)
L.sort()
L.reverse()
方法:增长,排序,搜索,插入,反转等
del L[k]
del L[i:j]
L.pop()
L.remove(2)
L[i:j]=[]
方法,语句:缩短
L[i]=1
L[i:j]=[4,5,6]
索引、分片赋值
L=[x**2 for x in range(5)]
list(map(ord,‘spam’))
列表解释(见13、17章)

实际应用中的列表

列表迭代和解析

# 一个简单的列表迭代
for x in [1,2,3]:
    print(x,end=' ')
1 2 3 
# 一个简单的列表解析
res=[c*4 for c in 'spam']
res
['ssss', 'pppp', 'aaaa', 'mmmm']
# 利用list+map函数构建列表
list(map(abs,[-1,-2,0,1,2]))
[1, 2, 0, 1, 2]

索引、分片和矩阵

列表中可以使用嵌套,有时需要将几次索引操作连在一起使用来深入到数据结构中区。其中个最简单的办法就是将其表示为矩阵(多维数组)。

matrix=[[1,2,3],[4,5,6],[7,8,9]]
print(matrix[1])
print(matrix[1][2])
[4, 5, 6]
6

原处修改列表

列表方法的调用

L.append(x)与L+[x]的结果类似,不同的是,前者会原地修改L,而后者则生成新的列表。

调用sort方法时可以传入参数reverse=True来反转排序。key参数则给出了一个单个参数的函数,返回在排序中使用的值。在排序字典的列表的时候,排序的key参数也很有用,可以通过索引每个字典挑选出一个排序键。

L=['abc','ABD','aBe']
L.sort()
L
['ABD', 'aBe', 'abc']
L=['abc','ABD','aBe']
L.sort(key=str.lower) # 全部转变为对小写字符的排序,但实际上并不改变内容的大小写形式
L
['abc', 'ABD', 'aBe']
L=['abc','ABD','aBe']
L.sort(key=str.upper,reverse=True)
L
['aBe', 'ABD', 'abc']

注意:要当心append和sort原处修改相关的列表对象,而结果并没有返回列表(从技术上来讲,两者返回的值皆为None)。如果编辑类似L=L.append (X)的语句,将不会得到L修改后的值(实际上,会失去整个列表的引用):当使用append和sort之类的属性时,对象的修改有点像副作用,所以没有理由再重新赋值。

L.append('ddd')
L
['aBe', 'ABD', 'abc', 'ddd']
L.append([1,2,3])
L
['aBe', 'ABD', 'abc', 'ddd', [1, 2, 3]]
L.extend('append')
L
['aBe', 'ABD', 'abc', 'ddd', [1, 2, 3], 'a', 'p', 'p', 'e', 'n', 'd']
L.extend([1,2,3])
L
['aBe', 'ABD', 'abc', 'ddd', [1, 2, 3], 'a', 'p', 'p', 'e', 'n', 'd', 1, 2, 3]

排序在最近的Python中也可以作为内置函数来使用,它可以排序任何结合(不只是列表),并且针对结果返回一个新的列表(而不是原处修改):

L=['abc','ABD','aBe']
sorted(L,key=str.lower,reverse=True)
['aBe', 'ABD', 'abc']
L=['abc','ABD','aBe']
sorted([x.lower() for x in L],reverse=True)
['abe', 'abd', 'abc']

pop方法(无参情况下),删除并返回最后一个元素。

reverse方法,反转列表。

在某些类型的应用程序中,往往会把这里用到的列表pop方法和append方法联用,来实现快速的后进先出 (LIFO. last-in-first-out) 堆钱结构。列表的末端作为堆栓的顶端:

L=[]
L.append(1)
L.append(2)
L
[1, 2]
L.pop()
2
L
[1]
L=[]
for x in range(1,10):
    L.append(x)
while len(L)!=0 :
    print(L.pop(),end=' ')

9 8 7 6 5 4 3 2 1 

将空列表赋值给一个索引只会在指定位置存储空列表的引用,而不是删除:

L=['Already','got','one']
L[1:]=[]
L[0]=[]
L
[[]]

字典

引言

字典也许是Pytho中最灵活的内置数据结构类型。字典可以看作是无序的结合。

字典的主要属性如下:

  • 通过键而不是偏移量来读取
  • 任意对象的无序集合
  • 可变长、异构、任意嵌套
  • 属于可变映射类型
  • 对象引用表(散列表)

常见字典常量和操作

操作 解释
D={} 空字典
D={‘spam’:2,‘eggs’:3} 两项目字典
D={‘food’:{‘ham’:1,‘egg’:2}} 嵌套
D=dict(zip(keyslist,valslist))
D=dic(name=‘Bob’,age=42)
关键字、对应的对、键列表
D[‘eggs’]
D[‘food’][‘ham’]
通过键进行索引运算
‘eggs’ in D 成员关系:键的存在测试
D.keys() 方法:键
D.values()
D.items() 键值对
D.copy() 副本拷贝
D.get(key,default) 默认
D.update(D2) 合并
D.pop(key) 删除键对应的值
len(D) 长度
D[key]=42 新增/修改键,删除键
del D[key] 根据键删除条目
list(D.keys())
D1.keys()&D2.keys()
Dictionary views(Python3.0)
字典视图(Python3.0)
D={x: x*2 for x in range(10)} 字典解析(Python3.0)

字典的基本操作

其他字典方法

# values 和 items方法
D={
     'spam':2,'ham':1,'eggs':3}
list(D.values())
[2, 1, 3]
list(D.items())
[('spam', 2), ('ham', 1), ('eggs', 3)]
# update 方法
# 此方法类似于合并,但它与顺序无关,它知识把一个字典的键值合并到另一个字典中,盲目地覆盖其中相同键的值
D={
     'spam':2,'ham':1,'eggs':3}
D['toast']=4
D2={
     'toast':5,'muffin':6}
D.update(D2)
D
{'spam': 2, 'ham': 1, 'eggs': 3, 'toast': 5, 'muffin': 6}
# pop中删除的是键而不是位置索引
D.pop('toast')
5

字典的copy方法将在下一章讨论,因为它是避免相同字典共享引用潜在的副作用的一种方式。

语言表

我们来看一个更实际的字典的例子。下面的例子能够生成一张表格,把程序语言名称(键)映射到它们的创造者(值)。你可以通过语言名称索引来读取语言创造者的名字:

table={
     
    'Python':'Guido van Rossum',
    'Perl':'Larry Wall',
    'Tcl':'John Ousterhout'
}
language='Python'
creator=table[language]
creator
'Guido van Rossum'
for lang in table: # 效果等同于 for lang in table.keys()
    print(lang,'\t',table[lang])

Python 	 Guido van Rossum
Perl 	 Larry Wall
Tcl 	 John Ousterhout

字典用法注意事项

  • 序列运算无效
  • 对新索引赋值会添加项
  • 键不一定总是字符串
    -任何不可变对象都可以作为字典的键

使用字典模拟灵活的列表

当使用列表的时候,对列表末尾以外的偏移赋值时非法的;虽然可以使用重复来按需预先分配足够大的列表,但也可以使用字典来做类似的事,这样就不需要事先分配空间了。

L=[]
L[99]='spam'
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

 in ()
      1 L=[]
----> 2 L[99]='spam'


IndexError: list assignment index out of range
D={
     }
D[99]='spam'
D[99]
'spam'

看起来似乎D事一个有100项的列表,但其实是一个有单个元素的列表;键99的值是字符串‘spam’。这样做可以项列表那样利用偏移访问这一结构,但不需要为将来可能会用到的会被赋值的所有位置分配空间。像这样使用时,字典很想更具灵活性的列表。

字典用于稀疏数据结构

Matrix={
     }
Matrix[(2,3,4)]=88
Matrix[(7,8,9)]=99
X=2
Y=3
Z=4
Matrix[(X,Y,Z)]
88
Matrix
{(2, 3, 4): 88, (7, 8, 9): 99}

在这里,我们用字典表示一个三维数组,这个数组中只有两个位置(2,3,4)和(7,8,9)有 值,其他位置都为空。键是元组,它们记录非空元素的坐标。我们并不是分配一个庞大 而几乎为空的三维矩阵,而是用一个简单的两个元素的字典。通过这一方式读取空元素时,会触发键不存在的异常,因为这些元素实质上并没有存储:

Matrix[(2,3,6)]
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

 in ()
----> 1 Matrix[(2,3,6)]


KeyError: (2, 3, 6)

避免missing-key错误

if (2,3,6) in Matrix:
    print(Matrix[(2,3,6)])
else:
    print(0)

0
try:
    print(Matrix[(2,3,6)])
except KeyError:
    print(0)

0
A1=Matrix.get((2,3,4),0)
A2=Matrix.get((2,3,6),0)
print(A1,A2)
88 0

使用字典作为“记录”

字典是在程序范围中多种描述某一项属性的方能之一。也就是说,它们能够扮演与其他语言中"记录"和"结构"相同的角色。

特别是在嵌套的时候,Python的内建数据类型可以很轻松地表达结构化信息。

创建字典的其他方法

  • 如果你可以事先拼出整个字典,那么第一种是很方便的。
  • 如果你需要一次动态地建立字典的一个字段,第二种比较合适。
  • 第三种关键字形式所需的代码比常量少,但是键必须都是字符串才行。
  • 如果你需要在程序运行时把键和值逐步建成序列,那么最后一种形式比较有用。
# method1
{
     'name':'Bob','age':45}
{'name': 'Bob', 'age': 45}
# method2
D={
     }
D['name']='William'
D['age']=20
D
{'name': 'William', 'age': 20}
dict(name='Bob',age=45)
{'name': 'Bob', 'age': 45}
dict([('name','William'),('age',20)])
{'name': 'William', 'age': 20}

如果所有键的值都一样(或一次性为所有键进行初始化),可以使用以下方法:

dict.fromkeys(['a','b'],0)
{'a': 0, 'b': 0}

Python3.0中的字典变化

具体来说,Python3.0中的字典:

  • 支持一种新的字典解析表达式,这是列表和集合解析的"近亲"。
  • 对于D.key、D.values和D.items方法,返回可迭代的视圈,而不是列表。
  • 由于前面一点,需要新的编码方式通过排序键来遍历。
  • 不再直接支持相对大小比较——取而代之的是手动比较。
  • 不再有D.has_key方总——相反,使用in成员关系测试。

字典解析

# zip函数的使用初探
list(zip(['a','b','c'],[1,2,3]))
[('a', 1), ('b', 2), ('c', 3)]
# 如果不能在代码中预计键和值的集合,总是可以将它们构建为列表然后再对应起来:

D=dict(zip(['a','b','c'],[1,2,3]))
D
{'a': 1, 'b': 2, 'c': 3}

Python3.0中可以使用列表解析来实现以上同样的效果。

D={
     k:v for (k,v) in zip(['a','b','c'],[1,2,3])}
D
{'a': 1, 'b': 2, 'c': 3}
D={
     x:x ** 2 for x in [1,2,3,4]}
D
{1: 1, 2: 4, 3: 9, 4: 16}

字典解析对于从键列表来初始化字典也很有用,这一点和使用哦fromkeys方法和相似:

D=dict.fromkeys('spam')
D
{'s': None, 'p': None, 'a': None, 'm': None}
D={
     k:None for k in 'spam'}
D
{'s': None, 'p': None, 'a': None, 'm': None}

字典视图

Python3.0中,字典的keys、values和items都返回视图对象。

视图对象可迭代。

字典视图还保持了字典成分的最初的顺序,反映字典未来的修改,并且能够支持集合操作。

视图不是列表,并且不支持像索引和列表sort方法这样的操作,打印的时候也不现实自己的项。

如果想要应用列表操作或者显示视图的值,必须通过内置函数list来运行这三个方法的结果。

D=dict(a=1,b=2,c=3)
K=D.keys()
K
dict_keys(['a', 'b', 'c'])
list(K)
['a', 'b', 'c']
K[0]
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
----> 1 K[0]


TypeError: 'dict_keys' object does not support indexing

Python中的字典视图并非在创建后不能改变——它们可以动态地反映在视图创建之后对字典做出的修改:

D=dict.fromkeys([1,2,3,4,5])
k=D.keys()
l=list(k)
l
[1, 2, 3, 4, 5]
D.pop(3)
k
dict_keys([1, 2, 4, 5])
l
[1, 2, 3, 4, 5]

字典视图和几何

keys方法返回的Python3.0的视图对象类似于几何,并且支持交集和并集等常见的集合操作;values视图则不是这样的,因为它们不是唯一的;但items结果是的,如果键值对是唯一并且可散列的话。

K
dict_keys(['a', 'b', 'c'])
K|{
     'x':4}
{'a', 'b', 'c', 'x'}
K&{
     'x':4}
set()
D={
     k:v for (k,v) in zip([1,2,3],['a','b','c'])}
KV=D.items()
KV
dict_items([(1, 'a'), (2, 'b'), (3, 'c')])
KV|{
     4:'c'}.items()
{(1, 'a'), (2, 'b'), (3, 'c'), (4, 'c')}

排序字典键

由于keys不会返回一个列表,因此必须要么手动地转换为一个列表,要么在一个键视图或者字典自身上使用sorted来排序字典键:

D={
     'a':1,'b':2,'c':3}
D
{'a': 1, 'b': 2, 'c': 3}
Ks=D.keys()
Ks=list(Ks)
Ks.sort()
for k in Ks:
    print(k,D[k])
a 1
b 2
c 3
Ks=D.keys()
for k in sorted(Ks):
    print(k,D[k])
a 1
b 2
c 3
# 更直接的方式
for k in sorted(D):
    print(k,D[k])
a 1
b 2
c 3

字典大小比较不再有效

在Python3.0中直接用比较符号来比较字典的相对大小的方法已经不再有效。但可以通过手动地比较排序后的键列表来模拟:

D1={
     1:'a',2:'b'}
D2={
     3:'c',4:'d'}
sorted(D1.items())<sorted(D2.items())
True

has_key方法已死,in永生

Python3.0中取消了广为使用的has_key这一键存在测试方法,而使用in成员关系表达式,或者带有默认测试的一个get(通常,in是首选)。

Chap09 元组、文件及其他

元组

引言

元组的属性如下:

  • 任意对象的有序集合
  • 通过偏移存取
  • 属于不可变序列类型
  • 固定长度、异构、任意嵌套
  • 对象引用的数组

常见元组常量和运算

运算 解释
() 空元组
T=(0,) 单个元素的元组(非表达式)
T=(0,‘Ni’,1.2,3) 四个元素的元组
T=0,‘Ni’,1.2,3 另一个四元素的元组(与前列相同)
T=(‘abc’,(‘def’,'ghi)) 嵌套元组
T=tuple(‘spam’) 一个可以迭代对象的的项元组
T[i]
T[i][j]
T[i:j]
len(T)
索引、索引的索引、分片、长度
T1+T2
T*3
合并、重复
for x in T:print(x)
‘spam’ in T
[x**2 for x in T]
迭代、成员关系
T.index(‘Ni’)
T.count(‘Ni’)
Python2.6和Python3.0中的方法:搜索、计数

实际应用中的元组

转换、方法以及不可变性

元组只有两个方法:index和count。

元组是不可变的。

为什么有了列表还要元组

Python的创造者接受过数学训练,并提到过把元组看傲是简单的对象组合,把列表看成是随时间改变的数据结构。实际上,单词"元组"就借用自数学领域,通常用来指关系数据库表的一行。

文件

引言

内置的open函数会创建一个Python文件对象,可以作为计算机上的一个文件链接。

文件对象只是常见文件处理任务输出模块。多数文件方法都与执行外部文件相关的文件对象的输入和输出有关,但其他文件方法可查找文件中的新位置、刷新输出缓存等。

常见文件运算

操作 解释
output=open(r’C:\spam’,‘w’) 创建输出文件('w’是指写入)
input=open(‘data’,‘r’) 创建输入文件('r’是指读写)
input=open(‘data’) 同上('r’是默认值)
aString=input.read() 把整个文件读进单一字符串
aString=input.read(N) 读取之后的N个字节(一或多个)到一个字符串
aString=input.readline() 读取下一行(包括行末标识符)到一个字符串
aList=input.readlines() 读取整个文件到字符串列表
output.write(aString) 写入字节字符串到文件
output.writelines(aList) 把列表内所有字符串写入文件
output.close() 手动关闭(当文件收集完成时会替你关闭文件)
output.flush() 把输出缓冲区刷到硬盘中,但不关闭文件
anyFile.seek(N) 修改文件位置到偏移量N处以便进行下一个操作
for line in open(‘data’):use line 文件迭代器一行一行地读取
open(‘f.texx’,encoding=‘latin-1’) Python3.0Unicode文本文件(str字符串)
open(‘f.bin’,‘rb’) Python3.0二进制byte文件(bytes字符串)

打开文件

文件操作的几种模式:

  • ‘w’:清空写,生成一个新的文件,写入内容,覆盖原文件
  • ‘w+’:先清空文件,然后写入内容,最后才能读取写入的内容
  • ‘wb’:二进制模式写
  • ‘r’:只读(默认)
  • ‘r+’:不清空源文件内容,同时可以读和写,从文件的开头写入
  • ‘rb’:二进制模式读
  • ‘a’:追加写,写在原文件末尾,从文件的结尾写入
  • ‘ab’:二进制模式追加写
  • ‘a+’:追加写后读取

使用文件

任何情况下,Python程序中的文本文件都采用字符串的形式。

一些基础用法的提示:

  • 文件迭代器是最好的读取行工具
  • 内容是字符串,不是对象(即必须传入一个已经转换为字符串的内容)
  • close是通常选项,手动关闭时大型程序中一个很不错的习惯
  • 文件是缓冲的并且是可查找的

实际应用中的文件

# 一个简单的文件处理例子
myfile=open('myfile.txt','w')
myfile.write('hello text file\n')
16
myfile.write('goodbye text file\n')
18
myfile.close()
myfile=open('myfile.txt')
myfile.readline()
'hello text file\n'
myfile.readline()
'goodbye text file\n'
myfile.readline()
''

如果想要显示带有末行字符解释的文件内容,用文件对象的read方法把整个文件读入到一个字符串中并打印:

open('myfile.txt').read()
'hello text file\ngoodbye text file\n'
print(open('myfile.txt').read())
hello text file
goodbye text file
for line in open('myfile.txt'):
    print(line,end=' ')
hello text file
 goodbye text file

Python3.0中的文本和二进制文件

Python总是支持文本和二进制文件,但在Python3.0中,二者之间有明显的区别:

  • 文本文件把内容表示为常规的str字符串,自动执行Unicode编码和解码,并且默认执行末行转换。
  • 二进制文件把内容表示成一个特殊的bytes字符串类型,并且允许程序不修改地访问文件内容。

此外,二进制文件不会对数据执行任何行末转换;在根据转换写入和读取并实现Unicode编码的时候,文本文件默认地把所有形式和\n之间映射起来。

在文件中存储并解析Python对象

X,Y,Z=43,44,45
S='Spam'
D={
     'a':1,'b':2}
L=[1,2,3]

F=open('datafile.txt','w')
F.write(S+'\n')
F.write('%s,%s,%s\n'%(X,Y,Z))
F.write(str(L)+'$'+str(D)+'\n')
F.close()
chars=open('datafile.txt').read()
chars
"Spam\n43,44,45\n[1, 2, 3]${'a': 1, 'b': 2}\n"
print(chars)
Spam
43,44,45
[1, 2, 3]${'a': 1, 'b': 2}

为了把文本文件中的字符转换为真正的Python对象,鉴于Python本身不会自动把字符串转换为数字或其他对象,就不得不使用其他转换的工具:

F=open('datafile.txt')
line=F.readline()
line
'Spam\n'
line.rstrip()
'Spam'
line=F.readline()
line
'43,44,45\n'
parts=line.split(',')
parts
['43', '44', '45\n']
int(parts[1]) # 不一定非要运用rstrip方法删除换行符,int和其他一些转换方法会忽略数字旁边的空白
44
numbers=[int(P) for P in parts]
numbers
[43, 44, 45]
tuple(numbers)
(43, 44, 45)
line=F.readline()
line
"[1, 2, 3]${'a': 1, 'b': 2}\n"
parts=line.split('$')
parts
['[1, 2, 3]', "{'a': 1, 'b': 2}\n"]
eval(parts[0]) # 转换成最贴近的对象类型
[1, 2, 3]
objects=[eval(P) for P in parts]
objects
[[1, 2, 3], {'a': 1, 'b': 2}]

用pickle存储Python的原生对象

从前面的程序中可以发现,eval可以把字符串转换成对象,它是一个功能强大的工具。但其过于强大以至于有可能会删除计算机上所有文件的表达式,只要给予必要的权限的话。

如果针对像存储Python原生对象,但又无法信赖文件的数据来源,使用pickle模块是个理想的选择。

D={
     'a':1,'b':2,'c':3}
F=open('datafile.pkl','wb')
import pickle
pickle.dump(D,F) # Pickle any object to file
F.close()

F=open('datafile.pkl','rb')
E=pickle.load(F)
E
{'a': 1, 'b': 2, 'c': 3}
open('datafile.pkl','rb').read()
b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02X\x01\x00\x00\x00cq\x03K\x03u.'
help(pickle)
Help on module pickle:

NAME
    pickle - Create portable serialized representations of Python objects.

DESCRIPTION
    See module copyreg for a mechanism for registering custom picklers.
    See module pickletools source for extensive comments.
    
    Classes:
    
        Pickler
        Unpickler
    
    Functions:
    
        dump(object, file)
        dumps(object) -> string
        load(file) -> object
        loads(string) -> object
    
    Misc variables:
    
        __version__
        format_version
        compatible_formats

CLASSES
    builtins.Exception(builtins.BaseException)
        _pickle.PickleError
            _pickle.PicklingError
            _pickle.UnpicklingError
    builtins.object
        _pickle.Pickler
        _pickle.Unpickler
    
    class PickleError(builtins.Exception)
     |  Common base class for all non-exit exceptions.
     |  
     |  Method resolution order:
     |      PickleError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
     |  Data descriptors defined here:
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.Exception:
     |  
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Static methods inherited from builtins.Exception:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.BaseException:
     |  
     |  __delattr__(self, name, /)
     |      Implement delattr(self, name).
     |  
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |  
     |  __reduce__(...)
     |      Helper for pickle.
     |  
     |  __repr__(self, /)
     |      Return repr(self).
     |  
     |  __setattr__(self, name, value, /)
     |      Implement setattr(self, name, value).
     |  
     |  __setstate__(...)
     |  
     |  __str__(self, /)
     |      Return str(self).
     |  
     |  with_traceback(...)
     |      Exception.with_traceback(tb) --
     |      set self.__traceback__ to tb and return self.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from builtins.BaseException:
     |  
     |  __cause__
     |      exception cause
     |  
     |  __context__
     |      exception context
     |  
     |  __dict__
     |  
     |  __suppress_context__
     |  
     |  __traceback__
     |  
     |  args
    
    class Pickler(builtins.object)
     |  Pickler(file, protocol=None, fix_imports=True)
     |  
     |  This takes a binary file for writing a pickle data stream.
     |  
     |  The optional *protocol* argument tells the pickler to use the given
     |  protocol; supported protocols are 0, 1, 2, 3 and 4.  The default
     |  protocol is 3; a backward-incompatible protocol designed for Python 3.
     |  
     |  Specifying a negative protocol version selects the highest protocol
     |  version supported.  The higher the protocol used, the more recent the
     |  version of Python needed to read the pickle produced.
     |  
     |  The *file* argument must have a write() method that accepts a single
     |  bytes argument. It can thus be a file object opened for binary
     |  writing, an io.BytesIO instance, or any other custom object that meets
     |  this interface.
     |  
     |  If *fix_imports* is True and protocol is less than 3, pickle will try
     |  to map the new Python 3 names to the old module names used in Python
     |  2, so that the pickle data stream is readable with Python 2.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  __sizeof__(self, /)
     |      Returns size in memory, in bytes.
     |  
     |  clear_memo(self, /)
     |      Clears the pickler's "memo".
     |      
     |      The memo is the data structure that remembers which objects the
     |      pickler has already seen, so that shared or recursive objects are
     |      pickled by reference and not by value.  This method is useful when
     |      re-using picklers.
     |  
     |  dump(self, obj, /)
     |      Write a pickled representation of the given object to the open file.
     |  
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  bin
     |  
     |  dispatch_table
     |  
     |  fast
     |  
     |  memo
     |  
     |  persistent_id
    
    class PicklingError(PickleError)
     |  Common base class for all non-exit exceptions.
     |  
     |  Method resolution order:
     |      PicklingError
     |      PickleError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
     |  Data descriptors inherited from PickleError:
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.Exception:
     |  
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Static methods inherited from builtins.Exception:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.BaseException:
     |  
     |  __delattr__(self, name, /)
     |      Implement delattr(self, name).
     |  
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |  
     |  __reduce__(...)
     |      Helper for pickle.
     |  
     |  __repr__(self, /)
     |      Return repr(self).
     |  
     |  __setattr__(self, name, value, /)
     |      Implement setattr(self, name, value).
     |  
     |  __setstate__(...)
     |  
     |  __str__(self, /)
     |      Return str(self).
     |  
     |  with_traceback(...)
     |      Exception.with_traceback(tb) --
     |      set self.__traceback__ to tb and return self.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from builtins.BaseException:
     |  
     |  __cause__
     |      exception cause
     |  
     |  __context__
     |      exception context
     |  
     |  __dict__
     |  
     |  __suppress_context__
     |  
     |  __traceback__
     |  
     |  args
    
    class Unpickler(builtins.object)
     |  Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict')
     |  
     |  This takes a binary file for reading a pickle data stream.
     |  
     |  The protocol version of the pickle is detected automatically, so no
     |  protocol argument is needed.  Bytes past the pickled object's
     |  representation are ignored.
     |  
     |  The argument *file* must have two methods, a read() method that takes
     |  an integer argument, and a readline() method that requires no
     |  arguments.  Both methods should return bytes.  Thus *file* can be a
     |  binary file object opened for reading, an io.BytesIO object, or any
     |  other custom object that meets this interface.
     |  
     |  Optional keyword arguments are *fix_imports*, *encoding* and *errors*,
     |  which are used to control compatibility support for pickle stream
     |  generated by Python 2.  If *fix_imports* is True, pickle will try to
     |  map the old Python 2 names to the new names used in Python 3.  The
     |  *encoding* and *errors* tell pickle how to decode 8-bit string
     |  instances pickled by Python 2; these default to 'ASCII' and 'strict',
     |  respectively.  The *encoding* can be 'bytes' to read these 8-bit
     |  string instances as bytes objects.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  __sizeof__(self, /)
     |      Returns size in memory, in bytes.
     |  
     |  find_class(self, module_name, global_name, /)
     |      Return an object from a specified module.
     |      
     |      If necessary, the module will be imported. Subclasses may override
     |      this method (e.g. to restrict unpickling of arbitrary classes and
     |      functions).
     |      
     |      This method is called whenever a class or a function object is
     |      needed.  Both arguments passed are str objects.
     |  
     |  load(self, /)
     |      Load a pickle.
     |      
     |      Read a pickled object representation from the open file object given
     |      in the constructor, and return the reconstituted object hierarchy
     |      specified therein.
     |  
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  memo
     |  
     |  persistent_load
    
    class UnpicklingError(PickleError)
     |  Common base class for all non-exit exceptions.
     |  
     |  Method resolution order:
     |      UnpicklingError
     |      PickleError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
     |  Data descriptors inherited from PickleError:
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.Exception:
     |  
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Static methods inherited from builtins.Exception:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.BaseException:
     |  
     |  __delattr__(self, name, /)
     |      Implement delattr(self, name).
     |  
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |  
     |  __reduce__(...)
     |      Helper for pickle.
     |  
     |  __repr__(self, /)
     |      Return repr(self).
     |  
     |  __setattr__(self, name, value, /)
     |      Implement setattr(self, name, value).
     |  
     |  __setstate__(...)
     |  
     |  __str__(self, /)
     |      Return str(self).
     |  
     |  with_traceback(...)
     |      Exception.with_traceback(tb) --
     |      set self.__traceback__ to tb and return self.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from builtins.BaseException:
     |  
     |  __cause__
     |      exception cause
     |  
     |  __context__
     |      exception context
     |  
     |  __dict__
     |  
     |  __suppress_context__
     |  
     |  __traceback__
     |  
     |  args

FUNCTIONS
    dump(obj, file, protocol=None, *, fix_imports=True)
        Write a pickled representation of obj to the open file object file.
        
        This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may
        be more efficient.
        
        The optional *protocol* argument tells the pickler to use the given
        protocol supported protocols are 0, 1, 2, 3 and 4.  The default
        protocol is 3; a backward-incompatible protocol designed for Python 3.
        
        Specifying a negative protocol version selects the highest protocol
        version supported.  The higher the protocol used, the more recent the
        version of Python needed to read the pickle produced.
        
        The *file* argument must have a write() method that accepts a single
        bytes argument.  It can thus be a file object opened for binary
        writing, an io.BytesIO instance, or any other custom object that meets
        this interface.
        
        If *fix_imports* is True and protocol is less than 3, pickle will try
        to map the new Python 3 names to the old module names used in Python
        2, so that the pickle data stream is readable with Python 2.
    
    dumps(obj, protocol=None, *, fix_imports=True)
        Return the pickled representation of the object as a bytes object.
        
        The optional *protocol* argument tells the pickler to use the given
        protocol; supported protocols are 0, 1, 2, 3 and 4.  The default
        protocol is 3; a backward-incompatible protocol designed for Python 3.
        
        Specifying a negative protocol version selects the highest protocol
        version supported.  The higher the protocol used, the more recent the
        version of Python needed to read the pickle produced.
        
        If *fix_imports* is True and *protocol* is less than 3, pickle will
        try to map the new Python 3 names to the old module names used in
        Python 2, so that the pickle data stream is readable with Python 2.
    
    load(file, *, fix_imports=True, encoding='ASCII', errors='strict')
        Read and return an object from the pickle data stored in a file.
        
        This is equivalent to ``Unpickler(file).load()``, but may be more
        efficient.
        
        The protocol version of the pickle is detected automatically, so no
        protocol argument is needed.  Bytes past the pickled object's
        representation are ignored.
        
        The argument *file* must have two methods, a read() method that takes
        an integer argument, and a readline() method that requires no
        arguments.  Both methods should return bytes.  Thus *file* can be a
        binary file object opened for reading, an io.BytesIO object, or any
        other custom object that meets this interface.
        
        Optional keyword arguments are *fix_imports*, *encoding* and *errors*,
        which are used to control compatibility support for pickle stream
        generated by Python 2.  If *fix_imports* is True, pickle will try to
        map the old Python 2 names to the new names used in Python 3.  The
        *encoding* and *errors* tell pickle how to decode 8-bit string
        instances pickled by Python 2; these default to 'ASCII' and 'strict',
        respectively.  The *encoding* can be 'bytes' to read these 8-bit
        string instances as bytes objects.
    
    loads(data, *, fix_imports=True, encoding='ASCII', errors='strict')
        Read and return an object from the given pickle data.
        
        The protocol version of the pickle is detected automatically, so no
        protocol argument is needed.  Bytes past the pickled object's
        representation are ignored.
        
        Optional keyword arguments are *fix_imports*, *encoding* and *errors*,
        which are used to control compatibility support for pickle stream
        generated by Python 2.  If *fix_imports* is True, pickle will try to
        map the old Python 2 names to the new names used in Python 3.  The
        *encoding* and *errors* tell pickle how to decode 8-bit string
        instances pickled by Python 2; these default to 'ASCII' and 'strict',
        respectively.  The *encoding* can be 'bytes' to read these 8-bit
        string instances as bytes objects.

DATA
    ADDITEMS = b'\x90'
    APPEND = b'a'
    APPENDS = b'e'
    BINBYTES = b'B'
    BINBYTES8 = b'\x8e'
    BINFLOAT = b'G'
    BINGET = b'h'
    BININT = b'J'
    BININT1 = b'K'
    BININT2 = b'M'
    BINPERSID = b'Q'
    BINPUT = b'q'
    BINSTRING = b'T'
    BINUNICODE = b'X'
    BINUNICODE8 = b'\x8d'
    BUILD = b'b'
    DEFAULT_PROTOCOL = 3
    DICT = b'd'
    DUP = b'2'
    EMPTY_DICT = b'}'
    EMPTY_LIST = b']'
    EMPTY_SET = b'\x8f'
    EMPTY_TUPLE = b')'
    EXT1 = b'\x82'
    EXT2 = b'\x83'
    EXT4 = b'\x84'
    FALSE = b'I00\n'
    FLOAT = b'F'
    FRAME = b'\x95'
    FROZENSET = b'\x91'
    GET = b'g'
    GLOBAL = b'c'
    HIGHEST_PROTOCOL = 4
    INST = b'i'
    INT = b'I'
    LIST = b'l'
    LONG = b'L'
    LONG1 = b'\x8a'
    LONG4 = b'\x8b'
    LONG_BINGET = b'j'
    LONG_BINPUT = b'r'
    MARK = b'('
    MEMOIZE = b'\x94'
    NEWFALSE = b'\x89'
    NEWOBJ = b'\x81'
    NEWOBJ_EX = b'\x92'
    NEWTRUE = b'\x88'
    NONE = b'N'
    OBJ = b'o'
    PERSID = b'P'
    POP = b'0'
    POP_MARK = b'1'
    PROTO = b'\x80'
    PUT = b'p'
    REDUCE = b'R'
    SETITEM = b's'
    SETITEMS = b'u'
    SHORT_BINBYTES = b'C'
    SHORT_BINSTRING = b'U'
    SHORT_BINUNICODE = b'\x8c'
    STACK_GLOBAL = b'\x93'
    STOP = b'.'
    STRING = b'S'
    TRUE = b'I01\n'
    TUPLE = b't'
    TUPLE1 = b'\x85'
    TUPLE2 = b'\x86'
    TUPLE3 = b'\x87'
    UNICODE = b'V'
    __all__ = ['PickleError', 'PicklingError', 'UnpicklingError', 'Pickler...

FILE
    t:\anaconda\lib\pickle.py
# shelve用pickle把Python对象存放到按键访问的文件系统之中
import shelve
help(shelve)

文件中打包二进制数据的存储与解析

另一个和文件相关的细节:有些高级应用程序也需要处理打包的二进制文件,这些数据可能是C语言程序生成的。Python的标准库中包含一个能够在这一范围起作用的工具:struct模块能够构造并解析打包的二进制数据。从某种意义上说,它是另一个数据转换工具,能够把文件中的字符串解读为二进制数据。

help(struct)

其他文件工具

Python工具集中还有其他类似的文件工具,例如:

  • os模块中的描述文件
    • 处理整数文件,支持诸如文件锁定之类的较低级工具
  • sockets、匹配上、和FIFO文件
    • 文件类对象,用于同步进程或者通过网络进行通信
  • 通过键来存取的文件
    • 通过键直接存储的不变的Python对象
  • Shell命令流
    • 像os.popen和subprocess.Popen这样的工具,支持产生shell命令,并读取和写入到标准流

重访类型分类

以下是一些需要记住要点:

  • 对象根据分类来共享操作;例如,字符串、列表和元组都共享诸如合并、长度和索引等序列操作。
  • 只有可变对象(列表、字典和集合)可以在原处修改;我们不能在原处修改数字、字符串或元组。
  • 文件导出唯一的方法,因此可变性并不真的适用于它们——当处理文件的时候,它们的状态可能会修改,但是,这与Python的核心类型可变性限制不完全相同。
  • “数字”包含了所有数字类型:整数、浮点数、复数、小数和分数。
  • 字符串包括了str,以及Python3.0中的bytes和Python2.6中的unicode;Python3.0中的bytearray字符串类型是可变的。
  • 集合类似于一个无值的字典的键,但是,它们不能映射为值,并且没有顺序;因此,集合不是一个映射类型或者一个序列类型,frozenset是集合的一个不可变的版本。

对象分类

对象类型 分类 是否可变
数字 数值
字符串 序列
列表 序列
字典 映射
元组 序列
文件 扩展 N/A
Sets 集合
frozenset 集合
bytearray(3.0) 序列

对象灵活性

一般来说:

  • 列表、字典和元组可以包含任何种类的对象。
  • 列表、字典和元组可以任意嵌套。
  • 列表和字典可以动态地扩大和缩小。

引用VS拷贝

赋值操作总是存储对象的引用,而不是对象的拷贝。但由于赋值操作会产生相同对象的多个引用,需要意识到在原处修改可变对象可能会影响程序中其他地方对相同对象的其他引用,这一点很重要。

对于需要拷贝的地方,可以采用以下方式:

  • 没有限制条件的分片表达式(如L[:])能够赋值序列
  • 字典的copy方法(X.copy())能够复制字典。
  • 有些内置函数(例如list)能够生产拷贝(list(L))。
  • copy标准库模块能够生产完整的拷贝.

拷贝需要注意的是:无条件值的分片以及字典copy方法只能做顶层赋值,即不能赋值嵌套的数据结构。如果需要深层嵌套的数据结构的完整、完全独立的拷贝,需要用到标准copy模块——包括import copy语句,并编辑copy.deepcopy()方法对任意嵌套对象做完整的赋值。

比较、相等性和真值

Python的比较总是检查符合对象的所有部分,指导可以得出结果为止。当嵌套对象存在时,Python能够自动便利数据结构,并从左到右递归地应用比较。过程中首次发现的差值将决定比较的结果。

两种测试相等性的方法:

  • ==:操作符测试值的相等性
  • is:表达式测试对象的一致性

Python中给多个变量赋予相同内容的字符串,实际上只创建了一个字符串。

相对大小的比较也能够递归地应用于嵌套的数据结构。

Python中不同的类型的比较方法如下:

  • 数字通过相对大小进行比较
  • 字符串是按字典顺序,一个字符接一个字符地对比进行比较(“abc”<“ac”)
  • 列表和元组从左到右对每个部分的内容进行比较
  • 字典通过排序后的(键、值)列表进行比较。字典的相对大小比较在Python3.0及以上不被支持。
  • 数字混合类型比较(如:1<‘spam’)在Python3.0中式错误的。

Python3.0的字典比较

在Python3.0中,要么编写循环来根据键比较值,要么手动比较排序的键/值列表——利用字典方法items()和内中的sorted。

D1={
     'a':1,'b':2}
D2={
     'a':1,'b':3}
D1==D2
False
D1<D2
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
----> 1 D1
list(D1.items())
[('a', 1), ('b', 2)]
sorted(D1.items())
[('a', 1), ('b', 2)]
sorted(D1.items())<sorted(D2.items())
True
sorted(D1.items())>sorted(D2.items())
False

Python中真和假的含义

和大多数程序设计语言一样,Python中整数0代表假,1代表真。不过除此之外,Python也把任意的空数据结构视为假,把任意非空数据结构视为真。更一般地,真和假的概念是Python中每个对象的固有属性:每个对象不是真就是假:

  • 数字如果非零,则是真
  • 其他对象如果非空,则是真

对象真值的例子

对象
“spam” True
‘’ False
[] False
{} False
1 True
0.0 False
None False

Type对象

Python系统中的任何东西都是对象类型,而且可以由Python程序来处理。事实上,即使是类型本身在Python中也是对象类型。

严格来说,对内置函数type(x)能够返回对象x的类型对象。类型对象可以用在Python中的if语句来进行手动类型比较。但手动类型测试在Python中通常不是一个好的选择,因为它限制了代码的灵活性。

你可能感兴趣的:(Python学习笔记,Python学习笔记,Python,学习笔记)