Python的核心对象类型
1、Python语法的基础:
1.1 Python程序的层次结构:
程序由模块组成,模块是以.py结尾的文本文件
模块包含语句
语句包含表达式
表达式创建和处理对象
1.2 使用Python的基本语法:
使用import语句导入模块
Python按照从上到下的顺序依次执行语句
Python以缩进来组织代码结构,安照PEP8规范缩进为4个空格
Python变量要先赋值再调用
#为注释,#号后的代码不会被执行
获取对象的属性:object.attributes
调用对象的方法:object.method()
1.3 第一个Python程序:
文件模式
打开Python IDLE -> FILE -> NEW FILE
输入如下代码:
#导入datetime模块
import datetime
# 获取当前时间
current_time = datetime.datetime.now().time()
# 判断当前时间是否早于12点
if current_time.hour < 12:
print("早上好")
else:
print("下午好")
交互式解释器模式:
输入如下代码,">>>"和"..."为提示符,无需输入:
>>>import datetime
>>>current_time = datetime.datetime.now().time()
>>>if current_time.hour < 12:
... print("早上好")
>>>else:
... print("下午好")
2、Python的内置的对象类型
2.1 Python的内置的对象类型:
对象类型 |
名称 |
创建对象的方法 |
Numbers |
数值类型 |
1234, 3.1415, 3+4j, 0b111, Decimal(), Fraction() |
Strings |
字符串 |
'spam', "Bob's", b'a\x01c', u'sp\xc4m' |
Lists |
列表 |
[1, [2, 'three'], 4.5], list(range(10)) |
Dictionaries |
字典 |
{'food': 'spam', 'taste': 'yum'}, dict(hours=10) |
Tuples |
元组 |
(1, 'spam', 4, 'U'), tuple('spam'), namedtuple |
Files |
文件 |
open('eggs.txt'), open(r'C:\ham.bin', 'wb') |
Sets |
集合 |
set('abc'), {'a', 'b', 'c'} |
2.1 使用内置类型的优点:
2.1.1 简化编程:内置对象提供强大、方便的工具,如列表和字典,使得解决简单任务变得轻松,减少了开发复杂数据结构的需求。
2.1.2 易于扩展:对于复杂任务,内置对象可以作为基础,通过自定义Python类或C接口进一步扩展功能。
2.1.3 高性能:内置对象通常使用C语言编写,通常比自定义数据结构更高效,提供了更好的性能表现。
2.1.4 一致性和标准化:内置对象是Python标准的一部分,始终保持一致,减少了依赖第三方框架的不确定性。
3 数值类型
Python中的常见数值类型工具包括:整数(integer)和浮点数(floating),复数(complex),固定精度十进制数(decimal),
有理数(fraction),集合(sets),布尔类型(booleans),内建的与数值相关函数和模块(round,math,random等等),
表达式(位与&,十六进制0x1A等等),第三方库(例如向量,数据可视化等等)。
3.1 常见的数值类型
3.1.1 整数(integers):Python的整数类型(integers)是一个不限制大小的数值类型,它能够自动扩展以容纳任意精度的整数值。
3.1.2 浮点数(floating-point):Python的浮点数类型(floating-point)表示带有小数部分的数值,基于双精度(64位)浮点数标准,具有有限的精度和范围。64位浮点数可以表示非常大或非常小的数,大约在10的负308次方到10的308次方之间。适用于大多数科学计算和工程应用。
3.1.3 复数(complex):Python的复数类型(complex)表示具有实部和虚部的数值,形式为 a + bj,其中 a 是实部,b 是虚部,j 表示虚数单位。
3.1.4 固定精度小数(decimals):Python的 固定精度小数类型decimal提供了精确的十进制浮点数运算,适用于高精度计算,尤其是财务和货币应用场景。
3.1.5 有理数(fractions):Python的有理数类型(fractions)用于表示有理数,以分子和分母的形式精确存储和计算分数值。例:三分之一可以表示为Fraction(1, 3)
3.1.6 布尔类型(Booleans):Python的布尔类型(Booleans)表示逻辑值,只有两个取值:True 和 False,用于条件判断和逻辑运算。
表1-1 Python 表达式运算符及优先级,操作符的优先级按从低到高排列,例如加法的优先级低于乘法
|
操作符 |
描述 |
|
yield x |
生成器函数(Generator function send protocol) |
|
lambda args: expression |
匿名函数生成器(Anonymous function generation) |
|
x if y else z |
if三元表达式(Ternary selection) |
|
x or y |
逻辑或(Logical OR) |
|
x and y |
逻辑与(Logical AND) |
|
not x |
逻辑非(Logical negation) |
|
x in y, x not in y |
包含测试(Membership) |
|
x is y, x is not y |
对象测试(Object identity tests) |
|
x < y, x <= y, x > y, x >= y, x == y, x != y |
比较(Magnitude comparison, set subset and superset; Value equality operators) |
|
x | y |
位或(Bitwise OR) |
|
x ^ y |
位异或(Bitwise XOR) |
|
x & y |
位与(Bitwise AND) |
|
x << y, x >> y |
位移操作符(Shift x left or right by y bits) |
|
x + y, x – y |
加法,连接(Addition,concatenation)减法,集合的差集(Subtraction, set difference) |
|
x * y, x % y, x / y, x // y |
乘法,重复(Multiplication, repetition;)余数,格式化(Remainder, format;)除法,整除(Division: true and floor) |
|
−x, +x |
复数,正数(Negation, identity) |
|
˜x |
位运算非(inversion) |
|
x ** y |
指数运算(exponentiation) |
|
x[i] |
索引(Indexing) |
|
x[i:j:k] |
切片(Slicing) |
|
x(...) |
函数调用(Call) |
|
x.attr |
获取属性(Attribute reference) |
|
(...) |
元组,表达式,生成器表达式(Tuple, expression, generator expression) |
|
[...] |
列表,列表推理表达式(List, list comprehension) |
|
{...} |
字典,集合,集合与字典推理表达式(Dictionary, set, set and dictionary comprehensions) |
>>>123 + 222 #整数加法,使用+号执行加法
>>>1.5 * 4 #浮点数乘法,使用*号执行乘法
>>>2 ** 100 # 2的100次方,使用**号执行幂运算
创建二进制,八进制,十六进制对象的语法:
>>>0b111 #二进制以0b/0B(数字0和字母b,大小写皆可)开头
>>>0o111 #八进制以0o/0O(数字0和字母o,大小写皆可)开头
>>>0x111 #十六进制以0x/0X(数字0和字母x,大小写皆可)开头
整数的精度,在Python中整数拥有无限精度:
>>>#import sys
>>>#sys.set_int_max_str_digits(0) #取消最大数字位数限制
>>>len(str(2 ** 1000000)) #2的1000000次方有多少位?
不同类型的数相加,会自动将精度低的数值转化为精度高的数值,然后再进行计算:
>>>40 + 3.14 #整数加浮点数,结果为浮点数
复数由实部和虚部组成,在Python内部,复数实际上是由一对浮点数组成的。
>>>(2 + 1j) * 3 #复数乘法
>>>import math #导入math库,math库包含很多常用的数学工具
>>>math.pi #圆周率
>>>math.sqrt(85) #开根号
>>>import random #导入random模块
>>>random.random() #生成随机数
>>>random.choice([1, 2, 3, 4]) #从列表中随机选取一个元素
操作符重载与多态性:
Python中所有的操作符都可以自定义,例如Python中的加法(+),实际上是调用对象的__add__方法,我们可以自定义__add__方法来改变加法的行为。
此外,Python自动重载一些操作符,根据处理的内置对象类型执行不同的操作。比如,+ 在数字间执行加法,而在序列(如字符串和列表)间执行拼接。这种行为被称为多态性,操作的意义取决于操作对象的类型。
后面的章节我们将会详细学习。
变量与基础表达式:
变量在首次赋值时被创建。
变量在表达式中使用时会被替换为它们的值。
变量必须在使用于表达式之前赋值。
变量引用对象,且无需提前声明。
数字的显示格式:
>>>num = 1 / 3.0
>>>num
>>>'%4.2f' % num # '%4.2f' 表示格式化为至少4个字符宽,包括小数点和小数点后2位数字的浮点数
数值的比较:
>>>X = 2; Y = 4; Z = 6
>>>X < Y < Z #等效于X < Y and Y < Z
除法与整除:
>>>10 / 4
>>>10 // 4
>>>import math
>>>math.floor(10 / 4)
4 字符串类型
字符串用于记录文本信息(例如你的名字),也可用于记录任意字节集合(如图像文件的内容)。 它们是我们在Python中所学的第一个序列类型————即按位置顺序排列的对象集合。 序列保持其包含项的从左到右顺序:这些项通过相对位置存储和获取。严格来说,字符串是由单字符组成的序列。 其他更通用的序列类型包括列表和元组,稍后会详细介绍。
字符串的三种类型:
str:str是Python用于表示文本的默认字符串类型,它是不可变的,str用于表示文本数据。
bytes:bytes是一种不可变的类型,用于表示二进制数据,它由一系列数字(字节值)组成,通常用于处理非文本二进制数据,bytes用于表示原始的字节数据(即二进制数据)。
bytearray:bytearray 是 bytes 的可变版本,它允许你修改字节序列。
>>>a = 'hello'; b = b'hello'
>>>list(a)
>>>list(b)
创建字符串:
使用单引号或者双引号创建字符串,单引号和双引号是一样的。
使用三个引号(单引号或者双引号都可以)创建跨行字符串。
>>>"可达鸭"
>>>"""
可达鸭是《宝可梦》系列中一种广受欢迎的水属性宝可梦,
以其呆萌的外表和独特的头痛特性而闻名。它那圆圆的身体、大大的眼睛和常常显得困惑的表情,
让它成为了粉丝心中的萌物。在战斗中,可达鸭虽然速度较慢,但拥有不错的特殊攻击能力,
且在头痛达到一定程度时,能够发挥出惊人的力量。当可达鸭达到33级时,会进化为更强大的哥达鸭,进一步提升其战斗性能。
无论是在游戏中还是在动画、漫画等衍生作品中,可达鸭都是一个深受喜爱的角色。
"""
4.1 字符串的序列操作
字符串作为序列类型,支持序列类型的操作。
4.1.1 字符串的索引
>>>S = 'Spam' #包含4个字符的字符串
>>>len(S) #使用内置的len函数获取字符串长度
>>>S[0] #字符串的索引操作,从0开始计数,表示从起始位置的偏移量(offset),这样第一个元素的偏移量为0
>>>S[1] #字符串的索引操作
>>>S[-1] #反向索引,从右向左
>>>S[len(S)-1] #索引支持表达式,结果等于S[-1]
4.1.2 字符串的切片
>>>S #包含4个字符的字符串
>>>S[1:3] #字符串切片,包含下界1,不包含上界3
>>>S[1:] #字符串切片,表示从1之后的所有元素
>>>S[:3] #字符串切片,表示从0开始到3(不含上界3)的所有元素
>>>S[:-1] #字符串切片,表示从0开始到最后一个(-1)元素(不含上界-1)的所有元素
>>>S[:] #S的所有元素,等于S[0:len(S)]
4.1.3 字符串连接
>>>S
>>>S + 'XYZ' #多态性,+号对于字符串而言为连接字符串
>>>S * 8 #多态性,*号对于字符串而言为重复
4.2 不可变对象(Immutability)
字符串为不可变对象,即创建后不可修改
>>>S = "可达鸭"
>>>S[0] = '小' #将字符串的第1(偏移量为0)个元素修改为'z'
>>>S = '小' + S[0:] #实际上并没有修改,而是创建的一个新的对象'zpam',并把这个新的对象命名为S
>>>S
>>>S = '可达鸭'
>>>L = list(S) #将字符串转换为列表,列表为可变对象(mutability)
>>>L
>>>L[0] = '小' #将列表的第2个元素,修改为'c'
>>>''.join(L) #将列表重新连接为字符串
4.3 字符串的特殊操作
前面介绍了序列对象支持的一些操作,字符串作为一种序列对象,也支持这些操作。 现在介绍仅适用于字符串对象的操作。
4.3.1 查找字符串
>>>S = 'Spam'
>>>S.find('pa') #在字符串S中查找子字符串如果找到,则返回偏移值
4.3.2 替换字符串
>>>S.replace('pa', 'XYZ') #返回一个新的对象
>>>S #字符串为不可变对象,还是原来的值
4.3.3 字符串拆分
>>>line = 'aaa,bbb,ccccc,dd'
>>>line.split(',') #以','为间隔拆分字符串
4.3.4 字符串大小写转换
>>>S = 'spam'
>>>S.upper() #转换为大写
4.3.5 字符串内容测试,测试是否为字母(isalpha)测试是否为数字(isdigit)
>>>S.isalpha() #测试是否为字母
4.3.6 去除行末尾的空白字符
如果不提供任何参数,rstrip() 会删除字符串末尾的所有空白字符,包括空格、制表符、换行符等。 使用readline()方法按行读取文件时,右侧会以\n(换行符)结束,rstrip() 方法在处理从文件中读取的文本行时非常有用,尤其是在清理每行末尾的空白字符时。
>>>line = 'aaa,bbb,ccccc,dd\n'
>>>line.rstrip() #去除右边的括号,字符串为不可变对象,操作后返回新对象
>>>line.rstrip().split(',') #去除右边括号,将字符串分列,合并操作
4.3.7 字符串的格式化输出
方法一:格式化表达式() Python字符串格式化表达式是一种构建字符串的方式,它允许通过占位符和格式化操作来插入变量、表达式或对象的值,从而生成动态的、定制化的文本输出。 详情参考:https://www.runoob.com/python/python-strings.html,“Python 字符串格式化”一节
>>>'%s, eggs, and %s' % ('spam', 'SPAM!') #'#'为占位符,'s'表示字符串
方法二:字符串格式化方法 详情参考:https://www.runoob.com/python/att-string-format.html
>>>'{}, eggs, and {}'.format('spam', 'SPAM!') #使用format()方法进行字符串格式化,其中{}是占位符,分别被'spam'和'SPAM!'替换
>>>'{0}, eggs, and {1}'.format('spam', 'SPAM!') #使用format()方法进行字符串格式化,其中{0}和{1}是索引占位符,分别被'spam'和'SPAM!'替换
>>>'{:,.2f}'.format(296999.2567) #使用format()方法格式化浮点数,其中':,.2f'指定了格式化的样式:以逗号分隔千位,保留两位小数
>>>'%.2f | %+05d' % (3.14159, −42) #使用百分号(%)格式化操作符来格式化字符串,其中%.2f用于格式化浮点数为两位小数,%+05d用于格式化整数为至少5位宽,包括正负号
方法三:f-string字符串格式化 Python的F-string是一种格式化字符串的方式,通过在字符串前加上f,可以在字符串中直接嵌入表达式并进行格式化,从而简化了字符串的插值操作。
>>>name = "可达鸭"
>>>age = 6
>>>f"Hello, my name is {name} and I am {age} years old." #{name}和{age}将插入变量的值
4.3.8 字符串的转换
>>>"42" + 1 #报错字符串不能和整数相加
>>>int("42") + 1 #先将字符串转换成整数,然后相加
>>>"42" + str(1) #将整数1转换成字符串,然后进行字符串连接
5 列表
Python列表对象是该语言提供的最常用的序列类型。列表是按位置有序的、可以包含任意类型对象的集合,并且它们没有固定大小。 与字符串不同,列表是可变的,列表可以通过对偏移量的赋值以及多种列表方法调用来就地修改。 因此,列表是一种非常灵活的工具,可以用于表示任意的集合——文件夹中的文件列表、公司中的员工、你的收件箱中的电子邮件等。
列表的特点:
1、按位置将对象有序排列
2、通过位置来获取元素的值
3、列表的长度可以改变,支持任意嵌套
4、是一种可变的序列对象
5、列表是指向引用对象的指针数组
5.1 列表的序列操作
和字符串一样,列表也是一种序列类型,也支持序列类型的通用操作。
5.1.1 获取列表的长度
>>>L = [123, 'spam', 1.23]
>>>len(L) #查看列表包含多少个元素
5.1.2 列表的索引与切片
>>>L[0]
>>>L[:-1]
5.1.3 列表的加法与乘法
>>>L + [4, 5, 6] #连接列表,创建并返回一个新的对象
>>>L * 2
>>>L #原始的列表对象并没有被修改
5.2 列表的特定操作
5.2.1 增加一个列表元素
>>>L.append('NI') #使用append方法增加一个元素
>>>L
5.2.2 删除列表中的一个元素
>>>item = L.pop(2) #pop方法会直接修改列表,并返回被删除的元素
>>>L
>>>item #被删除的元素
5.2.3 列表排序
>>>M = ['bb', 'aa', 'cc']
>>>M.sort() #使用sort方法对列表排序
>>>M
>>>M.reverse() #反向排序
>>>M
5.2.4 边界检查
>>>L
>>>L[99] #越界
>>>L[99] = 1 #赋值越界
5.2.5 列表的嵌套
>>>M = [[1, 2, 3],[4, 5, 6],[7, 8, 9]] #列表嵌套列表组成二维列表
>>>M[1] #获取列表第2行
>>>M[1][2] #获取列表第2行第3个元素
5.2.6 列表推理表达式
>>>col2 = [row[1] for row in M] #获取每一行的第2个元素
>>>col2
>>> [row[1] + 1 for row in M] #第2列的每一个元素+1
>>> [row[1] for row in M if row[1] % 2 == 0] #使用if过滤不符合条件的元素,即每一行第2个元素中能被2整除的元素
>>>diag = [M[i][i] for i in [0, 1, 2]] #获取矩阵的对角线(diagonal)
>>>diag
>>>doubles = [c * 2 for c in 'spam'] #重复字符串中的字符
>>>doubles
>>>list(range(4)) #使用range()函数生成连续的整数
>>>list(range(−6, 7, 2)) #range()函数第1个参数为起始位置,第2个参数为结束位置,第3个参数为步进。即从-6到7(不含上界)间隔为2的数字。
>>> [[x ** 2, x ** 3] for x in range(4)] # 使用列表推导式生成一个新列表,其中包含从0到3的每个数字的平方和立方
>>> [[x, x / 2, x * 2] for x in range(−6, 7, 2) if x > 0] # 使用列表推导式生成一个新列表,其中包含从-6到6(步进为2)的每个正数x的列表,
>>># 每个列表包含x本身、x除以2的结果和x乘以2的结果
>>># 条件语句if x > 0确保只处理正数
>>>G = (sum(row) for row in M) #创建一个生成器来求每行之和,后面会对生成器做详细介绍。
>>>next(G)
>>>list(map(sum, M)) #将列表的每一行映射到sum函数,用于求每一行之和。
>>>{i : sum(M[i]) for i in range(3)} #使用列表推理表达式创建字典(key/value)
>>> [ord(x) for x in 'spaam'] #使用列表推理表达式创建Unicode代码点的列表
>>>{ord(x) for x in 'spaam'} #使用列表推理表达式创建Unicode代码点的集合
>>>{x: ord(x) for x in 'spaam'} #使用列表推理表达式创建Unicode代码点的字典
>>> (ord(x) for x in 'spaam') #使用列表推理表达式创建Unicode代码点的生成器表达式
6 字典
字典不是序列类型,不通过位置(不维护任何可靠的从左到右的顺序)来存储对象,而是通过键来存储对象。 字典通常被称为映射,字典将键映射到关联的值。 字典,作为Python核心对象集中唯一的映射类型,也是可变的:像列表一样,它们可以就地更改,并且可以根据需要增长和缩小。像列表一样,它们是表示集合的灵活工具,但它们的更具助记性的键更适合于集合的项目被命名或标记的情况——例如数据库记录的字段。
字典的特点:
1、通过键来获取元素
2、对象的排列没有顺序
3、长度可以变,支持任意嵌套
4、是一种可变的映射类型
5、字典利用哈希表这种数据结构来存储对象的引用,从而实现快速的键值检索。
6.1 映射操作
>>>D = {'food': 'Spam', 'quantity': 4, 'color': 'pink'}
>>>D['food'] #通过键‘food’来获取值
>>>D['quantity'] += 1 #增加'quantity'的值
>>>D = {} #也可以使用空{}来创建一个字典对象,等效于D = dict()
>>>D['name'] = 'Bob' #通过赋值创建key
>>>D['job'] = 'dev'
>>>D['age'] = 40
>>>D
>>>print(D['name']) #打印键"name"的值
>>>bob1 = dict(name='Bob', job='dev', age=40) #使用关键字创建字典
>>>bob1
>>>bob2 = dict(zip(['name', 'job', 'age'], ['Bob', 'dev', 40])) #使用zip函数创建字典,zip函数将多个可迭代对象(如列表或元组)中的元素按位置配对,生成一个由元组组成的迭代器。
>>>bob2
字典获取元素与列表或者元素的区别:
>>>L = [1, 2, 3]; D = {"a":1, "b":2, "c":3}
>>>L[0] #通过位置获取
>>>D["a"] #通过键获取
6.2 回顾嵌套
在前面的例子中,我们使用了一个字典来描述一个假想的人,包含三个键。然而,假设信息更加复杂。也许我们需要记录一个名和一个姓,以及多个职位头衔。我们使用Python字典的嵌套来组织更有结构的信息:
>>>rec = {'name': {'first': 'Bob', 'last': 'Smith'}, 'jobs': ['dev', 'mgr'], 'age': 40.5} #字典中嵌套列表
>>>rec['name'] #获取"name"的值
>>>rec['name']['last'] #获取"name"的值中的"last"的值
>>>rec['jobs'] #获取"jobs"的值
>>>rec['jobs'][-1] #获取"jobs"值中的最后一个值
>>>rec['jobs'].append('janitor') #直接修改"jobs"嵌套的列表中的值
>>>rec
展示这个例子的真正目的是要展示Python核心数据类型的灵活性。正如你所见,嵌套允许我们直接且轻松地构建复杂的信息结构。在像C这样的低级语言中构建类似的结构将会非常繁琐,需要编写更多的代码:我们需要布局和声明结构体和数组,填写值,将一切链接在一起等等。在Python中,这一切都是自动的——运行表达式就为我们创建了整个嵌套对象结构。实际上,这是像Python这样的脚本语言的主要优势之一。
同样重要的是,在低级语言中,我们必须小心地清理不再需要的对象空间。在Python中,当我们失去对对象的最后一个引用时——例如,通过将变量赋给其他东西——那个对象结构所占用的所有内存空间就会自动为我们清理掉。
>>>rec = 0 #对象不在被引用时Python的内存管理机制将自动回收内存
6.3 使用if测试键是否存在
>>>D = {'a': 1, 'b': 2, 'c': 3}
>>>D
>>>D['e'] = 99 #通过赋值创建新的key
>>>D
>>>D['f'] #引用不存在的键错误
>>>'f' in D #使用in测试键是否存在
>>>if not 'f' in D: #if测试语句
... print('missing')
>>>if not 'f' in D: #如果if测试成立(结果为True),则执行缩进代码块中的语句
... print('missing') #缩进代码块d
... print('no, really...')
>>>value = D.get('x', 0) #使用字典的get方法来获取"x"的值,如果值不存在,则返回0(方法第2个参数为当值不存在是返回的值)
>>>value = D['x'] if 'x' in D else 0 #使用if三元表达式和上一行语句等效
6.4 字典的键排序与for循环
>>>D = {'a': 1, 'b': 2, 'c': 3}
>>>D
>>>Ks = list(D.keys()) #获取字典的keys并存储为列表
>>>Ks
>>>Ks.sort() #将列表排序
>>>Ks
>>>for key in Ks: #通过迭代遍历每一个key的值
... print(key, '=>', D[key])
>>>D
>>>for key in sorted(D): #等效上面的3个步骤
... print(key, '=>', D[key])
上面的例子除了展示字典的使用,还介绍了Python的for循环。for循环是一种简单高效的遍历序列中所有项目并依次对每个项目运行代码块的方法。
使用循环变量(这里是"key"),来引用每次迭代中的项目。在我们的示例中,最终效果是按键的排序顺序打印无序字典的键和值。
for循环和while循环是我们在脚本中编码重复任务的主要方式。然而,for循环像前面介绍的列表推导式一样,实际上是一个序列操作。
像列表推导式一样,它适用于任何序列对象,并且甚至适用于一些非序列对象。例如,它可以遍历字符串中的字符,打印每个字符的大写版本:
>>>for c in 'spam':
... print(c.upper())
>>>x = 4 #与for循环等效,但for循环更简洁
>>>while x > 0:
... print('spam!' * x)
... x -= 1
6.5 迭代
>>>squares = [x ** 2 for x in [1, 2, 3, 4, 5]] #列表推理表达式
>>>quares
>>>squares = [] #for循环,与上面的代码等效
>>>for x in [1, 2, 3, 4, 5]:
... squares.append(x ** 2)
>>>squares
如上面的两个例子所示,列表推理表达式和for循环都是通用的迭代工具,
实际上,两者都可以在遵循迭代协议的任何可迭代对象上工作,在Python中迭代协议是普遍的概念。
简而言之,如果一个对象是物理存储在内存中的序列,或者在迭代操作的上下文中一次生成一个项目的“虚拟”序列,那么它就是可迭代的。
更正式地说,这两种类型的对象都被认为是可迭代的,是因为它们支持迭代协议:
通过调用iter返回一个可迭代对象,然后调用next函数生成下一个值,直到所有的值都被处理完,然后抛出一个StopIteration异常。
>>>l = [1, 2, 3]
>>>i = iter(l) #调用iter函数返回一个可迭代对象
>>>i
>>>next(i) #调用next函数产生下一个值,直到产生完所有值,抛出一个StopIteration异常
前面例子中的生成器(generator)对象,它的值并不是直接保存在内存中的,而是安装需求依次产生。
例如使用迭代工具,在每次迭代中生成一个值,这个可以减少内存的占用,还可以节省程序运行的时间,我们不必等待所有的值都产生完,才执行下一步指令。
Python中的文件对象也与此相似,我们使用迭代工具,依次读取每一行的文件内容。
我们将在后续部分详细学习Python的可迭代对象,现在我们只需要记住Python 使用迭代协议来从左到右扫描可迭代对象。
所以字典可以直接使用sort方法,而不需要使用keys方法来获取字典的键列表,因为字典也是可迭代对象。
使用map、filter等函数式编程工具的速度比使用for循环更快(通常快一倍左右),当我们处理较大的数据集时,可迭代工具会具有更好的性能,
按照Python编程经验,我们应该优先考虑代码的简洁性和可读性,然后再考虑代码的性能优化,我们会在后续的章节中学习代码性能测试方法。
7 元组
元组也是一种序列类型,支持嵌套,以及常见的序列操作。元组和列表非常相似,但是元组是不可变对象(immutable)。
7.1 元组的序列操作
>>>T = (1, 2, 3, 4) #4个元素的元组
>>>len(T) #查看元组长度
>>>T + (5, 6)。#元组连接
>>>T[0] #元组索引
7.2 元组的特定操作
>>>T.index(4) #元组方法,元素4出现的位置(offset)
>>>T.count(4) #4出现的次数
7.3 元组是不可变对象(immutable)
>>>T[0] = 2 #对元组中的元素赋值,会报错
>>>T = (2,) + T[1:] #创建一个新的元组对象,并赋值
>>>T
>>>T = 'spam', 3.0, [11, 22, 33]
>>>T[1]
>>>T[2][1] #支持嵌套
>>>T.append(4) #元组是不可变对象
为什么使用元组:
元组和列表非常相似,但是元组支持的操作比列表更少,那么我们为什么要使用元组呢?
实际上,列表在实践中更常用,但是元组和列表最大的区别在于不可变性,这样就提供了一种完整性约束,特别是在编写大型程序时,
可以保证我们通过元组传递的值不会被意外修改。
8 文件
文件对象是Python代码处理外部文件的一个主要接口。 可以被用于读取和写入文本数据、音频文件、Excel文档、存储email信息等等我们需要保存在电脑上的文件。 文件是Python的核心对象,使用内建的open函数,传入一个外部的文件名和处理模式来创建文件对象。例如:(f = open('data.txt', 'w'))
8.1 文件的基本操作
>>>f = open('data.txt', 'w') #创建文件对象
>>>f.write('Hello\n') #在文件对象f中写入"hello"和换行符"\n"
>>>f.write('world\n') #返回被写入项目的数量
>>>f = open('data.txt') #创建一个文件对象,默认的操作模式为读取
>>>text = f.read() #读取整个文件的内容
>>>text
>>>print(text) #打印文件内容,"\n"是换行符,print函数会将其解释为换行
>>>text.split() #文件的内容是字符串对象,支持使用split方法拆分
>>>for line in open('data.txt'): print(line) #文件是可迭代对象,可以使用for进行遍历
8.2 二进制文件
编码:内容 ——> 二进制数(二进制数据便于计算机存储和处理) 解码:二进制数据 ——> 内容
在UTF-8编码中,Unicode字符的高位模式是指字节中的高位(即字节的左边几位)的模式,这些位用于指示该字节在字符编码中的作用和位置。UTF-8是一种变长编码,可以使用1到4个字节来表示一个Unicode字符,具体使用多少个字节取决于字符的Unicode码点范围。
UTF-8编码的高位模式如下:
- 单字节字符(0xxxxxxx):对于ASCII字符(码点值在0到127之间),UTF-8编码与ASCII编码相同,只使用一个字节,最高位(第8位)为0。
- 双字节字符(110xxxxx 10xxxxxx):码点值在128到2047之间的字符使用两个字节。第一个字节的高位模式为
110,表明这是一个双字节字符的起始字节。第二个字节的高位模式为10,表明这是后续字节。 - 三字节字符(1110xxxx 10xxxxxx 10xxxxxx):码点值在2048到65535之间的字符使用三个字节。第一个字节的高位模式为
1110,表明这是一个三字节字符的起始字节。 - 四字节字符(11110xxx 10xxxxxx 10xxxxxx 10xxxxxx):码点值在65536以上的字符使用四个字节。第一个字节的高位模式为
11110,表明这是一个四字节字符的起始字节。
在UTF-8编码中,每个字节的高位模式不仅指示了字节的类型(起始字节或后续字节),还隐含了字符的Unicode码点范围。这种设计使得UTF-8编码具有自我同步的特性,即使编码流中的数据出现错误或丢失,解码器也能够从下一个有效的起始字节开始重新同步。
>>>unicode_code_point = ord('可') # 获取字符的Unicode代码点
>>>utf8_bytes = '可'.encode('utf-8') # 将字符编码为UTF-8字节序列
>>># 打印结果
>>>print(f"字符 '可' 的UTF-8编码是(16进制): {bytearray(utf8_bytes)}")
>>>print(f"字符 '可' 的UTF-8编码是(2进制): {' '.join(format(byte, '08b') for byte in utf8_bytes)}")
>>>print(f"字符 '可' 的Unicode代码点是: {unicode_code_point}")
>>>print(f"字符 '可' 的Unicode代码点是: {format(unicode_code_point, '08b')}")
假设某个字的UTF-8代码点为:b'\xe5\x8f\xaf',如何将二进制数据解码为文字: 将b'\xe5\x8f\xaf'用二进制表示 第一字节:11100101,以1110开头,说明这个字符为3个字节,
11100101 10001111 10101111
红色的位数为高位模式标记,将剩余的数字连接得到:0101 001111 101111,即为"可"字的Unicode代码点,转换为10进制得到21487,查表可知这个字为"可":
9 用户定义数据类型
>>>class Worker:
... def __init__(self, name, pay): #创建实例的时候会执行__init__方法(初始化方法)
... self.name = name #在这个例子中,传教实例需要传入两个参数"name","pay"
self.pay = pay
... def lastName(self): #为这个类型定义一个获取lastName的方法
... return self.name.split()[-1] #将名字以空格拆分
... def giveRaise(self, percent): #定义了一个加薪的方法,接收一个加薪的百分比参数
... self.pay *= (1.0 + percent)
>>>bob = Worker('Bob Smith', 50000) #创建两个实例
>>>sue = Worker('Sue Jones', 60000)
>>>bob.lastName() #调用自定义的方法lastName
>>>sue.giveRaise(.10) #调用自定义方法giveRaise
这里我们定义了一个类型:Worker,这个类型需要提供name和pay进行初始化。
自定义的方法中的参数self代表,这个实例本身,后面我们学习类和面向对象编程时会详细说明。
10 获取帮助
Python中有非常多的内置对象,这些内置对象又很很多的属性和方法,我们不可能全都一一记住这些对象以及属性和方法,
这时我们可以使用dir函数来查看对象包含的属性和方法。
使用help函数来查看方法应该如何使用。
>>>f = open('data.txt', 'w')
>>>dir(f)
在Python中,以双下划线开头的方法(如__init__)通常是特殊方法(又称魔术方法),它们定义了对象的特定行为或与内置操作的交互。在后续的操作符重载中会详细介绍。
>>>help(f.readline)
>>>dir([])
>>>help([].append)
notebook链接:https://www.kaggle.com/code/jeanshendev/python-types-and-operations