02.python线性数据结构


内建常用数据类型

分类

数值型

  • int、float、complex、bool

序列sequence

  • 字符串str、字节序列bytes、bytearray
  • 列表list、元组tuple

键值对

  • 集合set、字典dict

数值型

  • int、float、complex、bool都是class,1、5.0、2+3j都是对象即实例
  • int:python3的int就是长整型,且没有大小限制,受限于内存区域的大小
  • float:由整数部分和小数部分组成。支持十进制和科学计数法表示。C的双精度型实现
  • complex:有实数和虚数部分组成,实数和虚数部分都是浮点数,3+4.2J
  • bool:int的子类,仅有2个实例True、False对应1和0,可以和整数直接运算

类型转换

  • int、float、complex、bool也可以当做内建函数对数据进行类型转换
  • int(x) 返回一个整数
  • float(x) 返回一个浮点数
  • complex(x)、complex(x,y) 返回一个复数
  • bool(x) 返回布尔值,前面讲过False等价的对象

取整

math模块的floor()、ceil()函数;内建函数int()、round();运算符//

# 整除
print(3//2, 5//2, 7//2)
print(-3//2, -5//2, -7//2)
print(7//2, 7//-2, -7//2, -(7//2))
# int
print('int ------------')
print(int(1.4), int(1.5), int(1.6))
print(int(-1.4), int(-1.5), int(-1.6))
# ceil floor
print('ceil floor ------------')
import math
print(math.floor(2.5), math.floor(-2.5))
print(math.ceil(2.5), math.ceil(-2.5))
# round
print('round ------------')
print(round(1.4), round(-1.4), round(-1.6), round(1.6))
  • round(),四舍六入五取偶
  • math.floor()向下取整
  • math.ceil()向上取整
  • int() 取整数部分
  • // 整除且向下取整

常用数值处理函数

  • min()、max()
  • abs()
  • pow(x, y) 等于 x ** y
  • math.sqrt() 等于 x ** 0.5
  • 进制函数,返回值是字符串
    • bin()、oct()、hex()
  • math模块
    • math.pi π
    • math.e 自如常数
    • math模块中还有对数函数、三角函数等
type(123) # 返回的是类型int
isinstance(456, int)
isinstance(True, (str, int, bool))
type(1 + True)
type(1 + True + 2.0) # 什么类型?

即使是强类型语言,也会有隐式类型转换。

线性数据结构

线性表

  • 线性表(简称表),是一种抽象的数学概念,是一组元素的序列的抽象,它由有穷个元素组成(0个或任意个)

  • 顺序表:使用一大块连续的内存顺序存储表中的元素,这样实现的表称为顺序表,或称连续表

    在顺序表中,元素的关系使用顺序表的存储顺序自然地表示

  • 链接表:在存储空间中将分散存储的元素链接起来,这种实现称为链接表,简称链表

列表如同地铁站排好的队伍,有序,可以插队、离队,可以索引。

链表如同操场上手拉手的小朋友,有序但空间排列随意。或者可以想象成一串带线的珠子,随意盘放在桌上。也可以离队、插队,也可以索引。

对比体会一下,这两种数据结构的增删改查。

列表list

  • 一个排列整齐的队伍,Python采用顺序表实现
  • 列表内的个体称作元素,由若干元素组成列表
  • 元素可以是任意对象(数字、字符串、对象、列表等)
  • 列表内元素有顺序,可以使用索引
  • 线性的数据结构
  • 使用 [ ] 表示
  • 列表是可变的

列表是非常重要的数据结构,对其内存结构和操作方法必须烂熟于心。

初始化

  • list() -> new empty list
  • list(iterable) -> new list initialized from iterable's items
  • []
  • 列表不能一开始就定义大小

索引

  • 索引,也叫下标
  • 正索引:从左至右,从0开始,为列表中每一个元素编号
  • 如果列表有元素,索引范围[0, 长度-1]
  • 负索引:从右至左,从-1开始
  • 如果列表有元素,索引范围[-长度, -1]
  • 正、负索引不可以超界,否则引发异常IndexError
  • 为了理解方便,可以认为列表是从左至右排列的,左边是头部,右边是尾部,左边是下界,右边是上界
  • 列表通过索引访问,list[index] ,index就是索引,使用中括号访问

使用索引定位访问元素的时间复杂度为O(1),这是最快的方式,是列表最好的使用方式。

查询

  • index(value,[start,[stop]])

    • 通过值value,从指定区间查找列表内的元素是否匹配
    • 匹配第一个就立即返回索引
    • 匹配不到,抛出异常ValueError
  • count(value)

    • 返回列表中匹配value的次数
  • 时间复杂度

    • index和count方法都是O(n)
    • 随着列表数据规模的增大,而效率下降
  • 如何返回列表元素的个数?如何遍历?如何设计高效?

    len()

修改

  • 索引定位元素,然后修改。注意索引不能超界
ls1 = [1,2,3,4]
ls1[2] = 200

增加单个元素

  • append(object) -> None
    • 列表尾部追加元素,返回None
    • 返回None就意味着没有新的列表产生,就地修改
    • 定位时间复杂度是O(1)
  • insert(index, object) -> None
    • 在指定的索引index处插入元素object
    • 返回None就意味着没有新的列表产生,就地修改
    • 定位时间复杂度是O(1)
  • 索引能超上下界吗?
    • 超越上界,尾部追加
    • 超越下界,头部追加

增加多个元素

  • extend(iteratable) -> None
    • 将可迭代对象的元素追加进来,返回None
    • 就地修改,本列表自身扩展
  • + -> list
    • 连接操作,将两个列表连接起来,产生新的列表,原列表不变
    • 本质上调用的是魔术方法__add__()方法
  • * -> list
    • 重复操作,将本列表元素重复n次,返回新的列表
ls1 = [1] * 5
ls2 = [None] * 6
ls3 = [1,2] * 3
ls4 = [[1]] * 3 

这个重复操作看似好用,如果原理掌握不好,但非常危险

x = [1] * 3 
x[0] = 100
print(x) # 结果是什么
y = [[1]] * 3
print(y) # 结果是什么
y[0] = 100
print(y) # 结果是什么
y1 = 200
print(y) # 结果是什么

在Python中一切皆对象,而对象都是引用类型,可以理解为一个地址指针指向这个对象。

但是,字面常量字符串、数值等表现却不像引用类型,暂时可以称为简单类型。

而列表、元组、字典,包括以后学习的类和实例都可以认为是引用类型。

你可以认为简单类型直接存在列表中,而引入类型只是把引用地址存在了列表中。

删除

  • remove(value) -> None
    • 从左至右查找第一个匹配value的值,找到就移除该元素,并返回None,否则ValueError
    • 就地修改
    • 效率?低
  • pop([index]) -> item
    • 不指定索引index,就从列表尾部弹出一个元素
    • 指定索引index,就从索引处弹出一个元素,索引超界抛出IndexError错误
    • 效率?指定索引的的时间复杂度?不指定索引呢?
  • clear() -> None
    • 清除列表所有元素,剩下一个空列表

反转

  • reverse() -> None
    • 将列表元素反转,返回None
    • 就地修改

这个方法最好不用,可以倒着读取,都不要反转。

排序

  • sort(key=None, reverse=False) -> None
    • 对列表元素进行排序,就地修改,默认升序
    • reverse为True,反转,降序
    • key一个函数,指定key如何排序,lst.sort(key=function)

如果排序是必须的,那么排序。排序效率高吗?

in成员操作

'a' in ['a', 'b', 'c'] 
[3,4] in [1, 2, 3, [3,4]]
for x in [1,2,3,4]:
    pass

列表复制

a = list(range(4))
b = list(range(4))
print(a == b) c = a c[2] = 10
print(a)
print(a == b) # 还相等吗?
print(a == c) # 相等吗?

问题:

  1. 最终a 和 b相等吗?a和b分别存着什么元素
  2. a 和 c 相等吗?为什么? c = a 这一句有复制吗?

下面的程序a和b相等吗?

a = list(range(4))
b = a.copy()
print(a == b) a[2] = 10
print(a == b)
a = [1, [2, 3, 4], 5] b = a.copy()
print(a == b) a[2] = 10
print(a == b) a[2] = b[2]
print(a == b) a[1][1] = 100
print(a == b) # 还相等吗?
print(a)
print(b)

列表的内存模型和深浅拷贝

  • shadow copy
    • 影子拷贝,也叫浅拷贝。遇到引用类型数据,仅仅复制一个引用而已
  • deep copy
    • 深拷贝,往往会递归复制一定深度

一般情况下,大多数语言提供的默认复制行为都是浅拷贝。

import copy
a = [1, [2, 3], 4] b = copy.deepcopy(a)
print(a == b) a[1][1] = 100
print(a == b) # 还相等吗?
print(a)
print(b)

Python内建数据类型,内部都实现了 == ,它的意思是内容比较

随机数

random模块

  • randint(a, b) 返回[a, b]之间的整数
  • randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数缺省值为1。 random.randrange(1,7,2)
  • choice(seq) 从非空序列的元素中随机挑选一个元素,比如
    • random.choice(range(10)),从0到9中随机挑选一个整数
    • random.choice([1,3,5,7])
  • 3.6开始提供choices,一次从样本中随机选择几个,可重复选择,可以指定权重
  • random.shuffle(list) ->None 就地打乱列表元素
  • sample(population, k) 从样本空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回一个新的列表
    • random.sample(['a', 'b', 'c', 'd'], 2)
    • random.sample(['a', 'a'], 2) 会返回什么结果
    • 每次从样本空间采样,在这一次中不可以重复抽取同一个元素
import random
for i in range(10):
    print(random.randint(1, 5))
print('-' * 30)
for i in range(10):
    print(random.randrange(1, 5))
print('-' * 30) x = [1, 2, 3, 4, 5]
for i in range(10):
    print(random.choice(x))
print('-' * 30)
# 观察下面的0和1的比例
for i in range(10):
    print(random.choices([0, 1], k=6))
print('-' * 30)
for i in range(10):
    print(random.choices([0, 1], [10, 1], k=6)) # 10比1权重
x = [1, 2, 3, 4, 5]
# 采样
for i in range(5):
    print(random.sample(x, 5)) # k能不能是6?

元组tuple

  • 一个有序的元素组成的集合
  • 使用小括号 ( ) 表示
  • 元组是不可变对象

初始化

  • tuple() -> empty tuple
  • tuple(iterable) -> tuple initialized from iterable's items
t1 = () # 空元组
t2 = (1,) # 必须有这个逗号
t3 = (1,) * 5
t4 = (1, 2, 3)
t5 = 1, 'a'
t6 = (1, 2, 3, 1, 2, 3)
t7 = tuple() # 空元组
t8 = tuple(range(5))
t9 = tuple([1,2,3])

索引

索引和列表规则一样,不可以超界

查询

方法和列表一样,时间复杂度也一样。index、count、len等

增删改

元组元素的个数在初始化的时候已经定义好了,所以不能为元组增加元素、也不能从中删除元素、也不能修改元素的内容。

但是要注意下面这个例子

t1 = ([1]) * 3
t1[1] = 100 # ?
# 注意下面的例子
t2 = ([1],) * 3
print(t2)
t2[1] = 100
t2[0][0] = 100
print(t2)

上例说明t2是可变的吗?不是说元组不可变吗?到底什么不可变

字符串str

  • 一个个字符组成的有序的序列,是字符的集合
  • 使用单引号、双引号、三引号引住的字符序列
  • 字符串是不可变对象,是字面常量

Python3起,字符串都是Unicode类型

初始化

s1 = 'string'
s2 = "string2"
s3 = '''this's a "String" '''
s4 = 'hello \n magedu.com'
s5 = r"hello \n magedu.com"
s6 = 'c:\windows\nt'
s7 = R"c:\windows\nt"
s8 = 'c:\windows\\nt'
name = 'tom'; age = 20 # python代码写在一行,使用分号隔开,不推荐
s9 = f'{name}, {age}' # 3.6支持f前缀
sql = """select * from user where name='tom' """

r前缀:所有字符都是本来的意思,没有转义

f前缀:3.6开始,使用变量插值

索引

字符串是序列,支持下标访问。但不可变,不可以修改元素。

sql = "select * from user where name='tom'"
print(sql[4]) # 字符串'c'
sql[4] = 'o' # 不可以

连接

  • 加号

    • 将2个字符串连接起来
  • 返回一个新的字符串

  • join方法

    • sep.join(iterable)
    • 使用指定字符串作为分隔符,将可迭代对象中字符串使用这个分隔符拼接起来
    • 可迭代对象必须是字符串
    • 返回一个新的字符串

字符查找

  • find(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub
    • 找到返回正索引,没找到返回-1
  • rfind(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从右至左,查找子串sub
    • 找到返回正索引,没找到返回-1
s = 'magedu.edu'
print(s.find('edu'))
print(s.find('edu', 3))
print(s.find('edu', 4))
print(s.find('edu', 6, 9))
print(s.find('edu', 7, 20))
print(s.find('edu', 200))
s = 'magedu.edu'
print(s.rfind('edu'))
print(s.rfind('edu', 3))
print(s.rfind('edu', 4))
print(s.rfind('edu', 6, 9))
print(s.rfind('edu', 7, 20))
print(s.rfind('edu', 200))

这两个方法只是找字符串的方向不同,返回值一样。找到第一个满足要求的子串立即返回。特别注意返

回值,找不到返回的是负数-1。

这两个方法效率高吗?要不要用?

这两个方法效率真不高,都是在字符串中遍历搜索,但是如果找子串工作必不可少,那么必须这么做,

但是能少做就少做。

  • index(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub
    • 找到返回正索引,没找到抛出异常ValueError
  • rindex(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub
    • 找到返回正索引,没找到抛出异常ValueError

index方法和find方法很像,不好的地方在于找不到抛异常。推荐使用find方法。

s = 'magedu.edu'
print(s.index('edu'))
print(s.index('edu', 3))
print(s.index('edu', 4))
#print(s.index('edu', 6, 9)) # 抛异常
print(s.index('edu', 7, 20))
#print(s.index('edu', 200)) # 抛异常
  • count(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,统计子串sub出现的次数
s = 'magedu.edu'
print(s.count('edu'))
print(s.count('edu', 4))
  • 时间复杂度
    • find、index和count方法都是O(n)
    • 随着字符串数据规模的增大,而效率下降
  • len(string)
    • 返回字符串的长度,即字符的个数

分割

  • split(sep=None, maxsplit=-1) -> list of strings
    • 从左至右
    • sep 指定分割字符串,缺省的情况下空白字符串作为分隔符
    • maxsplit 指定分割的次数,-1 表示遍历整个字符串
    • 立即返回列表
  • rsplit(sep=None, maxsplit=-1) -> list of strings
    • 从右向左开始切,但是输出的字符串字符不会反
    • sep 指定分割字符串,缺省的情况下空白字符串作为分隔符
    • maxsplit 指定分割的次数,-1 表示遍历整个字符串
    • 立即返回列表
  • splitlines([keepends]) -> list of strings
    • 按照行来切分字符串
    • keepends 指的是是否保留行分隔符
    • 行分隔符包括\n、\r\n、\r等
s = ','.join('abcd')
print(s.split(','))
print(s.split())
print(s.split(',', 2))
s1 = '\na b \tc\nd\n' # 注意下面3个切割的区别
print(s1.split())
print(s1.split(' '))
print(s1.split('\n'))
print(s1.split('b'))
print(s1.splitlines())
  • partition(sep) -> (head, sep, tail)
    • 从左至右,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组
    • 如果没有找到分隔符,就返回头、2个空元素的三元组
    • sep 分割字符串,必须指定
  • rpartition(sep) -> (head, sep, tail)
    • 从右至左,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组
    • 如果没有找到分隔符,就返回2个空元素和尾的三元组
s = ','.join('abcd')
print(s.partition(','))
print(s.partition('.'))
print(s.rpartition(','))
print(s.rpartition('.'))

替换

  • replace(old, new[, count]) -> str
    • 字符串中找到匹配替换为新子串,返回新字符串
    • count表示替换几次,不指定就是全部替换
s = ','.join('abcd')
print(s.replace(',', ' '))
print(s.replace(',', ' ', 2))
s1 = 'www.magedu.edu'
print(s1.replace('w', 'a'))
print(s1.replace('ww', 'a'))
print(s1.replace('ww', 'w')) # 返回什么?
print(s1.replace('www', 'a'))

移除

  • strip([chars]) -> str
    • 在字符串两端去除指定的字符集chars中的所有字符
    • 如果chars没有指定,去除两端的空白字符
  • lstrip([chars]) -> str ,从左开始
  • rstrip([chars]) -> str,从右开始
s = '\t\r\na b c,d\ne\n\t'
print(s.strip())
print('-' * 30)
print(s.strip('\t\n'))
print('-' * 30)
print(s.strip('\t\ne\r'))

首尾判断

  • endswith(suffix[, start[, end]]) -> bool
    • 在指定的区间[start, end),字符串是否是suffix结尾
  • startswith(prefix[, start[, end]]) -> bool
    • 在指定的区间[start, end),字符串是否是prefix开头
s = "www.magedu.edu"
print(s.startswith('ww'))
print(s.startswith('e', 7))
print(s.startswith('e', 10))
print(s.startswith('edu', 11))
print(s.endswith('edu'))

其它函数

  • upper()大写
  • lower()小写
  • swapcase() 交换大小写
  • isalnum() -> bool 是否是字母和数字组成
  • isalpha() 是否是字母
  • isdecimal() 是否只包含十进制数字
  • isdigit() 是否全部数字(0~9)
  • isidentifier() 是不是字母和下划线开头,其他都是字母、数字、下划线
  • islower() 是否都是小写
  • isupper() 是否全部大写
  • isspace() 是否只包含空白字符

其他格式打印函数中文几乎不用,大家自行查看帮助

格式化

简单的使用+或者join也可以拼接字符串,但是需要先转换数据到字符串后才能拼接。

C风格printf-style

  • 占位符:使用%和格式字符,例如%s、%d
  • 修饰符:在占位符中还可以插入修饰符,例如%03d
  • format % values
    • format是格式字符串,values是被格式的值
    • 格式字符串和被格式的值之间使用%
    • values只能是一个对象,可以是一个值,可以是一个元素个数和占位符数目相等的元组,也可以是一个字典
"I am %03d" % (20,)
'I like %s.' % 'Python'
"%3.2f%% 0x%x %#X" % (89.7654, 10, 256) # 宽度为3,小数点后2位
"I am %-5d" % (20,)
"%(host)s.%(domain)s" % {'domain':'magedu.com', 'host':'www'} # 靠名字对应

format函数

Python2.5之后,字符串类型提供了format函数,功能更加强大,鼓励使用。

"{} {xxx}".format(*args, **kwargs) -> str

  • args是可变的位置参数
  • kwargs是可变关键字参数,写作a=100
  • 使用花括号作为占位符
  • {}表示按照顺序匹配位置参数,{n}表示取位置参数索引为n的值
  • {xxx}表示在关键字参数中搜索名称一致的
  • {{}} 表示打印花括号
# 位置对应
"{}:{}".format('127.0.0.1', 8080)
# 位置或关键字对应
"{server} {1}:{0}".format(8080, '127.0.0.1', server='Web Server Info: ')
# 访问元素
"{0[0]}.{0[1]}".format(('magedu', 'com'))
# 进制
"{0:d} {0:b} {0:o} {0:x} {0:#X}".format(31)
# 浮点数
print("{}".format(3**0.5)) # 1.7320508075688772
print("{:f}".format(3**0.5)) # 1.732051,精度默认6
print("{:10f}".format(3**0.5)) # 右对齐,宽度10
print("{:2}".format(102.231)) # 宽度为2数字
print("{:2}".format(1))     # 宽度为2数字
print("{:.2}".format(3**0.5)) # 1.7 2个数字
print("{:.2f}".format(3**0.5)) # 1.73 小数点后2位
print("{:3.2f}".format(3**0.5))  # 1.73 宽度为3,小数点后2位
print("{:20.3f}".format(0.2745)) # 0.275
print("{:3.3%}".format(1/3)) # 33.333%
# 注意宽度可以被撑破
# 对齐
print("{}*{}={}".format(5, 6, 5*6))
print("{}*{}={:2}".format(5, 6, 5*6))
print("{1}*{0}={2:3}".format(5, 6, 5*6))
print("{1}*{0}={2:0>3}".format(5, 6, 5*6))
print("{}*{}={:#<3}".format(4, 5, 20))
print("{:#^7}".format('*' * 3))

字节序列

Python3 引入两个新的类型bytes、bytearray。

bytes不可变字节序列;bytearray是可变字节数组。

编码与解码

  • 编码:str => bytes,将字符串这个字符序列使用指定字符集encode编码为一个个字节组成的序列bytes
  • 解码:bytes或bytearray => str,将一个个字节按照某种指定的字符集解码为一个个字符串组成的字符串
print("abc".encdoe())        # 缺省为utf-8编码
print("啊".encode('utf-8'))
print("啊".encode('gbk'))
print(b'abc'.decode('utf8'))
print(b'\xb0\xa1'.decode('gbk'))

ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套单字节编码系统

基本ASCII码

前128个称为基本ASCII码,从二进制角度来看,它们的最高位bit[7]=0,只使用了低7位bit[6,0]来进行编码。
0~31 之间的ASCII码常用于控制像打印机一样的外围设备。

十进制DEC 八进制OCT 十六进制HEX 二进制BIN 符号Symbol HTML实体编码 中文解释Description
0 000 00 00000000 NUL ? 空字符
1 001 01 00000001 SOH ? 标题开始
2 002 02 00000010 STX ? 正文开始
3 003 03 00000011 ETX ? 正文结束
4 004 04 00000100 EOT ? 传输结束
5 005 05 00000101 ENQ ? 询问
6 006 06 00000110 ACK ? 收到通知
7 007 07 00000111 BEL ?
8 010 08 00001000 BS ? 退格
9 011 09 00001001 HT 水平制表符
10 012 0A 00001010 LF 换行键
11 013 0B 00001011 VT ? 垂直制表符
12 014 0C 00001100 FF 换页键
13 015 0D 00001101 CR 回车键
14 016 0E 00001110 SO ? 移出
15 017 0F 00001111 SI ? 移入
16 020 10 00010000 DLE ? 数据链路转义
17 021 11 00010001 DC1 ? 设备控制 1
18 022 12 00010010 DC2 ? 设备控制 2
19 023 13 00010011 DC3 ? 设备控制 3
20 024 14 00010100 DC4 ? 设备控制 4
21 025 15 00010101 NAK ? 拒绝接收
22 026 16 00010110 SYN ? 同步空闲
23 027 17 00010111 ETB ? 传输块结束
24 030 18 00011000 CAN ? 取消
25 031 19 00011001 EM ? 介质中断
26 032 1A 00011010 SUB ? 替换
27 033 1B 00011011 ESC ? 换码符
28 034 1C 00011100 FS ? 文件分隔符
29 035 1D 00011101 GS ? 组分隔符
30 036 1E 00011110 RS ? 记录分离符
31 037 1F 00011111 US ? 单元分隔符

32~127 之间的ASCII码表示的符号,在我们的键盘上都可以被找到。其中:32表示空格,127表示删除命令。

十进制DEC 八进制OCT 十六进制HEX 二进制BIN 符号Symbol HTML实体编码 中文解释Description
32 040 20 00100000 空格
33 041 21 00100001 ! ! 感叹号
34 042 22 00100010 " " 双引号
35 043 23 00100011 # # 井号
36 044 24 00100100 $ $ 美元符
37 045 25 00100101 % % 百分号
38 046 26 00100110 & &
39 047 27 00100111 ' ' 单引号
40 050 28 00101000 ( ( 左括号
41 051 29 00101001 ) ) 右括号
42 052 2A 00101010 * * 星号
43 053 2B 00101011 + + 加号
44 054 2C 00101100 , , 逗号
45 055 2D 00101101 - - 连字号或减号
46 056 2E 00101110 . . 句点或小数点
47 057 2F 00101111 / / 斜杠
48 060 30 00110000 0 0 0
49 061 31 00110001 1 1 1
50 062 32 00110010 2 2 2
51 063 33 00110011 3 3 3
52 064 34 00110100 4 4 4
53 065 35 00110101 5 5 5
54 066 36 00110110 6 6 6
55 067 37 00110111 7 7 7
56 070 38 00111000 8 8 8
57 071 39 00111001 9 9 9
58 072 3A 00111010 : : 冒号
59 073 3B 00111011 ; ; 分号
60 074 3C 00111100 < < 小于
61 075 3D 00111101 = = 等号
62 076 3E 00111110 > > 大于
63 077 3F 00111111 ? ? 问号
64 100 40 01000000 @ @ 电子邮件符号
65 101 41 01000001 A A 大写字母 A
66 102 42 01000010 B B 大写字母 B
67 103 43 01000011 C C 大写字母 C
68 104 44 01000100 D D 大写字母 D
69 105 45 01000101 E E 大写字母 E
70 106 46 01000110 F F 大写字母 F
71 107 47 01000111 G G 大写字母 G
72 110 48 01001000 H H 大写字母 H
73 111 49 01001001 I I 大写字母 I
74 112 4A 01001010 J J 大写字母 J
75 113 4B 01001011 K K 大写字母 K
76 114 4C 01001100 L L 大写字母 L
77 115 4D 01001101 M M 大写字母 M
78 116 4E 01001110 N N 大写字母 N
79 117 4F 01001111 O O 大写字母 O
80 120 50 01010000 P P 大写字母 P
81 121 51 01010001 Q Q 大写字母 Q
82 122 52 01010010 R R 大写字母 R
83 123 53 01010011 S S 大写字母 S
84 124 54 01010100 T T 大写字母 T
85 125 55 01010101 U U 大写字母 U
86 126 56 01010110 V V 大写字母 V
87 127 57 01010111 W W 大写字母 W
88 130 58 01011000 X X 大写字母 X
89 131 59 01011001 Y Y 大写字母 Y
90 132 5A 01011010 Z Z 大写字母 Z
91 133 5B 01011011 [ [ 左中括号
92 134 5C 01011100 \ \ 反斜杠
93 135 5D 01011101 ] ] 右中括号
94 136 5E 01011110 ^ ^ 音调符号
95 137 5F 01011111 _ _ 下划线
96 140 60 01100000 ` ` 重音符
97 141 61 01100001 a a 小写字母 a
98 142 62 01100010 b b 小写字母 b
99 143 63 01100011 c c 小写字母 c
100 144 64 01100100 d d 小写字母 d
101 145 65 01100101 e e 小写字母 e
102 146 66 01100110 f f 小写字母 f
103 147 67 01100111 g g 小写字母 g
104 150 68 01101000 h h 小写字母 h
105 151 69 01101001 i i 小写字母 i
106 152 6A 01101010 j j 小写字母 j
107 153 6B 01101011 k k 小写字母 k
108 154 6C 01101100 l l 小写字母 l
109 155 6D 01101101 m m 小写字母 m
110 156 6E 01101110 n n 小写字母 n
111 157 6F 01101111 o o 小写字母 o
112 160 70 01110000 p p 小写字母 p
113 161 71 01110001 q q 小写字母 q
114 162 72 01110010 r r 小写字母 r
115 163 73 01110011 s s 小写字母 s
116 164 74 01110100 t t 小写字母 t
117 165 75 01110101 u u 小写字母 u
118 166 76 01110110 v v 小写字母 v
119 167 77 01110111 w w 小写字母 w
120 170 78 01111000 x x 小写字母 x
121 171 79 01111001 y y 小写字母 y
122 172 7A 01111010 z z 小写字母 z
123 173 7B 01111011 { { 左大括号
124 174 7C 01111100 | | 垂直线
125 175 7D 01111101 } } 右大括号
126 176 7E 01111110 ~ ~ 波浪号
127 177 7F 01111111 ? 删除

扩展ASCII码

后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展ASCII码允许将每个字符的第8 位用于确定附加的128 个特殊符号字符、外来语字母和图形符号

十进制DEC 八进制OCT 十六进制HEX 二进制BIN 符号Symbol HTML实体编码 中文解释Description
128 200 80 10000000 ? 欧盟符号
129 201 81 10000001
130 202 82 10000010 ? ? 单低 9 引号
131 203 83 10000011 ? ? 带钩的拉丁小写字母f
132 204 84 10000100 ? ? 双低 9 引号
133 205 85 10000101 ? 水平省略号
134 206 86 10000110 ? ? 剑号
135 207 87 10000111 ? ? 双剑号
136 210 88 10001000 ? ? 修正字符抑扬音符号
137 211 89 10001001 ? 千分号
138 212 8A 10001010 ? ? 带弯音号的拉丁大写字母 S
139 213 8B 10001011 ? ? 左单书名号
140 214 8C 10001100 ? ? 拉丁大写组合 OE
141 215 8D 10001101
142 216 8E 10001110 ? ? 带弯音号的拉丁大写字母 z
143 217 8F 10001111
144 220 90 10010000
145 221 91 10010001 ? 左单引号
146 222 92 10010010 ? 右单引号
147 223 93 10010011 ? 左双引号
148 224 94 10010100 ? 右双引号
149 225 95 10010101 ? ?
150 226 96 10010110 ? 半长破折号
151 227 97 10010111 ? 全长破折号
152 230 98 10011000 ? ? 小波浪线
153 231 99 10011001 ? ?
154 232 9A 10011010 ? ? 带弯音号的拉丁小写字母 s
155 233 9B 10011011 ? ? 右单书名号
156 234 9C 10011100 ? ? 拉丁小写组合 oe
157 235 9D 10011101
158 236 9E 10011110 ? ? 带弯音号的拉丁小写字母 z
159 237 9F 10011111 ? ? 带弯音号的拉丁大写字母 Y
160 240 A0 10100000  
161 241 A1 10100001 ? ? 反向感叹号
162 242 A2 10100010 分币符号
163 243 A3 10100011 英磅符号
164 244 A4 10100100 ¤ ¤
165 245 A5 10100101 人民币符号
166 246 A6 10100110 | |
167 247 A7 10100111 § § 章节符号
168 250 A8 10101000 ¨ ¨ 通用货币符号
169 251 A9 10101001 ? ? 版权符号
170 252 AA 10101010 a a 阴性顺序指示符号
171 253 AB 10101011 ? ? 左角引号
172 254 AC 10101100 ? ?
173 255 AD 10101101 - -
174 256 AE 10101110 ? ?
175 257 AF 10101111 ˉ ˉ
176 260 B0 10110000 ° ° 温度符号
177 261 B1 10110001 ± ± 加/减号
178 262 B2 10110010 2 2 上标 2
179 263 B3 10110011 3 3 上标 3
180 264 B4 10110100
181 265 B5 10110101 μ μ 微符号
182 266 B6 10110110 ? ? 段落符号,pilcrow
183 267 B7 10110111 · · 中点
184 270 B8 10111000 ? ?
185 271 B9 10111001 1 1 上标 1
186 272 BA 10111010 o o 阳性顺序指示符
187 273 BB 10111011 ? ? 右角引号
188 274 BC 10111100 ? ? 分数四分之一
189 275 BD 10111101 ? ? 分数二分之一
190 276 BE 10111110 ? ?
191 277 BF 10111111 ? ? 反向问号
192 300 C0 11000000 à à 带重音符的大写字母 A
193 301 C1 11000001 á á 带尖锐重音的大写字母 A
194 302 C2 11000010 ? ? 带音调符号的大写字母 A
195 303 C3 11000011 ? ? 带代字号的大写字母 A
196 304 C4 11000100 ? ? 带元音变音(分音符号)的大写字母 A
197 305 C5 11000101 ? ? 带铃声的大写字母 A
198 306 C6 11000110 ? ? 大写字母 AE双重元音
199 307 C7 11000111 ? ? 带变音符号的大写字母 C
200 310 C8 11001000 è è 带重音符的大写字母 E
201 311 C9 11001001 é é 带尖锐重音的大写字母 E
202 312 CA 11001010 ê ê 带音调符号的大写字母 E
203 313 CB 11001011 ? ? 带元音变音(分音符号)的大写字母 E
204 314 CC 11001100 ì ì 带重音符的大写字母 I
205 315 CD 11001101 í í 带尖锐重音的大写字母 I
206 316 CE 11001110 ? ? 带音调符号的大写字母 I
207 317 CF 11001111 ? ? 带元音变音(分音符号)的大写字母 I
208 320 D0 11010000 D D
209 321 D1 11010001 ? ? 带代字号的大写字母 N
210 322 D2 11010010 ò ò 带重音符的大写字母 O
211 323 D3 11010011 ó ó 带尖锐重音的大写字母 O
212 324 D4 11010100 ? ? 带音调符号的大写字母 O
213 325 D5 11010101 ? ? 带代字号的大写字母 O
214 326 D6 11010110 ? ? 带元音变音(分音符号)的大写字母 O
215 327 D7 11010111 × × 大写字母OE 连字
216 330 D8 11011000 ? ? 带斜杠的大写字母 O
217 331 D9 11011001 ù ù 带重音符的大写字母 U
218 332 DA 11011010 ú ú 带尖锐重音的大写字母 U
219 333 DB 11011011 ? ? 带音调符号的大写字母 U
220 334 DC 11011100 ü ü 带元音变音(分音符号)的大写字母 U
221 335 DD 11011101 Y Y 带元音变音(分音符号)的大写字母 Y
222 336 DE 11011110 T T
223 337 DF 11011111 ? ? 德语高调小写字母 s
224 340 E0 11100000 à à 带重音符的小写字母 a
225 341 E1 11100001 á á 带尖锐重音的小写字母 a
226 342 E2 11100010 a a 带音调符号的小写字母 a
227 343 E3 11100011 ? ? 带代字号的小写字母 a
228 344 E4 11100100 ? ? 带元音变音(分音符号)的小写字母 a
229 345 E5 11100101 ? ? 带铃声的小写字母 a
230 346 E6 11100110 ? ? 小写字母 ae双重元音
231 347 E7 11100111 ? ? 带变音符号的小写字母 c
232 350 E8 11101000 è è 带重音符的小写字母 e
233 351 E9 11101001 é é 带尖锐重音的小写字母 e
234 352 EA 11101010 ê ê 带音调符号的小写字母 e
235 353 EB 11101011 ? ? 带元音变音(分音符号)的小写字母 e
236 354 EC 11101100 ì ì 带重音符的小写字母 i
237 355 ED 11101101 í í 带尖锐重音的小写字母 i
238 356 EE 11101110 ? ? 带音调符号的小写字母 i
239 357 EF 11101111 ? ? 带元音变音(分音符号)的小写字母 i
240 360 F0 11110000 e e
241 361 F1 11110001 ? ? 带代字号的小写字母 n
242 362 F2 11110010 ò ò 带重音符的小写字母 o
243 363 F3 11110011 ó ó 带尖锐重音的小写字母 o
244 364 F4 11110100 ? ? 带音调符号的小写字母 o
245 365 F5 11110101 ? ? 带代字号的小写字母 o
246 366 F6 11110110 ? ? 带元音变音(分音符号)的小写字母 o
247 367 F7 11110111 ÷ ÷ 小写字母 oe连字
248 370 F8 11111000 ? ? 带斜杠的小写字母 o
249 371 F9 11111001 ù ù 带重音符的小写字母 u
250 372 FA 11111010 ú ú 带尖锐重音的小写字母 u
251 373 FB 11111011 ? ? 带音调符号的小写字母 u
252 374 FC 11111100 ü ü 带元音变音(分音符号)的小写字母 u
253 375 FD 11111101 y y 带元音变音(分音符号)的小写字母 y2
254 376 FE 11111110 t t
255 377 FF 11111111 ? ?

重点

  1. \x00是ASCII表中第一项,C语言中的字符串结束符
  2. \t、\x09,表示tab字符
  3. \r\n是\x0d\x0a
  4. \x30~\x39 字符0~9,\x31是字符1
  5. \x41对应十进制65,表示A
  6. \x61对应十进制97,表示a

注意:这里的1指定是字符1,不是数字1

UTF-8、GBK都兼容了ASCII

'a\x09b\x0d\x0ac \x31\x41\x61' # 表示什么?
'A' > 'a' # 谁大?

Bytes初始化

  • bytes() 空bytes
  • bytes(int) 指定字节的bytes,被0填充
  • bytes(iterable_of_ints) -> bytes [0,255]的int组成的可迭代对象
  • bytes(string, encoding[, errors]) -> bytes 等价于string.encode()
  • bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer 从一个字节序列或者buffer复制出一个新的不可变的bytes对象
  • 使用b前缀定义
    • 只允许基本ASCII使用字符形式b'abc9'
    • 使用16进制转义表示b"\x41\x61"

bytes类型和str类型类似,都是不可变类型,操作方法类似。

print(b'abcd'[2]) # 返回int,指定是本字节对应的十进制数
x = b'\t\x09'
print(x, len(x))
y = br'\t\x09'
print(y, len(y))

bytearray初始化

  • bytearray() 空bytearray
  • bytearray(int) 指定字节的bytearray,被0填充
  • bytearray(iterable_of_ints) -> bytearray [0,255]的int组成的可迭代对象
  • bytearray(string, encoding[, errors]) -> bytearray 近似string.encode(),不过返回可变对象
  • bytearray(bytes_or_buffer) 从一个字节序列或者buffer复制出一个新的可变的bytearray对象

b前缀表示的是bytes,不是bytearray类型

由于bytearray类型是可变数组,所以,类似列表。

  • append(int) 尾部追加一个元素
  • insert(index, int) 在指定索引位置插入元素
  • extend(iterable_of_ints) 将一个可迭代的整数集合追加到当前bytearray
  • pop(index=-1) 从指定索引上移除元素,默认从尾部移除
  • remove(value) 找到第一个value移除,找不到抛ValueError异常
  • 注意:上述方法若需要使用int类型,值在[0, 255]
  • clear() 清空bytearray
  • reverse() 翻转bytearray,就地修改
b = bytearray()
b.append(97) b.append(99) b.insert(1,98) b.extend([65,66,67])
b.remove(66) b.pop()
b.reverse()
print(b) # 输出什么
b.clear()

线性结构

线性结构特征:

  • 可迭代 for ... in
  • 有长度,通过len(x)获取,容器
  • 通过整数下标可以访问元素。正索引、负索引
    • 可以切片

已经学习过的线性结构:list、tuple、str、bytes、bytearray

切片

sequence[start:stop]
sequence[start:stop:step]
  • 通过给定的索引区间获得线性结构的一部分数据
  • start、stop、step为整数,可以是正整数、负整数、零
  • start为0时,可以省略
  • stop为末尾时,可以省略
  • step为1时,可以省略
  • 切片时,索引超过上界(右边界),就取到末尾;超过下界(左边界),取到开头
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(x[:])
print(x[:-1]) # 
print(x[0:])
print(x[3:])
print(x[3:-1]) # 
print(x[9:])
print(x[:9])
print(x[9:-1])
print(x[:100])
print(x[-100:])
print(x[4:-2])
print(x[-4:-2])
print('0123456789'[-4:8])
print(b'0123456789'[-4:8])
print(bytearray(b'0123456789')[-10:5])
# 步长
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(x[::])
print(x[::2])
print(x[2:8:3])
print(x[:9:3])
print(x[1::3])
print(x[-10:8:2])
# 起止和方向
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(x[-10:])
print(x[-5:6])
print(x[-5:-6])
print(x[6:5])
print(x[5:5])
print(x[1:9:-2])
print(x[::-2])
print(x[8::-2]) # 表示索引8到左尽头,包含0
print(x[8:0:-2]) # 表示索引8到索引1,不含0
print(x[8:-10:2])
print(x[8:-10:-2])
print(x[-5:4:-1])
print(x[-5:5:-1])

在序列上使用切片[start:stop],子区间索引范围[start, stop),相当于从start开始指向stop的方向上获取数据

默认step为1,表示向右;步长为负数,表示向左

如果子区间方向和步长方向不一致,直接返回当前类型的"空对象"

如果子区间方向和步长方向一致,则从起点间隔步长取值

内建函数 函数签名 说明
id id(object) CPython中返回对象的内存地址 可以用来判断是不是同一个对象
# 使用id看地址,要注意地址回收复用问题
print(id([1,2,3]))
print(id([4,5,6,7])) 
# 上下两句可能内存地址一样,但是上面那个[1,2,3]没有意义,因为它用完之后,引用计数为0了,没
人能再次访问到,释放了内存
# 如果2个存在在内存中的对象,地址一样一定是同一个对象

本质

x = [0, 1, 2] y = x[:]
print(x, y)
print(id(x), id(y))
x[0] = 100
print(x, y) x = [[1]]
y = x[:]
print(x, y)
print(x == y)
print(id(x), id(y), x is y) x[0][0] = 100
print(x, y)
print(x == y)
print(x is y) x[0] = 200
print(x == y) # ?
print(x, y)

上例可知,实际上切片后得到一个全新的对象。 [:] 或 [::] 相当于copy方法。

练习

99乘法表

if __name__ == '__main__':
    for x in range(1,10):
        for y in range(1,x+1):
            print("{} * {} = {:<10}".format(x,y,x*y), end='' if x>y else '\n')

100奇数和

if __name__ == '__main__':
	sum=0
    for i in range(1,100,2):
        sum+=i
    print(sum)
#或者
print(sum(range(1,100,2)))