python基础(2)

取整


# 整除
print(3//2) #等于1
print(-3//2) #等于-2

# int函数:只会去整数部分的值,不会看小数部分
print(int(1.4)) #等于1
print(int(-1.9)) #等于-1

# ceil:向下取整 floor:向上取整 round:四舍五入,.5的情况向最近的偶数方向取整,1.5为2,3.5为3
import math
print(math.floor(1.9)) #等于1
print(math.ceil(2.1)) #等于3
print(round(2.5)) # 等于2
print(round(1.5)) # 等于2



随机数

random模块

  • randint(a,b):返回a和b之间的整数,a和b必须是整数
import random
print(random.randint(1,6))
  • randrange(start,stop,step):和range()一样,randrange(1,100,2)返回的是1到100之间的一个奇数,参数必须是整数
import random
print(random.randrange(1,100,2))

  • choice(seq):从一个列表中返回一个值
import random
print(random.choice([1,2.2,3])) # 随机返回一个

  • 3.6开始提供choices,一次从样本中随机选择几个,可重复选择,可以指定权重
import random

for i in range(10):
    print(random.choices([0,1],[10,1],k=10))
  • random.shuffle(list) ->None 就地打乱列表元素
import random

l = [1,2,3,4]
random.shuffle(l)
print(l)
  • sample(population, k) 从样本空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回 一个新的列表
import random
print(random.sample([1,2,3,4,5],2))

常用数值处理函数

  • min()、max()返回最大最小值

  • pow(x,y)等于x**y

  • math.sqrt()开方

  • type()返回值的类型、isinstance(value,str)、isinstance(value,(str,int))

type(1+True) 会把True转换成1运算

线性数据结构

定义:线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储,但是把最后一个数据元素的尾指针指向了首位结点)

  • 顺序表:开辟一块连续的内存存储数据

  • 链表:在分散的内存空间中,通过指针指向下一个元素

列表list

列表是顺序表的一种实现,开辟连续空间,顺序存储数据,数据可以是任意类型,列表是可变的,用[]表示

初始化

  • []
  • list()
  • list(iterable)
l=[]
l1=list()
l2=list(range(5))
l3=[1,2,"a",[1,2],("s","b")]

索引

  • 正索引:从左向右,范围[0,len-1]

  • 负索引:从右向左,范围[-1,-len]

  • 索引不在列表或者超出都会报IndexError

  • 列表通过list[index]访问元素,速度很快,因为是O(1)时间复杂度

l = list(range(10))
print(l[2])
print(l[3])
print(l[4])
print(l[10]) # IndexError: list index out of range的错误

查询

  • index(value,[start,[stop]]):返回参数值的索引

value是必须输入的,后面可以是0、1、2个参数,表示起始和结束索引

l = list(range(10))
print(l.index(1))
print(l.index(3, 2))
print(l.index(4, 1, 5))
  • count(value):返回参数值在列表中的个数
l = [1, 1, 2, 3, 4, 111]

print(l.count(1))
  • len(list)返回列表元素个数
l = [1, 1, 2, 3, 4, 111]

print(len(l))

修改

l=[1,2,3]
l[0]=100
print(l)

增加

  • append(value):尾部增加单个元素
l=[1,2,3]
l.append(4)
  • insert(index,value):在指定的索引前插入值,超过上界,尾部追加,超过下界,头部添加
l=[1,2,3]
l.insert(4,0)

增加多个元素

  • extend(iterable)
l=[1,2,3]
l.extend([4,44,444])
  • +:list1+list2产生新的列表,原来的列表不变
l1=[1,2]
l2=[3,4]
print(l1+l2)
  • *:产生多个相同元素的列表
print([1]*5)

需要注意的是,当列表的中的元素是列表时,修改其中的一个列表的值,会将所有的元素的值修改

x=[[1]] * 3 # 产生[[1],[1],[1]]的列表
x[0]=100 # x的元素将会变成[100,[1],[1]]

x=[[1]] * 3
x[0][0]=100 # 将会产生[[100],[100],[100]]

image.png

简单来说,就是在内存中开启一块内存存放[1],然后列表的元素指向[1]的地址,当修改了[1]中的值,所有列表中的值也变,因为指向同一个[1]。

删除

  • remove(value)->None:从做向右查找第一个匹配的值,删除并返回None,没有找到返回ValueError错误
l = [1,2,3,4]
print(l.remove())
print(1.remove(11)) # 返回ValueError错误
  • pop(index):不加索引参数默认删除最后一个索引的值并返回,加上索引参数删除对应索引的值并返回,没有找到该索引返回IndexError错误
l =[1,2,3,4]
print(l.pop())
print(l)
print(l.pop(1))
print(l)
print(l.pop(11)) # 返回IndexError错误
  • clear()->返回None:情况所有元素
l = [1,2,3,4]
l.clear()
print(l) #返回None

反转列表

  • reverse()->None
l = [1,2,3,4]
l.reverse()

排序

  • sort(key,reverse=False:key是一个自定义的方法,reverse是否倒叙排序
l = [4,3,2,1,0]
l.reverse()

成员判断

l =[1,2,3,4]
print(1 in l) # True
print(5 in l) # False

列表判断是否相等

a = list(range(4))
b = list(range(4))
print(a == b) # 判断值是否相等,返回True
c = a # 将a的地址赋予c(存储list(range(4))的地址)
c[2] = 10 # 实际上修改了a指向列表中的值,所以a和c都改变了索引2的值
print(a) # [0,1,10,3]
print(a == b) # False
print(a == c) # True

image.png

上图是执行到c=a的时候,无论是执行c[2]=10还是a[2]=10结果都是一样,改变了同一个地址列表的值

a = list(range(4))
b = a.copy() # 创建一个新的列表赋值给b
print(a == b) # True,因为==判断就是列表中的值是否相等
a[2] = 10 # 修改的是a列表的值
print(a == b) # False,值不相等了

image.png

b = a和b = a.copy()区别就是b和a指向同一个列表还是指向不同列表的区别

a = [1, [2, 3, 4], 5]
b = a.copy() # ab指向不同列表
print(a == b) # True 相等,因为列表中的值相等
a[2] = 10 # a = [1,[2,3,4],10]
print(a == b) # 不相等,值不同了,False
a[2] = b[2] # ab列表值相等了
print(a == b) # True
a[1][1] = 100 # 修改了列表中元素列表中的值,a.copy()拷贝了[2,3,4]的地址值,而不是值,所以无论a[1][1]还是b[1][1]=100,都修改成[2,100,3]
print(a == b) # True [1,[2,100,4],5]
print(a) # [1,[2,100,4],5]
print(b) # [1,[2,100,4],5]

image.png

  • shadow copy:碰到引用类型只会复制地址

  • deep copy:往往会复制引用类型的值

import copy
a = [1, [2, 3], 4]
b = copy.deepcopy(a) # 这次拷贝了[2,3,4],a[1]和b[1]是2个不同的列表了
print(a == b)
a[1][1] = 100
print(a == b) # False
print(a) # [1,[2,100],4]
print(b) # [1,[2,3],4]

元祖tuple

是一组元素集合,一旦定义无法改变,如果元素是引用类型,存储的是地址值,引用类型中值是可以改变,元祖用()表示

初始化

  • ()、tuple() 空元祖
  • tulle(iterable)
t1 = () # 空元组
t2 = (1,) # 必须有这个逗号 t2=(1)和t2=1相等
t3 = (1,) * 5 # (1,1,1,1,1)
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])

