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

文章目录

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)

<ipython-input-7-919096bd6ac9> in <module>()
      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)

<ipython-input-10-67d0e5c25547> in <module>()
----> 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)

<ipython-input-13-ab4851d800b4> in <module>()
      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)

<ipython-input-23-95ffc99bad65> in <module>()
      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']
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值