欠4年前自己的一份笔记,献给今后的自己。
分类
数值型
int、float、complex、bool序列对象
字符串 str
列表 list
tuple键值对
集合set
字典dict数值型
int、float、complex、bool都是class,1、5.0、2+3j都是对象即实例
int:python3的int就是长整型,且没有大小限制,受限于内存区域的大小
float:有整数部分和小数部分组成。支持十进制和科学计数法表示。只有双精度型。
complex:有实数和虚数部分组成,实数和虚数部分都是浮点数,3+4.2J
bool:int的子类,仅有2个实例True、False对应1和0,可以和整数直接运算类型转换(built-in)
int(x) 返回一个整数
float(x) 返回一个浮点数
complex(x)、complex(x,y) 返回一个复数
bool(x) 返回布尔值,前面讲过False等价的对象
数字的处理函数
- round(),四舍五入?
- math模块、floor()地板、天花板ceil()
- int() 、//
- 举例:
import math
print(int(-3.6), int(-2.5), int(-1.4))
print(int(3.6), int(2.5), int(1.4))
print(7 // 2, 7 // -2, -7 // 2, -(7 // 2))
print(2 // 3, -2 // 3, -1 // 3)
print(math.floor(2.5), math.floor(-2.5))
print(round(2.5), round(2.5001), round(2.6))
print(math.ceil(2.5), math.ceil(-2.5))
print(round(3.5), round(3.5001), round(3.6), round(3.3))
print(round(-2.5), round(-2.5001), round(-2.6))
print(round(-3.5), round(-3.5001), round(-3.6), round(-3.3))
输出:
-3 -2 -1
3 2 1
3 -4 -4 -3
0 -1 -1
2 -3
2 3 3
3 -2
4 4 4 3
-2 -3 -3
-4 -4 -4 -3
- round(),四舍六入五取偶
- floor()向下取整、ceil()向上取整
- int() 取整数部分
- // 整除且向下取整
- min()
- max()
- pow(x,y) 等于 x**y
- math.sqrt()
- 进制函数,返回值是字符串
bin()
oct()
hex() - math.pi π
- math.e 自如常数
类型判断
- type(obj) ,返回类型,而不是字符串
- isinstance(obj, class_or_tuple),返回布尔值
举例:
type(a)
type(‘abc’)
type(123)
isinstance(6, str)
isinstance(6, (str, bool, int))
type(1+True)
type(1+True+2.0) # 是什么?隐式转换
列表list
- 一个队列,一个排列整齐的队伍
- 列表内的个体称作元素,由若干元素组成列表
- 元素可以是任意对象(数字、字符串、对象、列表等)
- 列表内元素有顺序,可以使用索引
- 线性的数据结构
- 使用 [ ] 表示
- 列表是可变的
- 列表list、链表、queue、stack的差异
列表list定义 初始化
- list() -> new empty list
- list(iterable) -> new list initialized from iterable’s items
- 列表不能一开始就定义大小
lst = list()
lst = []
lst = [2, 6, 9, ‘ab’]
lst = list(range(5))
列表索引访问
- 索引,也叫下标
- 正索引:从左至右,从0开始,为列表中每一个元素编号
- 负索引:从右至左,从-1开始
- 正负索引不可以超界,否则引发异常IndexError
- 为了理解方便,可以认为列表是从左至右排列的,左边是头部,右边是尾部,左边是下界,右边是上界
- 列表通过索引访问
list[index] ,index就是索引,使用中括号访问
列表查询
- index(value,[start,[stop]])
通过值value,从指定区间查找列表内的元素是否匹配
匹配第一个就立即返回索引
匹配不到,抛出异常ValueError - count(value)
返回列表中匹配value的次数 - 时间复杂度
index和count方法都是O(n)
随着列表数据规模的增大,而效率下降 - 如何返回列表元素的个数?如何遍历?如何设计高效?
len()
如何查帮助
列表元素修改
- 索引访问修改
list[index] = value
索引不要超界
列表增加、插入元素
- append(object) -> None
列表尾部追加元素,返回None
返回None就意味着没有新的列表产生,就地修改
时间复杂度是O(1) - insert(index, object) -> None
在指定的索引index处插入元素object
返回None就意味着没有新的列表产生,就地修改
时间复杂度是O(n)
索引能超上下界吗?
超越上界,尾部追加
超越下界,头部追加 - extend(iteratable) -> None
将可迭代对象的元素追加进来,返回None
就地修改
+ -> list
连接操作,将两个列表连接起来
产生新的列表,原列表不变
本质上调用的是__add__()方法 - -> list
重复操作,将本列表元素重复n次,返回新的列表
Python中用[]表示空的list,我们也可以直接在其中填充元素进行初始化:
# Lists store sequences
li = []
# You can start with a prefilled list
other_li = [4, 5, 6]
print(li)
print(other_li)
使用append和pop可以在list的末尾插入或者删除元素:
# Lists store sequences
li = []
# Add stuff to the end of a list with append
li.append(1) # li is now [1]
print(li)
li.append(2) # li is now [1, 2]
print(li)
li.append(4) # li is now [1, 2, 4]
print(li)
li.append(3) # li is now [1, 2, 4, 3]
print(li)
# Remove from the end with pop
li.pop() # => 3 and li is now [1, 2, 4]
# Let's put it back
li.append(3) # li is now [1, 2, 4, 3] again.
print(li)
list可以通过[]加上下标访问指定位置的元素,如果是负数,则表示倒序访问。-1表示最后一个元素,-2表示倒数第二个,以此类推。如果访问的元素超过数组长度,则会出发IndexError的错误。
# Lists store sequences
li = [1,2,3,4,5]
# Access a list like you would any array
print(li[0]) # => 1
# Look at the last element
print(li[-1]) # => 5
# Looking out of bounds is an IndexError
print(li[10]) # Raises an IndexError
输出 :
1
5
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test1.py", line 10, in <module>
print(li[10]) # Raises an IndexError
~~^^^^
IndexError: list index out of range
list支持切片操作,所谓的切片则是从原list当中拷贝出指定的一段。我们用start:end的格式来获取切片,注意,这是一个左闭右开区间。如果留空表示全部获取,我们也可以额外再加入一个参数表示步长,比如[1:5:2]表示从1号位置开始,步长为2获取元素。得到的结果为[1, 3]。如果步长设置成-1则代表反向遍历。
# You can look at ranges with slice syntax.
# The start index is included, the end index is not
# (It's a closed/open range for you mathy types.)
li = [1, 2, 4, 3]
print(li[1:3]) # Return list from index 1 to 3 => [2, 4]
print(li[2:]) # Return list starting from index 2 => [4, 3]
print(li[:3]) # Return list from beginning until index 3 => [1, 2, 4]
print(li[::2]) # Return list selecting every second entry => [1, 4]
print(li[::-1]) # Return list in reverse order => [3, 4, 2, 1]
# Use any combination of these to make advanced slices
# li[start:end:step]
如果我们要指定一段区间倒序,则前面的start和end也需要反过来,例如我想要获取[3: 6]区间的倒序,应该写成[6:3:-1]。
只写一个:,表示全部拷贝,如果用is判断拷贝前后的list会得到False。可以使用del删除指定位置的元素,或者可以使用remove方法。
# You can look at ranges with slice syntax.
# The start index is included, the end index is not
# (It's a closed/open range for you mathy types.)
li = [1, 2, 4, 3]
# Make a one layer deep copy using slices
li2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false.
print(li2)
# Remove arbitrary elements from a list with "del"
del li[2] # li is now [1, 2, 3]
print(li)
# Remove first occurrence of a value
li.remove(2) # li is now [1, 3]
print(li)
li.remove(2) # Raises a ValueError as 2 is not in the list
print(li)
输出:
[1, 2, 4, 3]
[1, 2, 3]
[1, 3]
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test1.py", line 17, in <module>
li.remove(2) # Raises a ValueError as 2 is not in the list
~~~~~~~~~^^^
ValueError: list.remove(x): x not in list
insert方法可以指定位置插入元素,index方法可以查询某个元素第一次出现的下标。
# You can look at ranges with slice syntax.
# The start index is included, the end index is not
# (It's a closed/open range for you mathy types.)
li = [1, 2, 4, 3]
# Insert an element at a specific index
li.insert(1, 2) # li is now [1, 2, 3] again
print(li)
# Get the index of the first item found matching the argument
print(li.index(2)) # => 1
li = [1, 2, 4, 3]
print(li.index(5)) # Raises a ValueError as 4 is not in the list
输出 :
[1, 2, 2, 4, 3]
1
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test1.py", line 14, in <module>
print(li.index(5)) # Raises a ValueError as 4 is not in the list
~~~~~~~~^^^
ValueError: 5 is not in list
list可以进行加法运算,两个list相加表示list当中的元素合并。等价于使用extend方法:
# You can look at ranges with slice syntax.
# The start index is included, the end index is not
# (It's a closed/open range for you mathy types.)
li = [1, 2, 4, 3]
other_li = [4, 5, 6]
# You can add lists
# Note: values for li and for other_li are not modified.
print(li + other_li) # => [1, 2, 3, 4, 5, 6]
# Concatenate lists with "extend()"
li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6]
我们想要判断元素是否在list中出现,可以使用in关键字,通过使用len计算list的长度:
li = [1, 2, 4, 3]
other_li = [4, 5, 6]
# Check for existence in a list with "in"
print(1 in li) # => True
# Examine the length with "len()"
print(len(li)) # => 6
列表 *重复的坑
- * -> list
重复操作,将本列表元素重复n次,返回新的列表
x = [[1,2,3]]*3
print(x)
x[0][1] = 20
print(x)
y = [1]*5
y[0] = 6
y[1] = 7
print(y)
输出:
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 20, 3], [1, 20, 3], [1, 20, 3]]
[6, 7, 1, 1, 1]
上面代码运行结果是什么?为什么?
列表删除元素
- remove(value) -> None
从左至右查找第一个匹配value的值,移除该元素,返回None
就地修改
效率?
8 pop([index]) -> item
不指定索引index,就从列表尾部弹出一个元素
指定索引index,就从索引处弹出一个元素,索引超界抛出IndexError错误
效率?指定索引的的时间复杂度?不指定索引呢? - clear() -> None
清除列表所有元素,剩下一个空列表
列表其它操作
- reverse() -> None
n将列表元素反转,返回None
就地修改 - sort(key=None, reverse=False) -> None
对列表元素进行排序,就地修改,默认升序
reverse为True,反转,降序
key一个函数,指定key如何排序
lst.sort(key=functionname) - in
[3,4] in [1, 2, [3,4]]
for x in [1,2,3,4]
列表复制
lst0 = list(range(4))
lst2 = list(range(4))
print(lst0==lst2)
lst1 = lst0
lst1[2] = 10
print(lst0)
lst0==lst2相等吗?为什么?lst0里面存的是什么?
请问lst0的索引为2的元素的值是什么?
请问lst1 = lst0这个过程中有没有复制过程?
输出:
True
[0, 1, 10, 3]
- copy() -> List shadow copy返回一个新的列表
lst0 = list(range(4))
lst5 = lst0.copy()
print(lst5 == lst0)
lst5[2] = 10
print(lst5 == lst0)
lst0和lst5一样吗?
对比左右程序的差别
lst0 = [1, [2, 3, 4], 5]
lst5 = lst0.copy()
lst5 == lst0
lst5[2] = 10
lst5 == lst0
lst5[2] = 5
lst5[1][1] = 20
lst5 == lst0
输出:
True
False
- shadow copy
影子拷贝,也叫浅拷贝,遇到引用类型,只是复制了一个引用而已 - 深拷贝
copy模块提供了deepcopy
import copy
lst0 = [1, [2, 3, 4], 5]
lst5 = copy.deepcopy(lst0)
lst5[1][1] = 20
lst5 == lst0
随机数
- random模块
- randint(a, b) 返回[a, b]之间的整数
- choice(seq) 从非空序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。random.choice([1,3,5,7])
- randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数
缺省值为1。 random.randrange(1,7,2) - random.shuffle(list) ->None 就地打乱列表元素
- sample(population, k) 从样本空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回
一个新的列表
random.sample([‘a’, ‘b’, ‘c’, ‘d’], 2)
random.sample([‘a’, ‘a’], 2) 会返回什么结果
关于list的判断,我们常用的判断有两种,一种是刚才介绍的==,还有一种是is。我们有时候也会简单实用is来判断,那么这两者有什么区别呢?我们来看下面的例子:
a = [1, 2, 3, 4] # Point a at a new list, [1, 2, 3, 4]
print(a)
b = a # Point b at what a is pointing to
print(b is a) # => True, a and b refer to the same object
print(b == a) # => True, a's and b's objects are equal
b = [1, 2, 3, 4] # Point b at a new list, [1, 2, 3, 4]
print(b is a) # => False, a and b do not refer to the same object
print(b == a) # => True, a's and b's objects are equal
Python是全引用的语言,其中的对象都使用引用来表示。is判断的就是两个引用是否指向同一个对象,而==则是判断两个引用指向的具体内容是否相等。举个例子,如果我们把引用比喻成地址的话,is就是判断两个变量的是否指向同一个地址,比如说都是沿河东路XX号。而==则是判断这两个地址的收件人是否都叫张三。
显然,住在同一个地址的人一定都叫张三,但是住在不同地址的两个人也可以都叫张三,也可以叫不同的名字。所以如果a is b,那么a == b一定成立,反之则不然。
求100内的素数
import math
import datetime
start = datetime.datetime.now()
primenumber = []
flag = False
count = 1
for x in range(3, 100000, 2) :
for i in primenumber:
if x % i == 0:
flag = True
break
if i >= math.ceil(math.sqrt(x)) :
flag = False
break
if not flag:
#print(x)
count += 1
primenumber .append (x)
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print(count)
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
杨辉三角
triangle = [[1], [1, 1]]
for i in range(2,6):
cur = [1]
pre = triangle[i-1]
for j in range(len(pre)-1):
cur.append(pre[j] + pre[j+1])
cur.append (1)
triangle.append (cur)
print(triangle)
变体一 :
triangle = []
n = 6
for i in range(n):
cur = [1]
triangle.append(cur)
if i == 0:
continue
pre = triangle[i - 1]
for j in range(len(pre) - 1):
cur.append(pre[j] + pre[+1])
cur.append(1)
print(triangle)
补零(方法2)
除了第一行以外,每一行每一个元素(包括两头的1)都是由上一行的元素相加得到。如何得到两头的1呢?目标是打印指定的行,所以算出一行就打印一行,不需要用一个大空间存储所有已经算出的行。
while循环实现
n = 6
newline =[1] # 相当于计算好的第一行
print(newline)
for i in range(1,n):
oldline = newline.copy() # 浅拷贝并补0
oldline.append(0) # 尾部补0相当于两端补0
newline.clear() # 使用append,所以要清除
offset = 0
while offset <= i:
newline.append(oldline[offset-1] + oldline[offset])
offset += 1
print(newline)
for循环实现
n = 6
newline =[1] # 相当于计算好的第一行
print(newline)
for i in range(1,n):
oldline = newline.copy() # 浅拷贝并补0
oldline.append(0) # 尾部补0相当于两端补0
newline.clear() # 使用append,所以要清除
for j in range(i+1):
newline.append(oldline[j - 1] + oldline[j])
print(newline)
上面的代码看似不错,但行初始化的代码明显繁琐了,进一步简化
triangle = []
n = 6
for i in range(n):
row = [1] * (i + 1) # 一次性开辟
triangle.append(row)
for j in range(1, i // 2 + 1): # i=2第三行才能进来
# print(i, j)
val = triangle[i - 1][j - 1] + triangle[i - 1][j]
row[j] = val
if i != 2 * j: # 奇数个数的中点跳过
row[-j - 1] = val
print(triangle)
首先我们明确的知道所求最大行的元素个数,例如前6行的最大行元素个数为6个。下一行等于首元素不变,覆盖中间元素。
n = 6
row = [1] * n # 一次性开辟足够的空间
for i in range(n):
offset = n - i
z = 1 # 因为会有覆盖影响计算,所以引入一个临时变量学院
for j in range(1, i // 2 + 1): # 对称性
val = z + row[j]
row[j], z = val, row[j]
if i != 2 * j:
row[-j - offset] = val
print(row[:i + 1])
求杨辉三角第n行第k列的值
计算到m行,打印出k项
# 求m行k个元素
# m行元素有m个,所以k不能大于m
# 这个需求需要保存m行的数据,那么可以使用一个嵌套机构[L],[],[]]
m = 5
k = 4
triangle = []
for i in range(m):
# 所有行都需要1开头
row = [1]
triangle.append(row)
if i == 0:
continue
for j in range(1, i):
row.append(triangle[i - 1][j - 1] + triangle[i - 1][j])
row.append(1)
print(triangle)
print("---------" * 2)
print(triangle[m - 1][k - 1])
print("*" * 20)
输出:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
------------------
4
********************
算法2
# m行k列的值,C(m-1,k-1)组合数
m = 9
k = 5
# m最大
n = m - 1
r = k - 1
# c(n,r) = c(m-1, k-1) = (m-1) !/((k-1)! (m-r) !)
d = n - r
targets = [] # r,n-r, n
factorial = 1
# 可以加入k为1或者m的判断,返回1
for i in range(1, n + 1):
factorial *= i
if i == r:
targets.append(factorial)
if i == d:
targets.append(factorial)
if i == n:
targets.append(factorial)
# print(targets)
print(targets[2] // (targets[0] * targets[1]))
输出:
70
元组tuple
- 一个有序的元素组成的集合
- 使用小括号()表示
- 口元组是不可变对象
tuple和list非常接近,tuple通过()初始化。和list不同,tuple是不可变对象。也就是说tuple一旦生成不可以改变。如果我们修改tuple,会引发TypeError异常。
# Tuples are like lists but are immutable.
tup = (1, 2, 3)
print(tup[0]) # => 1
tup[0] = 3 # Raises a TypeError
输出 :
1
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test1.py", line 4, in <module>
tup[0] = 3 # Raises a TypeError
~~~^^^
TypeError: 'tuple' object does not support item assignment
由于小括号是有改变优先级的含义,所以我们定义单个元素的tuple,末尾必须加上逗号,否则会被当成是单个元素:
# Note that a tuple of length one has to have a comma after the last element but
# tuples of other lengths, even zero, do not.
print(type((1))) # => <class 'int'>
print(type((1,))) # => <class 'tuple'>
print(type(())) # => <class 'tuple'>
tuple支持list当中绝大部分操作:
# You can do most of the list operations on tuples too
tup = (1, 2, 3)
print(len(tup)) # => 3
print(tup + (4, 5, 6)) # => (1, 2, 3, 4, 5, 6)
print(tup[:2]) # => (1, 2)
print(2 in tup ) # => True
输出 :
3
(1, 2, 3, 4, 5, 6)
(1, 2)
True
我们可以用多个变量来解压一个tuple:
# You can unpack tuples (or lists) into variables
a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3
print(a, b, c)
# You can also do extended unpacking
a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4
print(a, b, c)
# Tuples are created by default if you leave out the parentheses
d, e, f = 4, 5, 6 # tuple 4, 5, 6 is unpacked into variables d, eand f
print(d, e, f)
# respectively such that d = 4, e = 5 and f = 6
# Now look how easy it is to swap two values
e, d = d, e # d is now 5 and e is now 4
print(d, e)
输出:
1 2 3
1 [2, 3] 4
4 5 6
5 4
解释一下这行代码:
a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4
我们在b的前面加上了星号,表示这是一个list。所以Python会在将其他变量对应上值的情况下,将剩下的元素都赋值给b。补充一点,tuple本身虽然是不可变的,但是tuple当中的可变元素是可以改变的。比如我们有这样一个tuple:
a = (3, [4])
print(a)
a[1].append(0) # 这是合法的
print(a)
输出:
(3, [4])
(3, [4, 0])
我们虽然不能往a当中添加或者删除元素,但是a当中含有一个list,我们可以改变这个list类型的元素,这并不会触发tuple的异常:
转置矩阵
有一个方阵,左边方阵,求其转置矩阵
规律:对角线不动,alillil <=> alili,而且到了对角线,就停止,去做下一行,对角线上的元素不动
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix)
count = 0
for i, row in enumerate(matrix):
for j, col in enumerate(row):
if i < j:
temp = matrix[i][j]
matrix[i][j] = matrix[j][i]
matrix[j][i] = temp
count += 1
print(matrix)
print(count)
输出:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
3
方法二:
#
matrix = [[1,2,3,10],
[4,5,6,11],
[7,8,9,12],
[1,2,3,4]]
length = len(matrix)
count = 0
for i in range(length):
for j in range(i): # j<i
matrix[i][j],matrix[j][i] = matrix[j][i],matrix[i][j]
count += 1
print(matrix)
print(count)
输出:
[[1, 4, 7, 1], [2, 5, 8, 2], [3, 6, 9, 3], [10, 11, 12, 4]]
1
有一个任意矩阵,求其转置矩阵
算法1
过程就是,扫描matrx第一行,在tm的第一列从上至下附加,然后再第二列附加举例,扫描第一行1.2,3,加入到tm的第一列,然后扫描第二行4,5,6,追加到tm的第二列
# 定义一个矩阵,不考虑稀疏矩阵
# 1 2 3 1 4
# 4 5 6 =>> 2 5
# 3 6
import datetime
matrix = [[1, 2, 3], [4, 5, 6]]
# matrix = [[1,4],[2,5],[3,6]]
tm = []
count = 0
for row in matrix:
for i, col in enumerate(row):
if len(tm) < i + 1: # matrix有i列就要为tm创建i行
tm.append([])
tm[i].append(col)
count += 1
print(matrix)
print(tm)
print(count)
输出:
[[1, 2, 3], [4, 5, 6]]
[[1, 4], [2, 5], [3, 6]]
6
算法2
思考:
能否一次性开辟目标矩阵的内存空间?
如果一次性开辟好目标矩阵内存空间,那么原矩阵的元素直接移动到转置矩阵的对称坐标就行了
# 定义一个矩阵,不考虑稀疏矩阵
# 1 2 3 1 4
# 4 5 6 =>> 2 5
# 3 6
import datetime
matrix = [[1, 2, 3], [4, 5, 6]]
# matrix = [[1,4],[2,5],[3,6]]
tm = [[0 for col in range(len(matrix))] for row in range(len(matrix[0]))]
count = 0
for i, row in enumerate(tm):
for j, col in enumerate(row):
tm[i][j] = matrix[j][i] # 将matrix的所有元素搬到tm中
count += 1
print(matrix)
print(tm)
print(count)
输出:
[[1, 2, 3], [4, 5, 6]]
[[1, 4], [2, 5], [3, 6]]
6
效率测试
import datetime
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
matrix = [[1, 4], [2, 5], [3, 6]]
print('\nMethod 1')
start = datetime.datetime.now()
for c in range(100000):
tm = [] # 目标矩阵
for row in matrix:
for i, item in enumerate(row):
if len(tm) < i + 1:
tm.append([])
tm[i].append(item)
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print(matrix)
print(tm)
print('\nMethod 2')
start = datetime.datetime.now()
for c in range(100000):
tm = [0] * len(matrix[0])
for i in range(len(tm)):
tm[i] = [0] * len(matrix)
# print(tm)
for i, row in enumerate(tm):
for j, col in enumerate(row):
tm[i][j] = matrix[j][i]
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print(matrix)
print(tm)
输出:
Method 1
0.094851
[[1, 4], [2, 5], [3, 6]]
[[1, 2, 3], [4, 5, 6]]
Method 2
0.100858
[[1, 4], [2, 5], [3, 6]]
[[1, 2, 3], [4, 5, 6]]
说明:
上面两个方法在ipython中,使用%%timeit测试下来方法一效率高。
但是真的是方法一效率高吗?
给一个大矩阵,测试一下
matrix = [[1, 2, 3], [4,5, 6], [1, 2, 3], [4,5, 6], [1,2, 3], [4,5, 6], [1, 2,3], [4,5, 6], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3], [4,5, 6], [1, 2, 3],
[4,5,6]]
测试发现,其实只要增加到4*4开始,方法二优势就开始了。
矩阵规模越大,先开辟空间比后append效率高。
元组的定义 初始化
- 定义
tuple() -> empty tuple
tuple(iterable) -> tuple initialized from iterable’s items
t = tuple() # 工厂方法
t = ()
t = tuple(range(1,7,2)) # iteratable
t = (2,4,6,3,4,2)
t = (1,) # 一个元素元组的定义,注意有个逗号
t = (1,)*5
t = (1,2,3) * 6
元组元素的访问
支持索引(下标)
正索引:从左至右,从0开始,为列表中每一个元素编号口
负索引:从右至左,从-1开始
正负索引不可以超界,否则引发异常IndexError
元组通过索引访问
tuple[index],index就是索引,使用中括号访问
t[1]
t[-2]
t[1] = 5
元组查询
- index(value,[start,[stop]])
通过值value,从指定区间查找列表内的元素是否匹配
匹配第一个就立即返回索引
匹配不到,抛出异常ValueError - count(value)
返回列表中匹配value的次数 - 时间复杂度
index和count方法都是O(n)
随着列表数据规模的增大,而效率下降 - len(tuple)
返回元素的个数
元组其它操作
- 元组是只读的,所以增、改、删方法都没有
命名元组namedtuple
- 帮助文档中,查阅namedtuple,有使用例程
- namedtuple(typename, field_names, verbose=False, rename=False)
命名元组,返回一个元组的子类,并定义了字段
field_names可以是空白符或逗号分割的字段的字符串,可以是字段的列表
from collections import namedtuple
Point = namedtuple('_Point',['x','y']) # Point为返回的类
p = Point(11, 22)
Student = namedtuple('Student', 'name age')
tom = Student('tom', 20)
jerry = Student('jerry', 18)
tom.name
练习
- 依次接收用户输入的3个数,排序后打印
- 转换int后,判断大小排序。使用分支结构完成
- 使用max函数
- 使用列表的sort方法
- 冒泡法
冒泡法
- 冒泡法
属于交换排序
两两比较大小,交换位置。如同水泡咕嘟咕嘟往上冒
结果分为升序和降序排列 - 升序
n个数从左至右,编号从0开始到n-1,索引0和1的值比较,如果索引0大,则交换两者位置,如果索引1大,则不交换。继续比较索引1和2的值,将大值放在右侧。直至n-2和n-1比较完,第一轮比较完成。第二轮从索引0比较到n-2,因为最右侧n-1位置上已经是最大值了。依次类推,每一轮都会减少最右侧的不参与比较,直至剩下最后2个数比较。 - 降序
和升序相反
冒泡法代码实现(一)
from sortTest.Maopao1 import num_list
num_list = [
[1, 9, 8, 5, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9]]
nums = num_list[1]
print(nums)
length = len(nums)
count_swap = 0
count = 0
# bubble sort
for i in range(length):
for j in range(length - i - 1):
count += 1
if nums[j] > nums[j + 1]:
tmp = nums[j]
nums[j] = nums[j + 1]
nums[j + 1] = tmp
count_swap += 1
print(nums, count_swap, count)
冒泡法代码实现(二)
num_list = [
[1, 9, 8, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9]]
nums = num_list[2]
print(nums)
length = len(nums)
count_Swap = 0
count = 0
# bubble sort
for i in range(length):
flag = False
for j in range(length - i - 1):
count += 1
if nums[j] > nums[j + 1]:
tmp = nums[j]
nums[j] = nums[j + 1]
nums[j + 1] = tmp
flag = True # swapped
count_Swap += 1
if not flag:
break
print(nums, count_Swap, count)
例一:
from collections import namedtuple
Point = namedtuple('P', ['x', 'y'])
print(Point)
p1 = Point(10, 20)
print(p1)
print(p1.x, p1.y)
print(p1[0], p1[1])
Student = namedtuple('stu','name age')
s1 = Student('tom',20)
s2 = Student('jerry',30)
print(s1.name)
print(s2.age)
结果输出:
<class '__main__.P'>
P(x=10, y=20)
10 20
10 20
tom
30
例二:
def sum(a,b):
return a ,b
a,b = sum(1,2)
print(a,b)
输出:
1 2
例三:
a = tuple([1,2])
print(a )
输出:
(1, 2)
冒泡法总结
- 冒泡法需要数据一轮轮比较
- 可以设定一个标记判断此轮是否有数据交换发生,如果没有发生交换,可以结束排序,如果发生交换,继续下一轮排序
- 最差的排序情况是,初始顺序与目标顺序完全相反,遍历次数1,…,n-1之和n(n-1)/2
- 最好的排序情况是,初始顺序与目标顺序完全相同,遍历次数n-1
- 时间复杂度O(n^2)
字符串
Python当中对字符串的限制比较松,双引号和单引号都可以表示字符串,看个人喜好使用单引号或者是双引号。我个人比较喜欢单引号,因为写起来方便。字符串也支持+操作,表示两个字符串相连。除此之外,我们把两个字符串写在一起,即使没有+,Python也会为我们拼接:
# Strings are created with " or '
print("This is a string.")
print('This is also a string.')
# Strings can be added too! But try not to do this.
print( "Hello " + "world!") # => "Hello world!"
# String literals (but not variables) can be concatenated without using '+'
print("Hello " "world!" )# => "Hello world!"
我们可以使用[]来查找字符串当中某个位置的字符,用len来计算字符串的长度。
# A string can be treated like a list of characters
print("This is a string"[0]) # => 'T'
# You can find the length of a string
print(len("This is a string")) # => 16
我们可以在字符串前面加上f表示格式操作,并且在格式操作当中也支持运算,比如可以嵌套上len函数等。不过要注意,只有Python3.6以上的版本支持f操作。
# You can also format using f-strings or formatted string literals (in Python 3.6+)
name = "Reiko"
print(f"She said her name is {name}.") # => "She said her name is Reiko"
# You can basically put any Python statement inside the braces and it will be output in the string.
print(f"{name} is {len(name)} characters long.") # => "Reiko is 5 characters long."
最后是None的判断,在Python当中None也是一个对象,所有为None的变量都会指向这个对象。根据我们前面所说的,既然所有的None都指向同一个地址,我们需要判断一个变量是否是None的时候,可以使用is来进行判断,当然用==也是可以的,不过我们通常使用is。
# None is an object
print(None) # => None
# Don't use the equality "==" symbol to compare objects to None
# Use "is" instead. This checks for equality of object identity.
print("etc" is None) # => False
print(None is None) # => True
理解了None之后,我们再回到之前介绍过的bool()函数,它的用途其实就是判断值是否是空。所有类型的默认空值会被返回False,否则都是True。比如0,“”,[], {}, ()等。
# None, 0, and empty strings/lists/dicts/tuples all evaluate toFalse.
# All other values are True
print(bool(None)) # => False
print(bool(0)) # => False
print(bool("")) # => False
print(bool([])) # => False
print(bool({})) # => False
print(bool(())) # => False
除了上面这些值以外的所有值传入都会得到True。
几种字符串的表示
在Python中,字符串是一种基本的数据类型,可以使用多种方式进行表示:
普通字符串:使用单引号(’或双引号(”)括起米的字符串,例如:
print('323232')
输出:323232
原始字符串:使用反斜杠(\)转义特殊字符的字符串,例如:
在Python中,r表示原始字符串(raw string)。原始宇符串是一种特类型的字符串,在字符串中不会将反斜杠(\)视为转义字符,而是作为普通字符原样输出。
print(r'hello\nworld!')
输出:hello\nworld!
三引号字符串:使用三个引号(单引号或双引号)括起来的字符串,可以包含多行文本,例如:
三引号字符串可以用来表示包含多行文本的字符串
当字符串中包含引号时,为了避免将引号视为转义字符,
可以使用三引号字符串。
三引号字符串也可以用来表示文档字符串
f-string: 使用f-string表示格式化的字符串,主要作用是简化了字符串格式化的过程,使得代码更加简洁和易读。
f-string使用大写的F‘或者作为字符串的前缀,然后在字符串中用花括号日来标记需要插入或替换的表达式。
for i in range(5):
print(f'第{i + 1} 个数字是{i}')
Unicode字符串和字节串
Unicode字符串通常用于表示包含非ASCII拿符的字符串,比如包含中文字符或特殊符号的文本。
在Python中,Unicode字符串通常以u或U“作为前缀, Unicode字符串表示的是字符本身,而不是它们的编码形式。
# codecs是Python的一个标准库,它提供了对各种字符编码的读取和写入操作的支持。
import codecs
# 定义一个包含中文字符的Unicode字符串
text = u'hello, Python! '
# 打印该字符串
print(text)
# 將该字符串写入文件
with codecs.open('output.txt', 'w', 'utf-8') as f:
f.write(text)
字节串 (Byte String)是一种特的数据类型,用于表示二进制数据。字节串以b或bytes作前缀, 并且包含了一串字符的ASCI码表示。每个字符都是一个字节,因此字节串可以包含多个字节。
# 创建一个字符串
byte_string = b'Hello,World!'
# 打印字符串
print(byte_string)
# 将字节串转换成字符串(需要解码 )
strint = byte_string.decode('utf-8')
print(strint)
# 将字符串转换成字节串 (需要编码 )
byte_string = strint.encode('utf-8')
print(byte_string)
输出 :
- 一个个字符组成的有序的序列,是字符的集合
使用单引号、双引号、三引号引住的字符序列
字符串是不可变对象
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'
sql = """select * from user where name='tom' """
字符串元素访问——下标
- 字符串支持使用索引访问
sql = "select * from user where name='tom'"
print(sql)
print(sql[4]) # 字符串'c'
sql[4] = 'o'
## print(sql)
输出:
select * from user where name='tom'
c
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test2.py", line 4, in <module>
sql[4] = 'o'
~~~^^^
TypeError: 'str' object does not support item assignment
- 有序的字符集合,字符序列
sql = "select * from user where name='tom'"
for c in sql:
print(c)
print(type(c)) # 什么类型?
输出:
s
<class 'str'>
e
<class 'str'>
l
<class 'str'>
e
<class 'str'>
c
<class 'str'>
t
<class 'str'>
<class 'str'>
*
<class 'str'>
<class 'str'>
f
<class 'str'>
r
<class 'str'>
o
<class 'str'>
m
<class 'str'>
<class 'str'>
u
<class 'str'>
s
<class 'str'>
e
<class 'str'>
r
<class 'str'>
<class 'str'>
w
<class 'str'>
h
<class 'str'>
e
<class 'str'>
r
<class 'str'>
e
<class 'str'>
<class 'str'>
n
<class 'str'>
a
<class 'str'>
m
<class 'str'>
e
<class 'str'>
=
<class 'str'>
'
<class 'str'>
t
<class 'str'>
o
<class 'str'>
m
<class 'str'>
'
<class 'str'>
- 可迭代
sql = "select * from user where name='tom'"
lst = list(sql)
print(lst)
输出:
['s', 'e', 'l', 'e', 'c', 't', ' ', '*', ' ', 'f', 'r', 'o', 'm', ' ', 'u', 's', 'e', 'r', ' ', 'w', 'h', 'e', 'r', 'e', ' ', 'n', 'a', 'm', 'e', '=', "'", 't', 'o', 'm', "'"]
字符串join连接*
- “string”.join(iterable) -> str
将可迭代对象连接起来,使用string作为分隔符
可迭代对象本身元素都是字符串
返回一个新字符串
lst = ['1','2','3']
print("\"".join(lst)) # 分隔符是双引号
print(" ".join(lst))
print("\n".join(lst))
lst = ['1',['a','b'],'3']
print(" ".join(lst))
输出:
1"2"3
1 2 3
1
2
3
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test2.py", line 6, in <module>
print(" ".join(lst))
~~~~~~~~^^^^^
TypeError: sequence item 1: expected str instance, list found
字符串+连接
- + -> str
将2个字符串连接在一起
返回一个新字符串
a = "1" + "2";
print(a)
输出:
12
字符串分割
分割字符串的方法分为2类
split系
partition系
将字符串按照分隔符分割成若干字符串,并返回列表
将字符串按照分隔符分割成2段,返回这2段和分隔符的元组split(sep=None, maxsplit=-1) -> list of strings
从左至右
sep 指定分割字符串,缺省的情况下空白字符串作为分隔符
maxsplit 指定分割的次数,-1 表示遍历整个字符串
s1 = "I'm \ta super student."
print(s1.split())
print(s1.split('s'))
print(s1.split('super'))
print(s1.split('super '))
print(s1.split(' '))
print(s1.split(' ',maxsplit=2))
print(s1.split('\t',maxsplit=2))
输出:
["I'm", 'a', 'super', 'student.']
["I'm \ta ", 'uper ', 'tudent.']
["I'm \ta ", ' student.']
["I'm \ta ", 'student.']
["I'm", '\ta', 'super', 'student.']
["I'm", '\ta', 'super student.']
["I'm ", 'a super student.']
- rsplit(sep=None, maxsplit=-1) -> list of strings
从右向左
sep 指定分割字符串,缺省的情况下空白字符串作为分隔符
maxsplit 指定分割的次数,-1 表示遍历整个字符串
s1 = "I'm \ta super student."
print(s1.rsplit())
print(s1.rsplit('s'))
print(s1.rsplit('super'))
print(s1.rsplit('super '))
print(s1.rsplit(' '))
print(s1.rsplit(' ',maxsplit=2))
print(s1.rsplit('\t',maxsplit=2))
输出:
["I'm", 'a', 'super', 'student.']
["I'm \ta ", 'uper ', 'tudent.']
["I'm \ta ", ' student.']
["I'm \ta ", 'student.']
["I'm", '\ta', 'super', 'student.']
["I'm \ta", 'super', 'student.']
["I'm ", 'a super student.']
- splitlines([keepends]) -> list of strings
按照行来切分字符串
keepends 指的是是否保留行分隔符
行分隔符包括\n、\r\n、\r等
'ab c\n\nde fg\rkl\r\n'.splitlines()
'ab c\n\nde fg\rkl\r\n'.splitlines(True)
s1 = '''I'm a super student.
You're a super teacher.'''
print(s1)
print(s1.splitlines())
print(s1.splitlines(True))
输出:
I'm a super student.
You're a super teacher.
["I'm a super student.", "You're a super teacher."]
["I'm a super student.\n", "You're a super teacher."]
- partition(sep) -> (head, sep, tail)
从左至右,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组;如果没有找到分隔符,就返回头、2个空元素的三元组
sep 分割字符串,必须指定
s1 = "I'm a super student."
print(s1.partition('s'))
print("==============")
print(s1.partition('stu'))
print("*********************")
print(s1.partition(''))
print("------------------------")
print(s1.partition('abc'))
输出:
("I'm a ", 's', 'uper student.')
==============
("I'm a super ", 'stu', 'dent.')
*********************
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test2.py", line 6, in <module>
print(s1.partition(''))
~~~~~~~~~~~~^^^^
ValueError: empty separator
- rpartition(sep) -> (head, sep, tail)
从右至左,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组;如果没有找到分隔符,就返回2个空元素和尾的三元组
字符串大小写
- upper()
全大写 - lower()
- 全小写
- 大小写,做判断的时候用
- swapcase()
交互大小写
字符串排版
- title() -> str
标题的每个单词都大写 - capitalize() -> str
首个单词大写 - center(width[, fillchar]) -> str
width 打印宽度
fillchar 填充的字符 - zfill(width) -> str
width 打印宽度,居右,左边用0填充 - ljust(width[, fillchar]) -> str 左对齐
- rjust(width[, fillchar]) -> str 右对齐
- 中文用的少,了解一下
字符串修改
- replace(old, new[, count]) -> str
字符串中找到匹配替换为新子串,返回新字符串
count表示替换几次,不指定就是全部替换
print('www.magedu.com'.replace('w','p'))
print('www.magedu.com'.replace('w','p',2))
print('www.magedu.com'.replace('w','p',3))
print('www.magedu.com'.replace('ww','p',2))
print('www.magedu.com'.replace('www','python',2))
输出:
ppp.magedu.com
ppw.magedu.com
ppp.magedu.com
pw.magedu.com
python.magedu.com
字符串修改
- strip([chars]) -> str
从字符串两端去除指定的字符集chars中的所有字符
如果chars没有指定,去除两端的空白字符
s = "\r \n \t Hello Python \n \t"
print(s.strip())
s = " I am very very very sorry "
print(s.strip('Iy'))
print(s.strip('Iy '))
输出:
Hello Python
I am very very very sorry
am very very very sorr
- lstrip([chars]) -> str
从左开始 - rstrip([chars]) -> str
从右开始
字符串查找
- find(sub[, start[, end]]) -> int
在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到返回-1 - rfind(sub[, start[, end]]) -> int
在指定的区间[start, end),从右至左,查找子串sub。找到返回索引,没找到返回-1
s = "I am very very very sorry"
print(s.find('very'))
print(s.find('very', 5))
print(s.find('very', 6, 13))
print(s.rfind('very', 10))
print(s.rfind('very', 10, 15))
print(s.rfind('very',-10,-1))
输出:
5
5
-1
15
10
15
- index(sub[, start[, end]]) -> int
在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到抛出异常ValueError - rindex(sub[, start[, end]]) -> int
在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到抛出异常ValueError
s = "I am very very very sorry"
print(s.index('very'))
print("="*60)
print(s.index('very', 5))
print("*"*60)
print(s.index('very', 6, 13))
print("-"*60)
print(s.rindex('very', 10))
print("|"*60)
print(s.rindex('very', 10, 15))
print("/")
print(s.rindex('very',-10,-1))
输出:
5
============================================================
5
************************************************************
Traceback (most recent call last):
File "/Users/quyixiao/pp/python_lesson/jk/zhushi/test2.py", line 6, in <module>
print(s.index('very', 6, 13))
~~~~~~~^^^^^^^^^^^^^^^
ValueError: substring not found
时间复杂度
index和count方法都是O(n)
随着列表数据规模的增大,而效率下降len(string)
返回字符串的长度,即字符的个数count(sub[, start[, end]]) -> int
在指定的区间[start, end),从左至右,统计子串sub出现的次数
s = "I am very very very sorry"
print(s.count('very'))
print(s.count('very', 5))
print(s.count('very', 10, 14))
输出:
3
3
1
字符串判断
- endswith(suffix[, start[, end]]) -> bool
在指定的区间[start, end),字符串是否是suffix结尾 - startswith(prefix[, start[, end]]) -> bool
在指定的区间[start, end),字符串是否是prefix开头
s = "I am very very very sorry"
print(s.startswith('very'))
print(s.startswith('very', 5))
print(s.startswith('very', 5, 9))
print(s.endswith('very', 5, 9))
print(s.endswith('sorry', 5))
print(s.endswith('sorry', 5, -1))
print(s.endswith('sorry', 5, 100))
输出:
False
True
True
True
True
False
True
字符串判断 is系列
- isalnum() -> bool 是否是字母和数字组成
- isalpha() 是否是字母
- isdecimal() 是否只包含十进制数字
- isdigit() 是否全部数字(0~9)
- isidentifier() 是不是字母和下划线开头,其他都是字母、数字、下划线
- islower() 是否都是小写
- isupper() 是否全部大写
- isspace() 是否只包含空白字符
字符串格式化
字符串的格式化是一种拼接字符串输出样式的手段,更灵活方便
join拼接只能使用分隔符,且要求被拼接的是可迭代对象
+ 拼接字符串还算方便,但是非字符串需要先转换为字符串才能拼接在2.5版本之前,只能使用printf style风格的print输出
printf-style formatting,来自于C语言的printf函数
格式要求
占位符:使用%和格式字符组成,例如%s、%d等
s调用str(),r会调用repr()。所有对象都可以被这两个转换。
占位符中还可以插入修饰字符,例如%03d表示打印3个位置,不够前面补零
format % values,格式字符串和被格式的值之间使用%分隔
values只能是一个对象,或是一个和格式字符串占位符数目相等的元组,或一个字典printf-style formatting 举例
print("I am %03d" % (20,))
print('I like %s.' % 'Python')
print('%3.2f%% , 0x%x, 0X%02X' % (89.7654, 10, 15))
print("I am %-5d" % (20,))
输出:
I am 020
I like Python.
89.77% , 0xa, 0X0F
I am 20
format函数格式字符串语法——Python鼓励使用
“{} {xxx}”.format(*args, **kwargs) -> str
args是位置参数,是一个元组
kwargs是关键字参数,是一个字典
花括号表示占位符
{}表示按照顺序匹配位置参数,{n}表示取位置参数索引为n的值
{xxx}表示在关键字参数中搜索名称一致的
{{}} 表示打印花括号位置参数
“{}:{}”.format(‘192.168.1.100’,8888),这就是按照位置顺序用位置参数替换前面的格式字符串的占位符中关键字参数或命名参数
“{server} {1}:{0}”.format(8888, ‘192.168.1.100’, server='Web Server Info : ') ,位置参数按照序号匹配,
关键字参数按照名词匹配访问元素
“{0[0]}.{0[1]}”.format((‘magedu’,‘com’))对象属性访问
from collections import namedtuple
Point = namedtuple('Point','x y')
p = Point(4,5)
print("{{{0.x},{0.y}}}".format(p))
输出:
{4,5}
- 对齐
print('{0}*{1}={2:<2}'.format(3,2,2*3))
print('{0}*{1}={2:<02}'.format(3,2,2*3))
print('{0}*{1}={2:>02}'.format(3,2,2*3))
print('{:^30}'.format('centered'))
print('{:*^30}'.format('centered'))
输出:
3*2=6
3*2=60
3*2=06
centered
***********centered***********
- 进制
print("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42))
print("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42))
octets = [192, 168, 0, 1]
print('{:02X}{:02X}{:02X}{:02X}'.format(*octets))
输出:
int: 42; hex: 2a; oct: 52; bin: 101010
int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010
C0A80001
bytes、bytearray
Python3引入两个新类型
bytes
不可变字节序列
bytearray
字节数组
可变字符串与bytes
字符串是字符组成的有序序列,字符可以使用编码来理解
bytes是字节组成的有序的不可变序列
bytearray是字节组成的有序的可变序列编码与解码
字符串按照不同的字符集编码encode返回字节序列bytes
encode(encoding=‘utf-8’, errors=‘strict’) -> bytes
字节序列按照不同的字符集解码decode返回字符串
bytes.decode(encoding=“utf-8”, errors=“strict”) -> str
bytearray.decode(encoding=“utf-8”, errors=“strict”) -> str
ASCII
ASCIl ( American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套单字节编码系统
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类型类似,都是不可变类型,所以方法很多都一样。只不过bytes的方法,输入是bytes,输出是
bytes
b’abcdef’.replace(b’f’,b’k’)
b’abc’.find(b’b’) - 类方法 bytes.fromhex(string)
string必须是2个字符的16进制的形式,‘6162 6a 6b’,空格将被忽略
bytes.fromhex(‘6162 09 6a 6b00’) - hex()
返回16进制表示的字符串
‘abc’.encode().hex() - 索引
b’abcdef’[2] 返回该字节对应的数,int类型
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操作
和bytes类型的方法相同
bytearray(b’abcdef’).replace(b’f’,b’k’)
bytearray(b’abc’).find(b’b’)类方法 bytearray.fromhex(string)
string必须是2个字符的16进制的形式,‘6162 6a 6b’,空格将被忽略
bytearray.fromhex(‘6162 09 6a 6b00’)hex()
返回16进制表示的字符串
bytearray(‘abc’.encode()).hex()索引
bytearray(b’abcdef’)[2] 返回该字节对应的数,int类型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)
print('append_97:',b)
b.append(99)
print('append_99:',b)
b.insert (1,98)
print('insert:',b)
b.extend ([65,66,67])
print('extend:',b)
b.remove(66)
print('remove_66:',b)
print(b.pop())
b.reverse()
print('reverse:',b)
b.clear()
print(b)
输出:
append_97: bytearray(b'a')
append_99: bytearray(b'ac')
insert: bytearray(b'abc')
extend: bytearray(b'abcABC')
remove_66: bytearray(b'abcAC')
67
reverse: bytearray(b'Acba')
bytearray(b'')
切片
线性结构
- 线性结构
可迭代 for … in
len()可以获取长度
通过下标可以访问
可以切片 - 学过的线性结构
列表、元组、字符串、bytes、bytearray
切片
- 通过索引区间访问线性结构的一段数据
- sequence[start:stop] 表示返回[start, stop)区间的子序列
- 支持负索引
- start为0,可以省略
- stop为末尾,可以省略
- 超过上界(右边界),就取到末尾;超过下界(左边界),取到开头
- start一定要在stop的左边
- [:] 表示从头至尾,全部元素被取出,等效于copy()方法
切片举例
print('www.magedu.com'[4:10]) # magedu
print('www.magedu.com'[:10]) # www.magedu
print('www.magedu.com'[4:]) # magedu.com
print('www.magedu.com'[:]) # www.magedu.com
print('www.magedu.com'[:-1]) # www.magedu.co
print('www.magedu.com'[4:-4]) # magedu
print('www.magedu.com'[4:50]) # magedu.com
print(b'www.magedu.com'[-40:10]) # b'www.magedu'
print(bytearray(b'www.magedu.com')[-4:10]) # bytearray(b'')
print(tuple('www.magedu.com')[-10:10]) # ('m', 'a', 'g', 'e', 'd', 'u')
print(list('www.magedu.com')[-10:-4]) # ['m', 'a', 'g', 'e', 'd', 'u']
- 步长切片
[start:stop:step]
step为步长,可以正、负整数,默认是1
step要和start:stop同向,否则返回空序列
print('www.magedu.com'[4:10:2]) # mgd
print(list('www.magedu.com')[4:10:-2]) # []
print(tuple('www.magedu.com')[-10:-4:2]) # ('m', 'g', 'd')
print(b'www.magedu.com'[-4:-10:2]) # b''
print(bytearray(b'www.magedu.com')[-4:-10:-2]) # bytearray(b'.dg')
数字统计
随机产生10个数字要求:
每个数字取值范围[1,20]
统计重复的数字有几个?分别是什么?
统计不重复的数字有几个?分别是什么?
举例:11,7.5,11,6, 7.4,其中2个数字7和11重复了,3个数字4、5、6没有重复过
思路:
对于一个排序的序列,相等的数字会挨在一起。但是如果先排序,还是要花时间,能否不排序解决?
例如11,7,5,11,6,7,4,先拿出11,依次从第二个数字开始比较,发现11就把对应索引标记,这样
一趟比较就知道11是否重复,哪些地方重复。第二趟使用7和其后数字依次比较,发现7就标记, 当遇到以前比较过的11的位置的时候,其索引已经被标记为1,直接跳过。
import random
nums = []
for _ in range(10):
nums.append(random.randrange(21))
# nums = [1,22,33, 56, 56,22,4,56, 9,56,2,1]
print("Origin numbers = {}".format(nums))
print()
length = len(nums)
samenums = [] # 记录相同的数字
diffnums = [] # 记录不同的数字
states = [0] * length # 记录不同的索引异同状态
for i in range(length):
flag = False # 假定没有重复
if states[i] == 1:
continue
for j in range(i + 1, length):
if states[j] == 1:
continue
if nums[i] == nums[j]:
flag = True
states[j] = 1
if flag: # 有重复
samenums.append(nums[i])
states[i] = 1
else:
diffnums.append(nums[i])
print("Same numbers = {1}, Counter = {0}".format(len(samenums), samenums))
print("Different numbers = {1}, Counter = {0}".format(len(diffnums), diffnums))
print(list(zip(states, nums)))