元祖操作和list类似,因为定义后无法改变,所以无法增删改,但是元素是引用类型的话,引用类型的值是可以改变的,因为元祖存储的是引用类型的值

t1 = ([1]) * 3 # 等于[1]*3 [1,1,1],因为没加,(1,)
t1[1] = 100 # [1,100,1]
# 注意下面的例子
t2 = ([1],) * 3 #
print(t2) # ([1],[1],[1]) 注意[1]是同一个列表,改变其中一个列表将会全部修改
# t2[1] = 100  报错
t2[0][0] = 100
print(t2)  # ([100],[100],[100])

字符串

是字符的序列,是不可变的。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' """

索引

  • 字符串是序列,支持下标访问。但不可变,不可以修改元素。
sql = "select * from user where name='tom'"
print(sql[4]) # 字符串'c'
sql[4] = 'o' # 不可以

连接

  • +:字符串拼接,返回新的字符串

  • join()方法:

    • sep.join(iterable)

    • 使用指定字符串作为分隔符,将可迭代对象中字符串使用这个分隔符拼接起来

    • 可迭代对象必须是字符串

    • 返回一个新的字符串

x = 'ab'
x = x + 'cd'
print(','.join(x))
print('\t'.join(x))
print('\n'.join(x))
print('-'.join(range(5))) # 不行,必须是字符串

