Python学习手册之Python对象类型
欢迎大家,评论,互相学习,谢谢~!
邮箱:yeilang3@foxmail.com
为什么使用内置类型
1.容易编写
2.拓展的组件
3.内置对象往往比内置的数据结构更有效率
4.内置对象是语言标准的一部分
Python的核心数据类型
数字
当有需要的时候,Python3.0整数类型会自动提供额外的精度。
全精度以及用户友好形式,全精度使用repr,第二种是用户友好形式str。
>>> import math >>> math.pi 3.141592653589793
>>> math.sqrt(85) 9.219544457292887
random :随机数字的生成器和选择器
import random
>>> random.random()
0.9612122816381569
>>> random.choice(1,2,3,4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: choice() takes 2 positional arguments but 5 were given
>>> random.choice([1,2,3,4])
2
字符串
序列的操作
字符串支持假设其中各个元素包含位置顺序的操作。
>>> S = 'Spam'
>>> len(S)
4
>>> S[0]
'S'
>>> S[1]
'p'
索引是按照从最前面的偏移量开始编码的,也就是从0开始,第一项索引为0,第二项索引为1,以此类推
反向索引
>>> S[-1]
'm'
>>> S[-2]
'a'
>>> S[len(S)-1]
'm'
>>> S
'Spam'
可以在方括号中使用任意表达是,而不仅仅能使用数字常量
分片:一般形式为X[I:J],表示“取出在X中从偏移量为I,知道但不包括偏移量为J的内容”。结果是返回一个新对象。
>>> S = 'spwan'
>>> S
'spwan'
>>> S[1:3]
'pw'
在一个分片中,左边界默认为0,并且右边界默认为分片序列的长度
>>> S
'spwan'
>>> S[1:]
'pwan'
>>> S[0:3]
'spw'
>>> S[:-1]
'spwa'
>>> S[:]
'spwan'
>>> S
'spwan'
>>> S + 'xyz'
'spwanxyz'
>>> S
'spwan'
>>> S * 8
'spwanspwanspwanspwanspwanspwanspwanspwan'
作为一个序列,字符串也支持用加号合并(将两个字符串合成一个新的字符串),或者(通过重复一个创建一个新的字符串)
+对不同对象有不同意义:对于数字为加法,对于字符串为合并。
不可变性
字符串在Python中具有不可变性 在创建或不能就地改变。例如,不能通过对其进行复制。因为Python在运行过程中会清理旧对象
>>> S
'spwan'
>>> S[0]='Z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> S = 'Z' + S[1:]
>>> S
'Zpwan'
在Python中每一个对象都可以分为不可变性或者可变性。
不变:数学、字符串和元祖
可变:列表和字典
类型特定的方法
字符串的find方法是一个基本的子字符串查找的操作(它将放回一个传入子字符串中的偏移量,或者没有找到的情况下返回-1),而字符串的replace方法将会对全局进行搜索和替换。
>>> S.find('pa')
-1
>>> S
'Zpwan'
>>> S.find('pW')
-1
>>> S.find('pw')
1
>>> S.replace('Zp','AAA')
'AAAwan'
>>> S
'Zpwan'
>>> line = 'aaa,bbb,ccccc,ddd'
>>> line.split(',')
['aaa', 'bbb', 'ccccc', 'ddd']
>>> line.split(',')[:1]
['aaa']
>>> line.split(',')[:]
['aaa', 'bbb', 'ccccc', 'ddd']
>>> line.split(',')[0:]
['aaa', 'bbb', 'ccccc', 'ddd']
>>> line.split(',')[0:1]
['aaa']
>>> line.split(',')[1:3]
['bbb', 'ccccc']
>>> line ='aaa,bbb,cccc,dd\n'
>>> line = line.rstrip()
>>> line
'aaa,bbb,cccc,dd'
Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔num+1 个子字符串
Python rstrip() 删除 string 字符串末尾的指定字符(默认为空格).
字符串还支持一个叫做格式化的高级代替操作,可以以一个表达式的形式(最初的)和一个字符串的方法调用:
>>> '%s eggs,and %s' %('spam','SPWAM!')
'spam eggs,and SPWAM!'
>>> '{0},eggs and {1}'.format('span','SPAM!')
'span,eggs and SPAM!'
一条简明法则是这样的:可作用于多种类型的通用操作型操作都是以内置函数或表达式的形式出现的[例如,len(x),len[0] ], 但是类型特定的操作是以方法调用的形式出现的[ 例如,aString.upper() ]。 如果经常使用Python,你会更顺利地从这些分类中找到你所需要的工具
帮助
dir函数简单地给出方法的总称,要查询他们是做什么的,你可以将其传递给help函数。
>>> help(S.replace)
编写字符串的其他方法
反斜线转义序列表示特殊的符号
>>> S = 'A\nB\tC'
>>> len(S)
5
>>> ord('\n')
10
>>> S = 'A\o\B\oC'
>>> len(S)
8
Python允许字符串包括在单引号或双引号中(他们代表着相同的东西)。它也允许在三个引号(单引号或双引号)中包括多行字符串常亮。当采用这种形式的时候,所有的行都合并在一起,并在没一行的末尾增加换行符。
>>> msg = """ aaaaaaaaaaaaaaa bbb'''bbbbbbbbbbbbb""bbbbbbbbb'bbbbbbbb cccccccccccccccccccc"""
>>> msg
' aaaaaaaaaaaaaaa bbb\'\'\'bbbbbbbbbbbbb""bbbbbbbbb\'bbbbbbbb cccccccccccccccccccc'
python也支持原始(raw) 字符串常量,即去掉反斜线转义机制(这样的字符串常量是以字母“r”)。Python还支持Unicode字符串形式从而支持国际化。在Python3.0中,基本的str字符串类型也处理Unicode,并且用bytes类型表示原始字节字符串,在Python2.6中,Unicode是一种单独的类型,str处理8位字符串和二进制数据。在Python3.0中,文件也改变为返回和接受str,从而处理二进制数据文本和字节。
模式匹配
>>> import re
>>> match = re.match('Hello[\t]*(.*)world','Hello Python world')
>>> match.group(1)
' Python '
这个子字符串以“Hello”,开始,后面跟着零个或几个制表符或空格,接着又任意字符并将其报酬之匹配的group中,最后以”world.“ 结尾。
模式匹配本身是一个相当高级的文本处理工具,但是在Python中还支持更高级的语言处理工具。
列表
列表是一个任意类型的对象位置相关的有序集合
序列操作
列表支持所有对字符串的序列操作,唯一区别就是其结果往往是列表不是字符串
>>> L = [123,'spam',1.23]
>>> len(L)
3
>>> L[0]
123
>>> L[::-1]
[1.23, 'spam', 123]
>>> L+[4,5,6]
[123, 'spam', 1.23, 4, 5, 6]
>>> L
[123, 'spam', 1.23]
类型特定的操作
Python的列表于其他语言中的数组有些类似,但是列表要强大的多,其中一个方面就是,列表没有固定类型的约束。
>>> L.append('NI')
>>> L
[123, 'spam', 1.23, 'NI']
>>> L.pop(2)
1.23
>>> L
[123, 'spam', 'NI']
列表的append方法扩充了列表的大小并在列表的尾部插入一项;pop方法(或者等效的del语句)移除给定偏移量的一项,从而让列表减小。其他的列表方法可以在任意位置插入(insert)元素,按照值移除(remove)元素等。因为列表是可变的,大多数列表的方法都会就地改变列表对象,而不会创建一个新的列表:
>>> M = ['bb', 'aa','cc']
>>> M.sort()
>>> M
['aa', 'bb', 'cc']
>>> M.reverse()
>>> M
['cc', 'bb', 'aa']
边界检查
尽管列表没有固定大小,Python仍不允许引用不存在的元素。超出列表末尾之外的索引总是会导致错误,对列表末尾范围之外的赋值也是如此。
>>> L[99] =1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
嵌套
Python核心数据类型的一个优秀特性就是它们支持任意的嵌套。能够以任意组合对其进行嵌套,并可以多个层次进行嵌套。这种特性的一个直接应用就是实现矩阵,或者Python中的多维数组,一个嵌套列表的列表能够完成这个基本操作。
>>> M = [ [1,2,3],
... [4,5,6],
... [7,8,9]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
列表解析
提供了一种处理想矩阵这样结构强大工具。
>>> col2= [row[1] for row in M]
>>> col2
[2, 5, 8, 11]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 2]]
他是通过对序列中每一项运行一个表达式来创建一个新的列表,每次一个,从左至右。列表解释是编写在方括号中的,并且使用同一种变量表达式和循环结构组合。
列表解析源自集合的概念。
>>> [row[1]+1 for row in M]
[3, 6, 9, 12]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 2]]
>>> [row [1] for row in M if row[1]%2 == 0]
[2, 8]
>>> diag = [M[i][i] for i in [0,1,2]]
>>> diag
[1, 5, 9]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> doubles = [c *2 for c in 'spam']
>>> doubles
['ss', 'pp', 'aa', 'mm']
>>>G = (sum(row) for row in M)
>>> next (G)
6
>>> next (G)
15
内置函数map可以做类似的事情,产生对各项运行一个函数的结果
>>> list(map(sum,M))
[6, 15, 24]
>>> {sum(row) for row in M}
{24, 6, 15}
map() 会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次function 函数返回值的新列表。
解析语法也可以用来创建集合和字典:
>>> {i : sum(M[i]) for i in range(3)}
{0: 6, 1: 15, 2: 24}
>>> [ord(x) for x in 'spaam']
[115, 112, 97, 97, 109]
>>> {ord(x) for x in 'spaam'}
{112, 97, 115, 109}
>>> {x:ord(x) for x in 'spaam'}
{'s': 115, 'p': 112, 'a': 97, 'm': 109}
字典
Python中的字典是完全不同的东西,它们不是序列,而是一种映射。映射是一个其他对象的集合,但是它们是通过键而不是相对位置来存储。实际上,映射并没有任何可靠的从左至右的顺序。它们简单地将键映射到值。字典是Python核心对象集合的唯一一种映射类型,也具有可变性——可以就地改变,并可以随需求增大或减小。
映射操作
作为常量编写时,字典编写在大括号中,并且包含一系列的“键:值” 对。在我们需要将键于一系列值相关联(例如,为了表述某物的某属性)的时候,字典是很有用的。
>>> D = {'food':'Spam','quantity':4,'color':'pink'}
>>> D
{'food': 'Spam', 'quantity': 4, 'color': 'pink'}
>>> D['food']
'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
重访嵌套
>>> rec = {'name': {'first' : 'Bob','last':'Smith'},
... 'job':['dev','mgr'],
... 'age':40.5}
>>> rec ['name']
{'first': 'Bob', 'last': 'Smith'}
>>> rec ['name'] ['last']
'Smith'
>>> rec ['job']
['dev', 'mgr']
>>> rec ['job'][-1]
'mgr'
>>> rec['job'].append('janitor')
>>> rec
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr', 'janitor'], 'age': 40.5}
Python具有一种叫垃圾收集的特性,在程序运行时可以清理不再使用的内存,并将你从管理代码中这样的细节中解放出来。在Python中,一旦一个对象的最后一次引用被移除,空间将会立即回收。
键的排序:for循环
因为字典不是序列,它们并不包含任何可靠的从左至右的顺序。
D = {'a':1,'b':2,'c':3}
Ks = list(D.keys())
for key in Ks:
print(key,'=>',D[key])
for循环是遍历一个序列中的所有元素并按顺序对每一元素运行一些代码的简单并有效的一种方法。一个用户定义的循环变量(这里是key)用作每次运行过程中当前元素的参考量。
>>> for c in 'spam':
... print (c.upper())
S
P
A
M
while循环是一种更为常见的排序循环工具,它不仅限于遍历序列:
>>> x = 4
>>> while x> 0:
... print ('spam!' *x )
... x -= 1
...
spam!spam!spam!spam!
spam!spam!spam!
spam!spam!
spam!
迭代和优化
迭代协议(这是Python中无处不在的一个概念,表示在内存中的物理存储序列,或一个在迭代操作情况下每次产生一个元素的对象)的任意对象。
从左往右地扫描一个对象的每个Python工具都使用迭代协议。
squares = [x ** 2 for x in [1,2,3,4,5,6]]
print (squares)
[1, 4, 9, 16, 25, 36]
编写一个等效的for循环
squares = []
for x in [1,2,3,4,5]:
squares.append(x**2)
print(squares)
[1, 4, 9, 16, 25]
if测试
D = {'a':1,'b':2,'c':3}
D['e'] = 12
print(D)
{'a': 1, 'b': 2, 'c': 3, 'e': 12}
print('f' in D)
False
>>> D = {'a':1,'b':2,'c':3}
>>> if 'f' not in D:
... print ('missing')
...
missing
get方法(带有一个默认值得条件索引)try语句(一个捕获异常并从异常中恢复的工具)
>>> value = D['x'] if 'x' in D else 0
>>> value
0
元组
基本就像一个不可以改变额列表,就像列表一样,元组是序列,但是它具有不可变性,和字符串类似。从语法上,它们编写在圆括号中而不是方括号
>>> T = (1,2,3,4)
>>> len(T)
4
>>> T + (5,6)
(1, 2, 3, 4, 5, 6)
>>> T[0]
1
>>> T
(1, 2, 3, 4)
元组的真正不同之处就在于一旦创建或就不能再改变。元组是不可变序列
>>> T = ('spam',3.0,[11,22,33])
>>> T
('spam', 3.0, [11, 22, 33])
>>> T[1]
3.0
>>> T[2]
[11, 22, 33]
>>> T[2][1]
22
>>> T.append(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'
为什么要用元组
元组在实际中往往没有列表那样常用,它是关键是不可变。元组提供了一个完整性的约束
文件
文件对象是Python代码对电脑上外部文件的主要接口。虽然文件是核心类型,但是它有些特殊:没有特定的常量语法创建文件。要创建一个文件对象,需调用内置的open函数以字符串的形式传递给他一个外部的文件名以及一个处理模式的字符串。
f = open('data.txt','w')
f.write('hello\n')
f.wirte('world\n')
f.close
这样就在当前文件下创建了一个文件,并向它写入文本(文件名可以是完整的路径,如果需要读取电脑上其他位置的文件)。为了读出刚才所写的内容,重新以‘r’处理模式打开文件,读取输入(如果在调用时忽略模式的话,这将是默认的)。之后将文件的内容渎职一个字符串,并显示它
f = open('data.txt')
text = f.read()
text.split()分隔,默认以逗号
Python3在文件和二进制数据之间划出了一条清晰的界限。文本文件把内容显示为字符串,并且自动执行Unicode编码和解码,而二进制文件把内容显示为一个特定的字节字符串类型,并且运行你不修改地访问
data = open('data.bin','rb').read
其他核心类型
集合不是映射也不是序列,相反他是唯一的不可改变的对象的无序集合。集合通过调用内置set函数而创建,或者使用Python3.0中新的集合常量和表达式创建,并且支持一般的数学集合操作
>>> X = set ('spam')
>>> Y={'h','a','m'}
>>> X,Y
({'s', 'm', 'a', 'p'}, {'h', 'a', 'm'})
>>> X&Y
{'a', 'm'}
>>> X|Y
{'h', 'p', 's', 'a', 'm'}
>>> X-Y
{'s', 'p'}
>>> {x **2 for x in [1,2,3,4]}
{16, 1, 4, 9}
如何破坏代码的灵活性
内置函数:type返回的类型对象是赋给该类型的另一个对象,其结果在Python3.0中略有不同,因为类型已经完全和类结合起来了。
>>> L=[x for x in range(4)]
>>> L
[0, 1, 2, 3]
>>> type(L)
<class 'list'>
>>> type(type(L))
<class 'type'>
>>> if type(L) == type([]):
... print('yes')
...
yes
用户定义的类
类定义了新的对象类型,扩展了核心类型
class Worker:
def __init__(self,name,pay):
self.name=name
self.pay=pay
def lastName(self):
return self.name.split()[-1]
def giverRaise(self,percent):
self.pay *= (1.0+percent)
这个类定义了一个新的对象的种类,有name和pay两个属性(有时候叫状态信息),也有两个小的行为编写为函数(通常叫方法)的形式。就像函数那样去调用,会生成新的类型实例,并且类的方法调用,类的方法自动获取被处理的实例
隐含的“self”对象是我们八折叫做面对对象模型的原因,即一个类中的函数总有一个隐含的对象。一般来说,尽管这样,基于类的类型是建立在并使用了核心类型的。
剩余内容
Python脚本中能处理的所有事情都是某种类型的对象,Python中每样东西都是一个对象