字符查找

  • find(sub,start,end):在指定的区间[start, end),从左至右,查找子串,没找到返回-1

  • rfind(sub,start,end):在指定的区间[start, end),从右至左,查找子串sub,没找到返回-1

  • index()、rindex()和上面用法相同,但是没找到会报ValueError错误

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))
  • count(sub,start,end)-->int:从左向右返回子串在字符串中的数量
s = 'magedu.edu'
print(s.count('edu'))
print(s.count('edu', 4))
  • len(str):返回字符串的字符个数
print(len("abc"))

分割

  • split(sep,maxsplit=-1)-->list

    • 从左向右,sep指定分隔符,默认是空白字符作为字符串
    • maxsplit指定切割的次数,-1表示遍历整个字符串
  • rsplit(sep,maxsplit=-1)-->list

    • 从右向左,sep指定分隔符,默认是空白字符作为字符串
    • maxsplit指定切割的次数,-1表示遍历整个字符串
  • splitlines([keepends]) -> list of strings

    • 按照(\n,\r,\r\n)切割,keepends是否保留切割符
  • partition(sep) -> (head, sep, tail)

    • 从左向右,遇到分隔符就分割成头、分隔符、尾
    • 没找到就返回头和2个空元素的3元祖
    • seq必须指定
  • rpatition(seq) -> (head,seq,tail)

    • 从右向左,遇到分隔符就分割成头、分隔符、尾
    • 没找到就返回头和2个空元素的3元祖
    • seq必须指定
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())
s = ','.join('abcd')
print(s.partition(','))
print(s.partition('.'))
print(s.rpartition(','))
print(s.rpartition('.'))

替换

  • replace(old,new,count)->str
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
  • startswith(prefix[, start[, end]]) -> bool
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() 是否只包含空白字符

格式化输出

realpython.com/python-stri…

docs.python.org/3/library/s…

pyformat.info/#simple

字节序列

python3引入bytes、bytearray类型,bytes是不可变类型,bytearray是可变类型

编码和解码

  • 编码:str=>bytes,字符串在内存中存储的字节序列的值,因为计算机只认识0和1

  • 解码:bytes=>str,字节序列按照某字符集转换成字符

  • python3中默认使用unicode字符集,utf-8的编码规则。unicode和utf-8的关系:www.zhihu.com/question/23… www.ruanyifeng.com/blog/2007/1…

print("abc".encdoe()) # 缺省为utf-8编码
print("啊".encode('utf-8'))
print("啊".encode('gbk'))
print(b'abc'.decode('utf8'))
print(b'\xb0\xa1'.decode('gbk')) # 不指定gbk解码的话会出现乱码,因为默认的编码规则utf-8无法识别b'\xb0\xa1'

bytes初始化

  • bytes():空字节
  • bytes(int):指定几个空字节的字节序列
  • bytes(str,encode):等价于str.encode()
  • bytes(bytes):复制一个字节序列
a=bytes()
b=bytes(2) # b'\x00\x00'
c=bytes('abc',"utf-8")
d=bytes(b'zxc')

bytesarray初始化

bytesarray可以理解为字节序列的列表

  • bytesarray():空bytesarray
  • bytesarray(int):指定几个空字节的字节列表
  • bytesarray(str,encode):bytearray 近似string.encode(),不过返回可变对象
  • bytesarray(bytes):复制一个字节序列成bytesarray
a = bytearray()
print(a)
b = bytearray(2)
print(b)
c = bytearray('abc',"utf-8")
print(c)
d = bytearray(b'qwe')
print(d)

bytearray和list比较像,所以有很多列表的操作

  • append(value):尾部添加
  • insert(index,value):指定索引插入
  • extend(iterable_of_int):将一个可迭代的整数集合追加到当前bytearray
  • pop(index):指定去除的索引
  • remove(value):找到第一个删除,找不到ValueError
  • clear():清空
  • reverse():反转,也可以用reversed()方法
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()

切片

sequence[start:stop]
sequence[start:stop:step]

  • 通过索引区间获取线性结构的一部分(list tuple str bytesarray bytes)

  • 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])
print(x[8:2:-2])
print(x[8:-10:2])
print(x[8:-10:-2])
print(x[-5:4:-1])
print(x[-5:5:-1])

切片原理

x = [0, 1, 2]
y = x[:] # 复制了x列表,但是地址值不同
print(x, y) 
print(id(x), id(y))
x[0] = 100 # 不会影响y
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 # x和y存储的都是[1]的地址
print(x, y) # 都是[[100]]
print(x == y)
print(x is y)
x[0] = 200 # x=[200] y=[[1]]
print(x == y) # ?
print(x, y)

切片是复制了索引区间的列表,如果有引用类型,只是会复制地址值