python前端基础知识总结
知识总结
认识Python
- 发展历史
- 版本选择
- python2.7是python2的最后一个版本,到2020年将不再维护
- python3.6是python3最新的版本,是python方向的未来
- py2与py3不兼容,现在我们选择py3进行讲解,以后会对比py2和py3的区别
- 就业方向
- WEB后端、爬虫、运维、数据分析、机器学习、人工智能
- 课程体系:
- python语法基础、WEB/Linux/DB、WEB框架、爬虫/数据分析/机器学习
安装环境
- python安装:
- 自定义安装(将安装目录添加系统环境变量PATH下、为所有用户安装),然后一路NEXT即可
- 测试:启动终端(win + r => cmd),在终端中输入python然后敲回车,看到>>>表示启动成功
- 退出环境:exit()
- pycharm安装
- 社区版,一路NEXT即可完成安装
- 启动测试:在快速启动栏中选择pycharm,看到欢迎页面表示成功
- 说明:若缺啥*.dll文件,去Windows官网下载相关软件包安装即可。
第一个程序
- 打开pycharm
- 新建一个工程
- 新建一个文件01-hello.py(后缀.py),输入:print(‘Hello world!’)
- 运行:
- 右键 =》 Run ‘01-hello’
- 终端:python 01-hello.py
- 记得文件的路径要写对
- python执行方式
- 交互式:直接终端启动python环境,然后输入一条解析执行一条命令;关闭后无法保留执行过的代码。
- 退出:exit() 或 quit()
- 脚本式:将所有要执行的代码放到一个文件中,然后统一执行
- 说明:为了保留代码,以后我们都采用此方式
- 交互式:直接终端启动python环境,然后输入一条解析执行一条命令;关闭后无法保留执行过的代码。
- 额外说明:代码中所有的控制语句都是英文字符
变量定义
-
什么是变量?
- 在程序运行过程中,其值可以改变的量。(具有名字的一段存储空间)
-
标识符命名规范
- 只能由数字、字母、下划线组成
- 不能以数字开头
- 不能是系统关键字(有特殊意义的语法字符串)
-
命名原则
- 尽量做到见名知意
- 尽量使用英文,实在不行使用全拼
- 推荐命名方式:采用小写+下划线,如:user_name
-
示例:
# 单一赋值
a = 10# 统一赋值 b = c = d = 20 # 对称赋值 e, f = 30, 40 # 删除变量 del a # 此处会报NameError错 print(a)
-
使用常量
- python中没有常量,通常我们会使用大写加下划线的方式模拟常量,如:USER_NAME = ‘xiaoming’
代码注释
- 什么是注释?
- 所谓注释就是写给开发人员看的提示说明内容;注释是给人看的,解析器会直接忽略。
- 为什么写注释?
- 对自己能够很快回忆起思路,对于合作伙伴可以非常方便的读懂你的意思。
- 怎么写注释?
- 单行注释
单行注释
- 多行注释(模拟)
‘’‘注释’’’
“”“注释”""
- 单行注释
输入输出
-
输出:将特定的内容打印出来
a = 10
b = 20# 输出:可以一次打印多个数据 # sep:多个数据的分割内容 # end:结束时的内容,默认是'\n',表示换行 print(a, b, sep=',', end='')
-
输入:程序运行后,等待用户的输入,然后才能进行下一步的操作
# 获取用户输入,或阻塞程序,使用时最好给出提示信息
c = input(‘请输入你的密码:’)print(c)
存储单位
- 最小数据单位是比特bit,表示一位二进制的0或1,写作’b’,是网络数据传输的基本单位
- 最小存储单位是字节byte,写作’B’,1B = 8b
- 1KB = 1024B
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
- 2^32 = 2^10 * 2^10 * 2^10 * 2^2 = 4G
数据类型
进制转换
- 十进制
- 基数0~9,逢10进1
- 示例:123 = 1 * 10^2 + 2 * 10^1 + 3 * 10^0 = 100 + 20 + 3 = 123
- 二进制
- 基数0和1,逢2进1
- 示例:0b110100 = 2^5 + 2^4 + 2^2 = 32 + 16 + 4 = 52
- 十进制转二进制:除2取余,倒序书写
- 22 = 0b10110
- 八进制
- 基数0~7,逢8进1
- 示例:0o123 = 1 * 8^2 + 2 * 8^1 + 3 * 8^0 = 64 + 16 + 3 = 83
- 八进制转二进制:八进制的1位可以表示3位二进制数
- 0o123 = 0b 001 010 011
- 十六进制
- 基数09、AF,逢16进1
- 示例:0xAB = 10 * 16^1 + 11 * 16^0 = 160 + 11 = 171
- 十六进制转二进制:十六进制的1位可以表示4位二进制数
- 0xABC = 0b 1010 1011 1100
- 计算机中是以哪种进制存储数据的,为什么?
- 二进制,因为计算机只识别二进制。具体原因:
- 稳定性高(只有0和1)、成本低(技术上容易实现)、与生活中的真假逻辑相吻合(便于解决生活中的实际问题)
- 原码反码补码
- 如何存储负数?
- 最高位作为符号位:0表示正数、1表示负数
- 虽然牺牲了最高位,但是解决了负数的表示问题,简化了硬件设计
- 原码反码和补码:是针对负数而言的(正数的三码一致)
- 负数的反码等于数据原码的符号位不变,数据位取反
- 负数的补码等于对应的反码加1
- 计算机中的数据都是以补码的形式存储的
- 如何存储负数?
数据类型
-
说明:编程语言中不同的数据类型都是为了解决生活中的实际问题而出现的,每种类型都有相关的运算。
-
python中常用数据类型:整形、浮点、布尔、字符串、列表、元组、字典、集合等
-
整型(int):就是数学中的整数
-
浮点(float):就是数学中的小数
# 浮点
b = 3.14
print(b, type(b))# 科学计数法 c = 3.1415926e-3 print(c, type(c))
-
复数(complex)
# 复数:了解
d = 2 + 3j
print(d, type(d)) -
布尔(bool):对应于生活中的真假逻辑,只有两个值True/False
-
空(NoneType):空类型,只有一个值None
-
字符串(str):使用引号括起来的一串字符
- 定义:一对单引号、一对双引号、三对单引号、三对双引号
- 转义:使用’’,使原来有特殊含义的字符变成普通字符,也可以在定义字符串的前面加一个’r’
-
列表(list):通过[]进行定义,可以存放一系列的任意数据,是一种容器类型
lt = [1, 2, ‘hello’, 3.14, True]print(lt, type(lt)) # 通过下标获取元素,有越界问题 print(lt[1])
-
元组(tuple):通过()进行定义,可以作为容器存放任意数据,元素是不可修改的
tp = (1, 2, [3, 4, 5])
print(tp, type(tp))
# 也是通过下标进行访问
print(tp[2])# 定义一个元素的元组后面要添加一个, tp2 = (1,) print(tp2, type(tp2))
-
集合(set):通过{}进行定义,可以作为容器存放任意数据,但是元素是不能重复的,且是无序的
s1 = {‘李白’, ‘杜甫’, ‘白居易’, ‘王安石’, ‘苏轼’, ‘李白’}
s2 = {‘李白’, ‘李商隐’, ‘李清照’, ‘李贺’, ‘李煜’, ‘苏轼’}# print(s1, type(s1)) # 交集 print(s1 & s2) # 并集 print(s1 | s2) # 差集 print(s1 - s2) print(s2 - s1) # 定义空集合不能使用{},这是留给定义空字典使用的 # 应该使用set() # s3 = {} # print(type(s3)) s4 = set() print(type(s4))
集合经常用于去重操作
-
字典(dict):通过{}进行定义
-
元素是由键值对组成的
-
键和值之间是有’:'进行连接
-
键是唯一的,而值可以是任意的
-
示例:
d = {‘name’: ‘dahua’, ‘age’: 18}
print(d, type(d))可以根据键获取值
print(d[‘name’])
当键不存在时或报KeyError错
print(d[‘height’])
可以通过get方法根据键获取值,
print(d.get(‘age’))
当键不存在时不会报错,会返回None
print(d.get(‘height’))
可以设置默认值,有对应的键返回其值,没有时返回设置的默认值
print(d.get(‘weight’, 75))
统计元素个数,字典统计的是键值对个数
print(len(d))
print(len(s1))
print(len(lt))
print(len(‘helloworld’))
-
类型转换
-
隐式类型转换:混合运算、条件判断
-
强制类型转换:使用专门的函数进行转换
int:转换为整型
float:转换为浮点
str:转换为字符串
list:转换为列表
tuple:转换为元组
set:转换为集合
dict:转换为字典 -
示例:
# 转换为整数
# a = int(3.14)
# 参数1:需要转换的数据
# base:数据的进制类型,默认为十进制
# a = int(‘123’, base=8)
# a = int(‘abc’, base=16)# 浮点 # a = float(250) # 字符串 # a = str(123) # 列表 # a = list('hello') # a = list((1, 2, 3)) # a = list({1, 2, 3}) # 可以转换不会报错,但是只保留了键 # a = list({'name': 'ergou', 'age': 18}) # 元组 # a = tuple([1, 2, 3]) # 集合 # a = set([1, 2, 3]) # 字典 lt = [('name', 'dahua'), ('age', 18)] a = dict(lt) print(a, type(a))
类型相关操作
-
字符串
s1 = ‘hello’
s2 = ‘world’
# 可以使用’+'将字符串拼接在一起
s3 = s1 + s2
print(s3)# '*'可以重复前面的字符串若干次 s4 = 'abc' * 3 print(s4) # len函数统计字符串长度 print(len(s1)) s = 'abcdefg' # 从开头进行提取,下标从0开始 print(s[0]) # 从末尾进行提取,下标从-1开始 print(s[-1]) # 切片 # 格式:s[开始:结束:步进] print(s[1:3]) # 当一边的边界省略,则提取到改侧的边缘 print(s[1:]) print(s[:4]) print(s[1:-2]) print(s[:-3]) print(s[-3:]) # 指定步进值,默认为1 print(s[::2]) # 逆序提取 print(s[::-1]) # 格式化 # %s:字符串 # %d:整型 # %f:浮点 # %c:字符 name = '二狗' like = '大花' age = 18 print('俺叫%s,暗恋%s,她今年%d岁' % (name, like, age)) # python中特有的解决方案 print('俺叫{},暗恋{},她今年{}岁'.format(name, like, age)) print('俺叫{2},暗恋{1},她今年{0}岁'.format(name, like, age)) print('俺叫{l},暗恋{n},她今年{a}岁'.format(n=name, l=like, a=age))
-
列表
lt = [1, 2, 3, 4, 5]print(lt[0]) print(lt[-1]) print(lt[1:3]) print(len(lt)) # 修改元素 lt[0] = 100 # 追加元素,将传递的元素作为一个整体(一个元素)追加到列表尾部 lt.append(200) # lt.append([300, 400]) # 将可迭代对象的元素展开添加到列表中 (扩充) lt.extend([300, 400]) # 插入元素,在指定位置插入元素 lt.insert(2, 250) lt.insert(4, 250) # 删除元素 # 根据索引号删除 del lt[0] # 根据值进行删除,只会删除第一个 lt.remove(250) # 返回并删除:返回并删除指定下标的元素,默认是最后一个 ele = lt.pop(2) # print(ele) # print(lt) lt = [1, 2, 3, 4, 5, 3] # 查询元组在列表中的索引号 # 找到就会返回其索引号,即第一个出现的位置 # 若不在列表中则会报错 print(lt.index(3)) # 统计元素在列表中出现的次数 print(lt.count(3)) # 逆序 lt.reverse() # 排序 # reverse=True表示降序排序 lt.sort(reverse=True) print(lt)
ASCII
- 说明:美国信息交换标准代码,就是用一个数字表示一个字符的规范
- 转换函数:
# 字符 => ASCII
print(ord(‘A’))
# ASCII => 字符
print(chr(97))
运算符与分支结构
运算符
- 赋值运算符
- 用’='表示,左边只能是变量。
- 算术运算符
- +、-、*:加、减、乘
- /:除法,结果是浮点数
- //:除法,结果是整数
- %:求余
- **:求幂,也可以使用函数pow
- 复合运算符
- +=、-=、*=、…
- 示例:a += b等价于a = a + b
- 关系运算符
-
、>=、<、<=、==、!=
- 表达式:由运算符和操作数构成的式子
- 关系表达式:由关系运算符和操作数构成的式子
- 关系表达式式有值的:符合数学逻辑值为真(True),不符合数学逻辑值为假(False)
-
- 逻辑运算符
- 说明:逻辑运算就是用来合并或取反表达式的
- 运算:与、或、非
- 与(and):两边的表达式同时为真,结果才为真
a = 200其他语法也通用的写法
print(a > 10 and a < 100)python中特有的形式
print(10 < a < 100)
print(a%3 == 0 and a%5 == 0) - 或(or):两边的表达式一个为真,结果就为真
y = int(input(‘请输入一个年份:’))
print((y%40 and y%100!=0) or (y%4000)) - 非(not):用于取反表达式,真变假,假变真
- 使用not是为了简化表达式的书写
- 经常伴随着隐式类型转换
- 成员运算符
- in、not in:判断一个值是否在另一个里面
- 说明:经常用在字符串、列表、元组、集合、字典等成员的判断
- 示例:
lt = [1, 2, 3]
print(8 not in lt)
dt = {‘name’:‘dahua’, ‘age’: 18}对于字典,判断的是键
print(‘name’ in dt)
- 位运算符(了解)
- &:按位与,对应的数据位同时为1,结果上对应的位才为1
- |:按位或,对应的数据位一个为1,结果上对应的为就为1
- ^:按位异或,对应的数据位相同是结果为0,不同时结果为1
- ~:按位取反,数据的每一位0变1,1变0
- <<:按位左移,左移一位相当于乘以2
-
:按位右移,右移一位相当于除2
- 运算符的优先级与结合性
- 语法中没有明确规定优先级与结合性,即使是明确说明了你也记不住
- 建议:使用时不用刻意记录优先级与结合性,当需要明确指定时添加括号即可
流程控制
- 说明:
- 按照代码的执行流程,程序可以分为三种结构:顺序结构、分支结构、循环结构
- 顺序结构:代码按照从上到下的顺序依次执行的结构,没有语法要求
- 代码层次:python中的代码层次不是通过大括号表示的,而是通过缩进体现的
- 分支结构(if-elif-else)
- 格式1:适合于解决生活中的条件执行问题
if 表达式:
语句块
执行流程:当程序执行到if语句时,首先会判断表达式的真假。若表达式的值为真,则执行后面缩进的语句块;若表达式的值为假,则跳过语句块,执行后面的内容。 - 格式2:适合于解决生活中的非此即彼的问题
if 表达式:
语句块1
else:
语句块2
执行流程:当程序执行到if-else语句时,首先会判断表达式的真假。若表达式的值为真,则执行语句块1;若表达式的值为假,则执行语句块2. - 格式3:适合于解决生活中的多种选择问题
if 表达式1:
语句块1
elif 表达式2:
语句块2
…
else:
语句块n
- elif的个数没有限制
- else可以省略不写
- 所有的互斥选择语句块最多只能执行一个
- 格式1:适合于解决生活中的条件执行问题
相关类型操作
-
字符串切片
-
列表操作
-
元组操作
# tp1 = (1, 2, 3)
# tp1 = (1,)
tp1 = 1, 2, 3
tp2 = (4, 5, 6)
# 可以直接拼接在一起
# tp3 = tp1 + tp2
# print(tp3, type(tp3))
# 重复指定次数
tp4 = tp1 * 3
print(tp4)
# 统计元素个数
print(len(tp4))
tp = (1, 2, 3, 4, 5, 6)
# 切片操作
print(tp[0], tp[-1])
print(tp[1:-1])
# 获取指定元素的索引
print(tp.index(3))
# 统计元素出现的次数
print(tp.count(3))
# 最大值
print(max(tp))
# 最小值
print(min(tp)) -
集合操作
s = {‘彦炯’, ‘露露’, ‘彦博’, ‘启明’, ‘吕威’, ‘二狗’}# 添加元素 s.add('继光') # 删除元素 # s.remove('二狗') # 删除不存在元素会报KeyError错 # s.remove('狗蛋') # 删除元素,元素存在则删除,不存在也不报错 s.discard('狗蛋') # 返回并删除,元素是随机的 # print(s.pop()) # 清空元素 s.clear() # print(s) s1 = {'小马', '小乔', '小周'} s2 = {'小王', '小杜', '小马', '小乔', '小周'} # 并集 # print(s1.union(s2)) # 交集 # print(s1.intersection(s2)) # 求交集,并用交集覆盖原来的集合 # s1.intersection_update(s2) # 差集 # print(s1.difference(s2)) # 求差集,并用差集覆盖原来的集合 # s1.difference_update(s2) # print(s1) # 判断是否没有交集 print(s1.isdisjoint(s2)) # 判断是否是另一集合的子集 print(s1.issubset(s2)) # 判断是否是另一集合的父集/超集 print(s2.issuperset(s1))
-
字典操作
d = {‘name’: ‘xiaoming’, ‘age’: 20}# 获取元素 # 有就返回对应的值,没有就报KeyError错 print(d['name']) # 有就返回对应的值,没有就返回None,可以指定默认值 print(d.get('namexxx', '默认值')) # 修改元素 # 键存在则修改对应的值 d['name'] = '二狗' # 键不存在则添加键值对 d['height'] = 180 # 更新:存在的键会覆盖,不存在的键会添加 d.update({'name': 'dahua', 'weight': 50}) # 删除元素 # del d['weight'] # 返回并删除 print(d.pop('weight')) # 清空元素 d.clear() print(d)
练习
-
从终端获取一个表示年份的整数,判断是否是闰年,是就打印xxx年是闰年,不是就打印xxx年是平年
-
'''a=int(input('请输入一个年份')) if (a % 4 ==0 and a % 100!=0) or (a % 400==0): print(a,'年是闰年') else: print('是平年')'''
-
输入两个整数,打印较大值
-
'''a = (8,20) print(max(a))''' '''a = int(input('请输入第一个数字')) b = int(input('请输入第二个数字')) if a > b: print(a) else: print(b)'''
-
输入三个整数,按照从小到大的顺序打印
-
# a = int(input('请输入第一个整数:')) # b = int(input('请输入第二个整数:')) # c = int(input('请输入第三个整数:')) # lt=list((a,b,c)) # lt.sort() # print(lt)
-
输入一个整数,判断其是否能同时被3和7整除
-
'''a = int(input('请输入一个数字')) if a % 3 ==0 and a % 7 ==0: print(a,'能被3和7整出') else: print(a,'不能被3和7整除')'''
输入一个字符,是大写转换为小写,小写转换为大写,其他字符保持不变,然后输出
ch = input('亲输入一个字符:')
asc = ord(ch)
#if 65<=asc<=90: #判断字符大小写
if 'A'<= ch <='Z':
print('是大写,转换后:',chr(asc+32) )
#elif 97<=asc<=122: #判断字符大小写
elif 'a'<= ch <='z':
print('是小写,转换后:',chr(asc-32))
else:
print(ch)
循环结构
循环结构(while)
- 格式:
while 表达式:
语句块
执行流程:当程序执行到while语句时,首先判断表达式的真假。若表达式的值为真,则执行缩进的语句块,之后返回表达式继续判断;若表达式的值为假,则跳过缩进的语句块执行。 - 说明:
- 表达式:也叫循环条件
- 语句块:也叫循环体
- 死循环:循环条件一直成立
- break:跳出循环
- continue:结束本次循环,进入下次循环
- else:对应的语句块,循环正常退出时会执行,非正常退出(break)时不执行
循环结构(for-in)
- 说明:也是一种循环结构,经常用于便利可迭代对象,如:字符串、列表、元组、字典等
- 格式:
for x in y:
语句块
执行流程:x一次代表y种的一个元素,遍历结束循环也就结束了。
列表生成式
-
range:
# 一个对象,保存了产生连续整数的算法,可以节约空间
# 可以指定起始位置,默认为0
# print(range(10))# 可以进行遍历 for i in range(10): print(i) # 可以转换为列表 print(list(range(2, 10)))
-
列表生成式
# 列表生成式:可以快速方便地生成列表
print([i for i in range(1, 11)])
print([i for i in ‘abcdefg’])
print([i2 for i in range(1, 11)])
print([ii for i in range(1, 11)])
print([str(i) for i in range(1, 11)])
print([i for i in range(1, 11) if i % 2 == 0])
# 生成的列表可以与遍历的内容没有一毛钱关系
print([250 for i in range(1, 11)])
循环嵌套
-
循环能否嵌套
- 答:能
-
循环嵌套示例
# 外层循环控制打印多少行
for i in range(1, 11):
# print(’’ * i)
# 内存循环控制每一行多少个
for j in range(i):
print(’’, end=’ ')
print()
练习:使用while实现一遍 -
思考:列表排序实现,冒泡排序法思路(升序排序)
lt = [8, 3, 6, 9, 5, 2, 4, 1, 7]
第一轮:[3, 6, 8, 5, 4, 1, 7, 9]
第二轮:[3, 6, 5, 4, 1, 7, 8, 9]
第三轮:[3, 5, 4, 1, 6, 7, 8, 9]-
参考示例:
冒泡排序:升序排序
lt = [8, 3, 6, 9, 5, 2, 4, 1, 7]
n = len(lt)外出循环控制排序多少轮
for i in range(n-1):
# 内存循环控制相邻两个元素的比较
for j in range(n-1-i):
if lt[j] > lt[j+1]:
# 通用交换元素方式
# temp = lt[j]
# lt[j] = lt[j+1]
# lt[j+1] = temp
# python中特有方式
lt[j], lt[j+1] = lt[j+1], lt[j]print(lt)
-
-
选择排序
思路:先取出一个位置,用该位置的元素与后面的所有元素挨个比较,不合适就发生交换。
示例:lt = [8, 3, 6, 9, 5, 2, 4, 1, 7]
第一轮:1, 8, 6, 9, 5, 3, 4, 2, 7
第二轮:1, 2, 8, 9, 6, 5, 4, 3, 7
第三轮:1, 2, 3, 9, 8, 6, 5, 4, 7
字符串操作
-
切割与拼接
s = ‘I love you more than i can say’
# 切割字符串
# sep:指定按照什么进行切割,默认按照空格切割
# maxsplit:指定最大切割次数,默认不限制次数
# ret = s.split(sep=‘abc’, maxsplit=1)
# 从右边进行切割
ret = s.rsplit(’ ', maxsplit=1)
print(ret)s = 'Hello\nworld' # 按照换行进行切割 print(s.splitlines()) s = 'I love you more than i can say' ret = s.split() # print(ret) # 字符串拼接 s2 = '*'.join(ret) print(s2)
-
查找统计判断
s = ‘Hi buddy, if you have something to say, than say; if you have nothing to say, than go.’# 子串查找:找到首次出现的位置,返回下标,找不到返回-1 # ret = s.find('hello') # 从后面查找 # ret = s.rfind('to') # 统计子串出现的次数 # ret = s.count('if') # 判断是否已指定内容开头 # ret = s.startswith('Hi') # 判断是否已指定内容结尾 ret = s.endswith('go.') print(ret)
-
转换及替换
s = ‘hellO worlD!’
# 转换为全大写
print(s.upper())
# 转换为全小写
print(s.lower())
# 大小写转换
print(s.swapcase())
# 首字母大写
print(s.capitalize())
# 每个单词首字母大写
print(s.title())
# 用指定的内容替换指定内容,还可以值替换次数
print(s.replace(‘l’, ‘L’, 2)) -
类型判断
s = ‘abcABC2’
# 是否是全大写
print(s.isupper())
# 是否是全小写
print(s.islower())
# 是否每个单词首字母都大写
print(s.istitle())
# 是否是全数字字符
print(s.isdecimal())
# 是否是全字母
print(s.isalpha())
# 是否全是字母或数字
print(s.isalnum())
练习
-
计算1~100之间所有整数的和
-
'''a = 0 i = 0 while a < 100: a+=1 i+=a print(i)'''
-
-
打印字符A~Z
print([chr(i) for i in range(ord('A'),ord('Z')+1)])
-
循环输入10个字符,大写转小写,小写转大写,其它字符不变,然后输出
-
'''a = 1 while a<=10: ch = input('亲输入一个字符:') asc = ord(ch) # if 65<=asc<=90: #判断字符大小写 if 'A' <= ch <= 'Z': print('是大写,转换后:', chr(asc + 32)) # elif 97<=asc<=122: #判断字符大小写 elif 'a' <= ch <= 'z': print('是小写,转换后:', chr(asc - 32)) else: print(ch) a+=1'''
-
将12345转换为54321
-
n = 12345 ret = 0 while n : #获取最后一位 last = n % 10 #求商 n = n // 10 #原来的结果乘以10 然后加上本次得到的数 ret = ret * 10 +last print(ret))
‘’'n = 12345
ret = 0
while n :
#获取最后一位 last = n % 10 #求商
n = n // 10
#一次性得到商和余数 n,last=divmod(n,10) #原来的结果乘以10 然后加上本次得到的数 ret = ret * 10 +last
print(ret)’’’
-
将12345转换为’12345’,不要使用str
-
n = 12345 ret = '' while n: n,last=divmod(n,10) ch = chr(last + ord('0')) ret = ch + ret print(ret,type(ret))
-
-
将’12345’转换为12345,不要使用int
-
遍历列表,打印:我叫name,今年age岁,家住dizhi,电话phone
lt = [
{‘name’:‘小王’, ‘age’:18, ‘info’:[(‘phone’, ‘123’), (‘dizhi’, ‘广州’)]},
{‘name’:‘小芳’, ‘age’:19, ‘info’:[(‘phone’, ‘789’), (‘dizhi’, ‘深圳’)]},
{‘name’:‘小杜’, ‘age’:22, ‘info’:[(‘phone’, ‘567’), (‘dizhi’, ‘北京’)]},
{‘name’:‘小孟’, ‘age’:28, ‘info’:[(‘phone’, ‘000’), (‘dizhi’, ‘上海’)]},
{‘name’:‘小乔’, ‘age’:26, ‘info’:[(‘phone’, ‘111’), (‘dizhi’, ‘河南’)]},
] -
for i in lt: name=i['name'] age=i['age'] #取出info中下标为1的元素中的下标为1的元素值 dizhi=i['info'][1][1] phone=i['info'][0][1] print('我叫{},今年{},家住{},电话{}'.format(name,age,dizhi,phone))
-
打印九九乘法表
-
#外层循环控制打印多少行 for i in range(1,10): #内层控制每行怎么打印 for j in range(1,i+1): print("%d*%d=%2d" % (j,i,i*j),end=" ") print (" ")'''
-
从终端输入两个整数m和n,打印m*n的表格,如:2,5,打印如下图形:
1 2 3 4 5
6 7 8 9 10m = int(input(“请输入一个数字”))
n = int(input(“请输入一个数字”))for i in range(m):
for j in range(1,n+1):
num = j + i* n
print(num,end=" ")print()
函数基础
函数简介
- 定义:具有特定功能的一段代码。
- 优点:
- 可以减少代码的重复书写
- 可以将功能的实现着和使用者分开,提高开发效率
- 分类:
- 库函数:print、input、type等
- 自定义:用户自己封装的函数
函数使用
- 基本格式:
def 函数名([参数列表]):
函数体 - 函数名:
- 像变量名一样,只要符合标识符命名规范即可。
- 函数调用:
- 调用格式:函数名([参数])
- 说明:函数不调用是不执行的,只有调用后才会执行
函数分类
-
说明:按照有无参数及返回值来分
-
示例:
# 无参无返回值
def print_ten_hello():
for i in range(10):
print(‘hello world!’)# 无参:调用时无需传参数 # 无返回值:执行完函数的返回值为None # None的一个作用是为了不报错,仅仅只是这样 # ret=print_ten_hello() # print(print_ten_hello()) # # 带参无返回值 def print_n_hello(n): for i in range(n): print('hello world!') # 需要传递参数 print_n_hello(3) # 带参有返回值 def add(a, b): ret = a+b # 使用关键字return返回内容 # 一旦执行return,函数立即结束 # return后面会返回函数返回值 return ret print(add(3,5))
函数参数
-
形参:形式参数,就是写在函数定义处的参数。
-
实参:实际参数,就是在函数调用时传递的参数。
-
位置参数:函数定义时没有默认值的参数,也叫必传参数。调用时实参与定义时的形参要一一对应
-
默认参数:函数定义时有默认值的参数,调用函数时可以不传递该参数。默认参数需要放在末尾
-
关键字参数:函数调用时指定参数的名字,参数的位置就无需考虑。
-
可变长度参数:
def var_len_args(a, b, *args, name=‘二狗’, **kwargs):
print(a, b)
# 是一个元组,用于保存多传的位置参数
print(args)
# 是一个字典,用于保存多传的关键字参数 -
*的使用
def show(a, b=8):
print(a, b)lt = [2, 3] # show(lt[0], lt[1]) # 与上式等价,*是将列表展开,然后作为位置参数传递给函数 show(*lt) d = {'a': '大花', 'b': 18} # show(a=d['a'], b=d['b']) # 与上式等价,**式将字典展开,然后作为关键字参数传递给函数 show(**d)
函数进阶
- 函数定义的位置是随意的吗?
- 不是,函数调用一定要放在定义之后,也就是先定义再调用。
- 函数的名字是否可以相同?
- 不可以,虽然语法不报错,但是后者会覆盖前面的同名函数。
- 函数内部能否定义另一个函数?
- 能,函数内部定义的函数叫内部函数,它是很多高级功能实现的基础。
常用函数
-
内置函数(无需导入)
print:打印,输出
input:输入
type:获取类型
len:统计元素个数
range:产生连续的整数对象
enumerate:枚举可迭代对象
ord:字符转ASCII
chr:ASCII转字符
abs:求绝对值类型转换:int、float、str、bool、set、list、tuple、dict max:最大值 min:最小值 sum:求和 pow:求幂 round:四舍五入 hex:十六进制 oct:八进制 bin:二进制
-
模块函数(需要导入)
import time
#
# while True:
# print(‘Hello world!’)
# time.sleep(1)import math print(math.e) print(math.pi) print(math.ceil(3.1)) print(math.floor(3.9)) print(math.sqrt(4)) # 度转换为弧度 print(math.radians(360)) # 弧度转换为度 print(math.degrees(math.pi)) import sys # 是一个列表,保存所有的命令行参数 print(sys.argv)
练习
-
前面的练习使用函数封装一下
-
实现一个终端计算器,如:python test.py 3 + 5,结果:8
-
删除列表中重复的元素,要求元素的顺序不变
-
lt = [1, 2, 3, 4, 5, 3, 6, 8, 2]
def quchong(lt):
lt2 = []
for i in lt:
# 当前元素不在新列表中,就追加到列表后面
if i not in lt2:
lt2.append(i)
return lt2lt2 = quchong(lt)
print(lt2)
-
-
统计一个字符串中字母、数字、其它字符的个数,返回一个元组
-
def tj(s): zimu = 0 num = 0 qita = 0 for i in range(len(s)): if (s[i]>='a' and s[i]<='z') or (s[i]>='A' and s[i]<='Z'): zimu+=1 elif s[i]>='0' and s[i]<='9': num+=1 else: qita+=1 return (zimu,num,qita) s=input('请输入字符串') print(tj(s))
-
-
返回一个列表中第二大的数
-
字符串解析:号码归属地查询
‘’‘5582|1860101|010|北京市|北京联通GSM卡
5583|1860100|010|北京市|北京联通GSM卡
5584|1368141|010|北京市|北京移动神州行卡
5585|1860111|010|北京市|北京联通GSM卡
5586|1358198|010|北京市|北京移动动感地带卡
5587|1361139|010|北京市|北京移动预付费卡
5588|1361138|010|北京市|北京移动神州行卡
5591|1360110|010|北京市|北京移动全球通卡
5748|1364110|010|北京市|北京移动神州行卡
10186|1581584|020|广东省广州市|广东移动全球通卡
15046|1391897|021|上海市|上海移动全球通卡
17250|1502207|022|天津市|天津移动全球通卡
21137|1345272|023|重庆市万州|重庆移动大众卡
22700|1347812|024|辽宁省沈阳市|辽宁移动大众卡
24256|1377065|025|江苏省南京市|江苏移动全球通卡
26360|1898606|027|湖北省武汉市|湖北电信CDMA卡
28709|1860802|028|四川省成都市|四川联通GSM卡
30641|1552961|029|陕西省西安市|陕西联通GSM卡
31700|1563007|0310|河北省邯郸市|河北联通GSM卡
33360|1583396|0311|河北省石家庄市|河北移动全球通卡
34825|1508122|0312|河北省保定市|河北移动全球通卡
35363|1551235|0313|河北省张家口|河北联通GSM卡
37700|1331326|0316|河北省廊坊市|河北电信CDMA卡
43500|1350358|0358|山西省吕梁市|山西移动全球通卡
43908|1553625|0359|山西省运城市|山西联通GSM卡
44521|1335360|0370|河南省商丘市|河南电信CDMA卡
50078|1509369|0378|河南省开封市|河南移动全球通卡
53603|1583981|0398|河南省三门峡|河南移动全球通卡
53916|1335897|0410|辽宁省铁岭市|辽宁电信CDMA卡
55248|1554254|0411|辽宁省大连市|辽宁联通GSM卡
58618|1374272|0427|辽宁省盘锦市|辽宁移动全球通卡
58932|1554183|0429|辽宁省葫芦岛|辽宁联通GSM卡
60268|1340475|0431|吉林省长春市|吉林移动大众卡’’’
def chaxun(haoma):
set = a.split(’\n’)
n=len(set)
dt = {}
for i in range(n):
set1=set[i].split(’|’)
dt.update({set1[1]:set1[4]})
print(‘号码区域为:’,dt.get(haoma),sep=’’)
while True:
haoma=input(‘请输入号码:’)
chaxun(haoma)
函数使用
变量作用域
-
块级作用域
if True:
name = ‘xiaoming’# 没有块级作用域 print(name)
-
局部作用域
def test():
a = 10test() # 局部变量:在函数内部定义的变量,只能在函数内部使用 # print(a)
-
全局作用域
# 全局变量:定义在函数外部的变量,拥有全局的作用
num = 10def show(): # 函数内部可以使用外部定义的变量 # print(num) # 若想更改外部变量,需要进行global声明 global num # 不能更改外部的全局变量,而是定义了一个局部变量 num = 20 show() print(num)
-
nonlocal使用
def wai():
n = 100
def nei():
# 使用外部函数的局部变量,需要进行声明才可更改
nonlocal n
# 内部函数可以使用外部函数的局部变量,但是不能更改
n = 200
print(n)
nei()
print(n)
wai()
匿名函数
-
函数可以像普通变量一样进行赋值
def test():
print(‘for test’)print(test.__name__) # 函数可以像普通变量一样进行赋值 a = test print(a.__name__) a()
-
函数可以作为一个函数的参数
def show(func):
func()# 函数作为参数传递 show(test)
-
匿名函数
-
说明:当将函数作为参数传递时,若函数只需要一次,没有必要单独定义函数,可以使用匿名函数解决。
-
格式:lambda 参数列表: 表达式
- 参数列表与定义函数是一样,可以是多个,多个参数之间使用逗号分隔
- 表达式就是返回值,不需要使用return关键字
-
示例:
lt = [
{‘name’: ‘dahua’, ‘age’: 18, ‘height’: 165},
{‘name’: ‘erhua’, ‘age’: 16, ‘height’: 160},
{‘name’: ‘dagou’, ‘age’: 20, ‘height’: 175},
{‘name’: ‘ergou’, ‘age’: 15, ‘height’: 155}
]def key(d):
return d[‘height’]lt.sort(key=key)
lt.sort(key=lambda d: d[‘age’])
for i in lt:
print(i)
-
闭包使用
-
定义:具有执行环境的函数
- 外部函数中定义一个内部函数
- 内部函数中使用外部函数的局部变量
- 外部函数将内部函数作为返回值返回
- 此时的内部函数就叫闭包
-
示例:
def wai(n):
# 定义内部函数
def nei():
# 内部函数中使用外部函数的局部变量
return n * n
# 内部函数作为返回值
return neif1 = wai(10) f2 = wai(4) print(f1()) print(f2())
装饰器
-
作用:当需要改变一个函数原有的功能时,但是不想/不能改变原来的函数,可以通过装饰器解决
-
使用:
- 装饰器其实就是一个函数,该函数有一个参数(函数类型),返回一个闭包
- 在返回的闭包中调用传递进来的函数,然后在调用函数的前后就可以添加内容
-
示例:
def zhuangshiqi(func):
def wrapper():
print(‘开始装饰’)
func()
print(‘装饰结束’)return wrapper @zhuangshiqi # 相当于执行了:test = zhuangshiqi(test) def test(): print('for test') # t2 = zhuangshiqi(test) # t2() # test = zhuangshiqi(test) test() @zhuangshiqi def demo(): print('原有内容') demo()
-
分类:
-
装饰无参无返回值的函数
def shuai(func):
def wrapper():
print(‘拉风的暴龙眼镜’)
func()
print(‘鳄鱼牌大头皮鞋’)
return wrapper@shuai def diaosi(): print('杰哥,屌丝一枚') diaosi()
-
装饰带参无返回值的函数
def zhuangshiqi(func):
def wrapper(*args, **kwargs):
print(‘开始装饰’)
func(*args, **kwargs)
print(‘装饰结束’)
return wrapper@zhuangshiqi
def test(n):
print(‘I like num {}’.format(n))test(250)
-
装饰带参有返回值的函数
def zhuangshiqi(func):
def wrapper(*args, **kwargs):
print(‘开始装饰’)
ret = func(*args, **kwargs)
print(ret)
print(‘装饰结束’)
return ret
return wrapper@zhuangshiqi
def add(a, b):
return a + bprint(add(3, 5))
-
递归函数(了解)
- 定义:在函数内部调用自己的函数就叫递归函数。
- 组成:
- 函数内部调用自己
- 终止条件(停止调用自己的条件)
- 核心算法
- 特点:
- 代码简介
- 可读性差
- 瞬间占用内存比较大,终止条件出错立即崩溃
- 能不使用就不使用,就是在不得不用的时候再使用(遍历目录)
- 练习:
-
求n的阶乘
-
def he(n): if n ==1: return n return he(n-1)*n print(he(5))
-
斐波那契数列的第n项
-
示例:1, 1, 2, 3, 5, 8, 13, 21, 34, …
递归方式实现 生成前20项
lis =[]
for i in range(20):
if i ==0 or i ==1:#第1,2项 都为1
lis.append(1)
else:
lis.append(lis[i-2]+lis[i-1])#从第3项开始每项值为前两项值之和print(lis)
#输出第几个斐波那契数字
def fib(n):
a,b=1,1
for i in range(n-1):
a,b =b,a+b
return a
print(fib(10))
-
-
练习:
-
实现列表排序sort函数,要求支持任意类型元素的排序,也支持降序
‘’‘lt = [2,1,5,8,4,3]
def list_sort(lt,key=None,reveres=False):
n = len(lt)
for i in range(n-1):
for j in range(n-1-i):
if key:
if reveres:
if key(lt[j]) < key(lt[j + 1]):
lt[j], lt[j + 1] = lt[j + 1], lt[j]
else:
if key(lt[j]) > key(lt[j + 1]):
lt[j], lt[j + 1] = lt[j + 1], lt[j]
else:
if reveres:
if lt[j] < lt[j+1]:
lt[j],lt[j+1]=lt[j+1],lt[j]
else:
if lt[j] > lt[j+1]:
lt[j],lt[j+1]=lt[j+1],lt[j]
list_sort(lt,reveres=True)
for i in lt:
print(i)’’’ -
计算一个字符串中所有数字的和
-
def num(a): sum = 0 # 设置变量 保存和 for i in range(len(a)): #遍历字符串 if a[i]>='0' and a[i]<='9': #根据下标看是否是数字 sum = sum+int(a[i]) # 数字转换为整数 相加求和 return sum a = input('请输入数字') print(num(a))
-
-
实现一个字符串逆序的函数
def nixu(a):
n = len(a)
for i in range(n):
for j in range(n-1):
s = []
s.append(i)
return s -
返回一个列表中出现次数最多的元素
def duo(n):
a = 0
for i in n:
if n.count(i) > a:
s = i
a = n.count(i)
return s
n = [1,2,3,4,5,5,5,6,7,8,9,9,9,9,9]
print(duo(n))lt = [‘小马’,‘小敏’,‘小乔’,‘小敏’,‘小杜’,‘小蒙’,‘小敏’]
def max_count(lt):
#定义一个字典用于存放元素及出现的次数
d = {}
#记录最大的次数的元素
max_key=None
#遍历列表 统计每个元素出现的次数 然后保存到字典
for i in lt:
if i not in d:
#计算元素出现的次数
count = lt.count(i)
#保存到字典中 最多的元素为键 次数为值
d[i] = count
#记录次数最大元素
if count > d.get(max_key,0):
max_key = i
return max_keyprint(max_count(lt))
#直接统计 简单统计
print(max(lt,key=lt.count))from collections import Counter
c = Counter(lt)
print(dict©)
函数使用
零碎知识
-
灵活的if-else
a = 3 if False else 5# 上下两种写法等价 # if False: # a = 3 # else: # a = 5 print(a)
-
灵活的and/or
# 前面的表达式为真,才会执行后面的表达式
a = True and 3
print(a)# 前面的表达式为假,后面的表达式根本无需执行 b = False and 5 print(b) # 前面的表达式为真,后面的表达式无需执行 c = True or 3 print(c) # 前面的表达式为假,需要后面表达式的判断 d = False or 5 print(d)
-
类型判断
a = 250
# print(type(a))
# if type(a) == int:
if type(a) == type(1):
print(‘a’, ‘是一个整数’)# 判断一个对象是不是某种类型的一个实例 print(isinstance(a, int)) print(isinstance(a, str)) def test(): pass # print(type(test)) # 用能使用这种方式进行函数类型的判断 # print(isinstance(test, function)) from inspect import isfunction # 判断一个标识符是否是函数 print(isfunction(test)) print(isfunction(a))
-
变量地址
# 获取变量地址
print(id(a))b = 10 print(id(b)) # a和b地址相同 lt = [1, 2, 3] print(id(lt)) lt2 = [1, 2, 3] print(id(lt2)) # lt和lt2地址不同
生成器
-
使用场景:
在使用列表时,很多时候我们不会一下子使用数据,通常都是一个一个使用;当数据量较大的时候,定义一个列表会使程序内存占用突然增大,为了解决此类问题,python中引入了生成器。 -
生成方式:
-
方式1:将列表生成式的[]改为()即可
列表生成式
lt = [i for i in range(10)]
print(lt)
lt = (i for i in range(3))
print(lt)可以转换为列表
print(list(lt))
可以进行遍历
for i in lt:
print(i)
可以一个一个提取,当提取结束后再次提取会报StopIteration错
print(next(lt))
print(next(lt))
print(next(lt))
print(next(lt)) -
方式2:在函数中使用yield关键字
‘’’当数据量特别大的时候,占用内存会突然增大
def test(n):
lt = []
for i in range(1, n+1):
lt.append(i)
return ltprint(test(10))
‘’’def test(n):
for i in range(1, n+1):
# 执行到此处,函数会返回yield后的内容,然后会停止在这里
yield it = test(3)
print(t)
可以一个一个提取
print(next(t))
print(next(t))
print(next(t))
可以遍历
for i in t:
print(i)
可以转换为列表
print(list(t))
-
-
使用说明:
- 生成器对象保存的是特定数据的生成算法,而不是特定的所有数据
- 使用任意一种方式操作,都是单次的
- 生成器可以做的操作:遍历、next、转换为列表
迭代器
- 定义:能够使用for-in进行遍历,并且可以使用next函数进行迭代的对象
- 说明:
- 生成器就是一种特殊的迭代器
- 判断一个对象是否是迭代器
from collections import Iterator判断是否是迭代器
print(isinstance(lt, Iterator)) - 字符串及容器类型的对象都不是迭代器,他们都是可迭代对象
可迭代对象
- 定义:可以使用for-in遍历的对象,都是可迭代对象
- 说明:
-
前面学习过的字符串及容器类型的对象都是可迭代对象
-
迭代器一定是可迭代对象
-
判断一个对象是否是可迭代对象
from collections import Iterable, Iteratorlt = [1, 2, 3]
判断是否是可迭代对象
print(isinstance(lt, Iterable))
判断是否是迭代器
print(isinstance(lt, Iterator))
-
iter:可以将可迭代对象转换为迭代器
lt = [1, 2, 3]将可迭代对象转换为迭代器
lt2 = iter(lt)
-
random
-
示例:
import random# 生成指定范围内的随机整数 print(random.randint(1, 10)) # 生成0~1之间的随机小数 print(random.random()) # 生成指定范围内的随机整数,可以指定步幅 print(random.randrange(1, 10, 2)) lt = [1, 2, 3, 4, 5, 6, 7] # 从容器对象或字符串中随机挑选一个元素 print(random.choice(lt)) # print(random.choice('ashdaiapo')) # 从容器对象中随机挑取指定个数的元素 print(random.sample(lt, 3)) # 从容器对象中随机挑取一个元素,sample函数个数为1的情况 print(random.choices(lt)) # 打乱一个列表 random.shuffle(lt) print(lt)
高级函数
-
map
-
参数:
func:一个函数
iter:一个可迭代对象 -
功能:
将可迭代对象遍历,每个元素都使用该函数处理一遍,然后返回,保存这种算法的迭代器 -
使用:
from collections import Iterator
lt = [1, 2, 3, 4, 5]def pingfang(n):
return n * n返回map对象,是一个迭代器
ret = map(pingfang, lt)
ret = map(lambda x: x*x, lt)
print(isinstance(ret, Iterator))
print(list(ret))print(next(ret))
print(next(ret))
-
-
练习:
- 熟悉字符串函数:strip、lstrip、rstrip
- 使用map函数:将一个元素全是字符串的列表进行处理,去掉两边空白,然后首字符大写
-
filter
-
参数
function:一个函数
iterable:可迭代对象 -
功能:
使用function依次作用于可迭代对象中的每个元素,当返回结果为True时保留该元素。返回filter对象,是一个迭代器。 -
示例:
lt = [1, 2, 3, 4, 5]def oushu(n):
return n%2 == 0返回filter对象,是一个迭代器
ret = filter(oushu, lt)
ret = filter(lambda x: x%2 != 0, lt)
print(ret)
print(list(ret))print(next(ret))
-
练习:使用filter函数,提取一个任意列表中长度大于3的字符串元素。
-
-
reduce
-
参数
function:一个函数
sequence:一个序列 -
功能:
- 首先从序列中取出前两个元素,作为function的参数处理一下
- 处理完的结果与下一个元素再使用function处理一下
- 处理结束,将处理完的结果返回
-
示例:
from functools import reducelt = [1, 2, 3, 4, 5]
def add(a, b):
return a + bret = reduce(add, lt)
ret = reduce(lambda x, y: x*y, lt)
ret = reduce(lambda x, y: x*10 + y, lt)
print(ret) -
练习:使用reduce函数实现,求一个列表中所有元素的乘积
-
练习
-
使用random函数实现randint函数的功能
-
第一种 import random def my_randint(m,n): return round(random.random()*(n-m)+m) my_randint(1,10) print(my_randint(1,10)) 第二种 import random print(random.randint(1,100)) print(random.random()) def rand_int(start,stop): return round(random.random() * (stop-start)+start) print(rand_int(1,10))
-
生成指定长度的随机字符串,参数:长度、类型
-
from random import randint,choice,sample,random def rand_str(l=6,t=0): s = '' if t == 0: #纯数字 for i in range(6): # s = s+chr(randint(ord('0'),ord('9'))) s = s+str(randint(0, 9)) elif t == 1: #纯字母 base_str= 'abcdefghjklmnopqrstuvwxyz' # s=''.join(sample(base_str,l)) s = ''.join(choice(base_str)for i in range(l)) else: #数字字母混合 s =.join(choice('0123456789abcdefghjklmnopqrstuvwxyz')for i in range(l)) # s = sample(s,l) return s print(rand_str(l=6,t=2))
-
字符串转换,如:‘IloveYOUmoreTHANiCANsay’ => ‘I love you more than i can say’
-
s = 'IloveYOUmoreTHANiCANsay' def sep_word(s): # ret = s[0].upper() # for i in range(1,len(s)): # if s[i].isupper() ==s[i-1].islower(): # ret = ret+' ' # ret = ret+s[i].lower() # return ret # ret = s[0] # for i in range(1, len(s)): # if s[i].isupper() == s[i - 1].islower(): # ret = ret + ' ' # ret = ret + s[i] # return ret.capitalize() ret='' for i in range(len(s)-1): ret +=s[i] if s[i].isupper() == s[i+1].islower(): ret +=' ' ret +=s[-1] return ret.capitalize() print(sep_word(s))
-
将列表元素完成特定的移动操作,参数:列表、移动位数(正数表示右移,负数表示左移)
- 如:[1, 2, 3, 4, 5]、移动2,结果:[4, 5, 1, 2, 3]
-
lt = [1,2,3,4,5,6] def shift(lt,step): step %= len(lt) # for i in range(step): # #弹出最后一个元素 # last=lt.pop() # #插入到开头 # lt.insert(0,last) #提取左半部分 left = lt[:-step] #提取右半部分 right = lt[-step:] #清空列表 lt.clear() #将右半部分添加到列表 lt.extend(right) #将左半部分添加到列表 lt.extend(left) shift(lt,2) print(lt)
-
使用递归,完成以下功能:传入n,返回:1! + 2! + 3! + … + (n-1)! + n!
-
def jh(n): if n==1: return 1 elif n == 2: return 3 return jh(n-1)+n*(jh(n-1)-jh(n-2)) print(jh(1)) print(jh(2)) print(jh(3))
-
歌词解析:解析成一个时间戳一句歌词的形式,封装函数(根据时间返回歌词)
[ti:蓝莲花]
[ar:许巍]
[al:留声十年绝版青春北京演唱会]
[00:-01.70]蓝莲花
[00:-00.70]演唱:许巍
[00:00.00]
[00:00.70]没有什么能够阻挡
[00:06.01]你对自由的向往
[00:11.43]天马行空的生涯
[00:16.99]你的心了无牵挂
[00:21.20]
[02:11.55][01:50.60][00:22.63]穿过幽暗的岁月
[02:16.93][01:55.60][00:27.81]也曾感到彷徨
[02:22.21][02:01.09][00:33.13]当你低头的瞬间
[02:27.62][02:06.33][00:38.32]才发觉脚下的路
[02:31.64][02:10.23][00:42.37]
[02:32.97][00:43.79]心中那自由的世界
[02:38.23][00:49.50]如此的清澈高远
[02:43.30][00:54.31]盛开着永不凋零
[02:47.70][00:58.50]蓝莲花
[02:53.95][03:00.06][01:05.41]s = '''[ti:蓝莲花] [ar:许巍] [al:留声十年绝版青春北京演唱会] [00:-01.70]蓝莲花 [00:-00.70]演唱:许巍 [00:00.00] [00:00.70]没有什么能够阻挡 [00:06.01]你对自由的向往 [00:11.43]天马行空的生涯 [00:16.99]你的心了无牵挂 [00:21.20] [02:11.55][01:50.60][00:22.63]穿过幽暗的岁月 [02:16.93][01:55.60][00:27.81]也曾感到彷徨 [02:22.21][02:01.09][00:33.13]当你低头的瞬间 [02:27.62][02:06.33][00:38.32]才发觉脚下的路 [02:31.64][02:10.23][00:42.37] [02:32.97][00:43.79]心中那自由的世界 [02:38.23][00:49.50]如此的清澈高远 [02:43.30][00:54.31]盛开着永不凋零 [02:47.70][00:58.50]蓝莲花 [02:53.95][03:00.06][01:05.41]''' # 定义一个字典,保存歌曲信息 song_dict = {} # 定义一个字典,保存歌词信息 lrc_dict = {} # 按照换行进行切割 str_list = s.splitlines() for string in str_list: # 判断是否是歌词信息 if string[1].isdecimal(): # [02:11.55][01:50.60][00:22.63]穿过幽暗的岁月 # 按照']'进行切割 lrc_list = string.split(']') # 提取歌词信息 lrc_info = lrc_list[-1] # 提取时间信息 time_info = lrc_list[:-1] # 遍历处理每个时间戳 for time_str in time_info: # [02:11.55,去掉'[' time_str = time_str[1:] # 02:01.09,按照':'进行切割 time_info_list = time_str.split(':') # 提取分钟 time_min = float(time_info_list[0]) # 提取秒数 time_sec = float(time_info_list[1]) # 合并时间 time = time_min * 60 + time_sec # 保存歌词及对应的时间戳 lrc_dict[time] = lrc_info else: # [ti:蓝莲花] # 去掉两边的[] string = string[1:-1] # 按照':'进行切割 song_list = string.split(':') # 保存到字典中 if song_list[0] == 'ti': song_dict['标题'] = song_list[1] elif song_list[0] == 'ar': song_dict['艺术家'] = song_list[1] elif song_list[0] == 'al': song_dict['专辑'] = song_list[1] 提取所有的时间戳 time_list = list(lrc_dict) 对时间戳进行降序排序 time_list.sort(reverse=True) 根据时间戳返回对应歌词 def get_lrc_by_time(t): for i in time_list: if i <= t: return lrc_dict[i] return lrc_dict[time_list[-1]] 下面的代码都是测试代码 import time import os t = 0 last_lrc = None while True: lrc = get_lrc_by_time(t) if last_lrc != lrc: # 清屏 os.system('cls') for s in song_dict: print(s, song_dict[s]) print() last_lrc = lrc print(lrc) time.sleep(0.5) t += 0.5
文件操作
目录管理(os)
-
示例:
import os# 执行命令 # 清屏 # os.system('cls') # 调出计算器 # os.system('calc') # 操作系统类型,nt表示windows,posix表示类unix # print(os.name) # 获取环境变量 # print(os.environ['path']) # print(os.environ.get('pathxx', 'default')) # 与上式等价 # print(os.getenv('pathxx', 'default')) print(os.getenv('xxx', 'default'))
-
查看当前工作目录
print(os.getcwd()) -
创建目录
# 新建目录
# os.mkdir(‘test’)
# 不能创建中间目录,否则会失败
# os.mkdir(‘a/b/c’)
# 可以创建中间目录
os.makedirs(‘a/b/c’) -
删除目录
# 删除目录
# os.rmdir(‘test’)
# 只能删除空目录,不能删除有内容的目录
os.rmdir(‘a’) -
重命名
os.rename(‘test2’, ‘test’) -
查看文件信息
stat = os.stat(‘01-os.py’)
print(stat.st_size) -
查看指定目录内容
print(os.listdir(os.getcwd())) -
path使用
import os# 目录拼接 # print(os.path.join('abc/def', 'hello.py')) # 提取目录 # print(os.path.dirname('abc/def/hello.py')) # print(os.path.dirname('C:/Apache24/htdocs/code/day08')) # 提取文件 # print(os.path.basename('abc/def/hello.py')) # 切割路径与文件名 # dir, file = os.path.split("abc/def/hello.py") # print(dir, file) # 切割路径名与后缀 # print(os.path.splitext('abc/def/hello.py')) # print(os.path.splitext('hello.py')) # 判断文件是否存在,可以是目录 # print(os.path.exists('a')) # 判断是否是目录 # print(os.path.isdir('01-os.py')) # print(os.path.isdir('a')) # 判断是否是文件 # print(os.path.isfile('01-os.py')) # print(os.path.isfile('a')) # 获取文件大小,只适用于文件,不能是目录 print(os.path.getsize('01-os.py')) print(os.path.getsize('a'))
文件管理
-
打开文件
-
示例
fp = open(‘00-test.txt’) -
参数
file:操作的文件名
mode:打开模式
encoding:编码方式,通常不指定,系统会自动识别 -
打开方式
r:只读方式,文件不存在会报错
w:只写方式,文件不存在则创建,存在则清空
a:追加方式,文件不存在则创建,存在则打开(不会清空内容),只能向末尾添加内容
r+:在r的基础上添加写的权限
w+:在w的基础上添加读的权限
a+:在a的基础上添加读的权限在上面打开方式上添加一个字符’b’,表示已二进制方式进行操作:rb、wb、ab、rb+、wb+、ab+
说明:没有添加b的方式的打开,默认都是以字符串形式操作,带b的方式都是以bytes形式操作的 -
编码方式
ASCII:美国信息交换标准代码(128)
ansi:扩展的ASCII(256)
gb2312:中国的ansi
gbk:扩充的gb2312unicode:万国码,能够将所有国家的所有字符进行统一编码
utf-8:可变长度的unicode实现方案,并且对中文支持良好
-
-
关闭文件
fp.close() -
文件读写
# 判断是否可读
# print(fp.readable())
# 判断是否可写
# print(fp.writable())# 读取指定长度内容,默认读取全部 # content = fp.read(5) # print(content) # 写操作 # fp.write('123')
-
操作位置
# 获取文件操作位置
print(fp.tell())# 设置操作位置 # 参数1:偏移量 # 参数2:参考位置,0表示开头,1表示当前位置,2表示文件末尾 # 当以bytes方式操作时没有问题,但是以str方式操作时只能设置从开头的偏移 fp.seek(-3, 2)
bytes类型
-
示例:
# s = b’hello’
# print(s, type(s))# 编码:str => bytes s = 'hello'.encode('utf-8') print(s) # 解码:bytes => str b = s.decode('utf-8') print(b)
环境变量
- 设置:set 名称=值
- 获取:set 名称
- 代码:
# print(os.environ[‘path’])
# print(os.environ.get(‘pathxx’, ‘default’))
# 与上式等价
# print(os.getenv(‘pathxx’, ‘default’))
print(os.getenv(‘xxx’, ‘default’))
文件目录
- 目录分隔符
- Windows:’/’、’'都行
- 类unix:’/’
- 建议:统一使用’/’
- 目录名词
- 相对目录:有参考的目录叫相对目录
- . 表示当前目录
- … 表示上一级目录
- 绝对目录:没有参考的目录叫绝对目录
- windows:以盘符开头的目录
- 类unix:以’/'开头的目录
- 相对目录:有参考的目录叫相对目录
练习: 见第二周第五天代码
- 实现文件的拷贝功能,需要考虑大文件的操作。
- 删除一个目录,需要进行递归操作
- 拷贝一个目录
- 移动一个目录
- 整理目录
- 一个目录下有各种文件,也有文件夹
- 将所有的文件夹都放在DIRS中
- 将所有无后缀的文件都放在OTHERS中
- 将有后缀的文件放在后缀大写的目录下
- 示例:
整理前:
test/
dir1/
dir2/
dir3/
1.txt
2.txt
3.py
4.py
123
456
整理后:
test/
DIRS/
dir1/
dir2/
dir3/
TXT/
1.txt
2.txt
PY/
3.py
4.py
OTHERS/
123
456
常用模块
time
- sleep:睡眠
print(‘开始计时’)
# 睡眠指定的秒数,可以是小数
time.sleep(3)
print(‘时间到’) - time:获取时间戳
# 获取时间戳(从1970-01-01 00:00:00到此刻的秒数)
t = time.time()
# print(t) - localtime:将时间戳转换time.struct_time对象
# 将一个时间戳转换为日期时间对象(time.struct_time)
# 当不传时间戳时,默认转换当前时间,包含时区
local_time = time.localtime()
# 可以通过属性访问成员
print(local_time.tm_hour)
# 也可以通过下标进行访问
print(local_time[0]) - gmtime:将时间戳转换time.struct_time对象
# 将时间戳转换为日期时间对象(time.struct_time),不带时区
gt = time.gmtime()
print(gt) - mktime:根据年月日等信息创建时间戳
# 根据年月日等信息,创建一个时间戳
t = time.mktime((2018, 11, 26, 11, 1, 50, 0, 330, 0))
print(t) - timezone:
# 0时区与当前系统时区相差的秒数
print(time.timezone) - strftime:对time.struct_time对象进行格式化
# 将一个时间转换为特定格式显示,默认转换当前时间
# print(time.asctime())
‘’’
格式化处理
%Y:年(4位)
%y:年(2位)
%m:月
%d:日
%D:月/日/年
%H:时
%M:分
%S:秒
%w:星期
%W:本周是今年的第几周
‘’’
print(time.strftime(’%D’, local_time))
print(time.strftime(’%Y-%m-%d %H:%M:%S’, local_time))
calendar
-
示例:
import calendar# 返回一年的日历 c = calendar.calendar(2018, w=3, l=2, c=2, m=2) # print(c) # 返回某一年的某一月的日历 m = calendar.month(2018, 11) # print(m) # 判断闰年 print(calendar.isleap(2008)) # 两个年份之间的闰年数量,区间:[起始,结束) print(calendar.leapdays(2000, 2008)) print(calendar.leapdays(2000, 2009))
datetime
-
date
from datetime import date
import time# 创建对象 d1 = date(2018, 11, 26) # print(d1, type(d1)) d2 = date.today() # print(d2) d3 = date.fromtimestamp(time.time()) # print(d3) # 标准格式显示 print(d1.isoformat()) # 日历显示:(年,第几周,星期) print(d2.isocalendar()) # 获取星期,标准格式1~7 print(d3.isoweekday()) # 获取星期,格式0~6 print(d3.weekday()) # 格式化显示 print(d3.strftime('%Y/%m/%d')) # 提取单独的年月日 print(d3.year, d3.month, d3.day) # 转换为time.struct_time对象 print(d3.timetuple())
-
time
from datetime import time# 创建对象 t = time(1, 2, 3) print(t, type(t)) print(str(t)) # 单独获取时、分、秒 print(t.hour, t.minute, t.second) # 格式化显示 print(t.strftime('%H::%M::%S'))
-
datetime
from datetime import datetime
import time# 创建对象 dt = datetime(2018, 11, 26, 14, 53, 52) # 当前时间,带时区 dt2 = datetime.now() # 当前时间,不带时区 dt3 = datetime.utcnow() # 转换时间戳 dt4 = datetime.fromtimestamp(time.time()) # print(dt4) # 提取日期 d = dt.date() print(d, type(d)) # 提取时间 t = dt.time() print(t, type(t)) # 转换成时间戳 print(dt.timestamp()) # 格式化显示 print(dt.strftime('%Y/%m/%d %H/%M/%S'))
-
timedelta
from datetime import timedelta, datetimetd = timedelta(seconds=3600) td2 = timedelta(days=2) dt1 = datetime(2018, 11, 26, 15, 6, 10) dt2 = datetime(2018, 11, 25, 14, 6, 10) td3 = dt1 - dt2 # print(td3, type(td3)) dt3 = dt1 + td2 # print(dt3, type(dt3)) # 提取天数 print(td3.days) # 提取秒数(天以外的) print(td3.seconds) # 总共的秒数 print(td3.total_seconds())
模块使用
-
定义:模块就是一个工具包,里面可以包含函数、类库等,使用时导入即可。
-
分类:
- 标准库:os、sys、random等
- 自定义:自己根据需要书写的模块
- 第三方:就是别人写好的,可以直接使用,但是需要提前安装。
-
语法:
# 导入模块
import time# 导入模块中指定的内容 from time import sleep # 带入模块,并且起别名 import random as rdm # 导入模块中的指定内容,并且起别名 from random import randint as rint
-
as
- 使用as可以起别名,让导入的内容变得简单易记
- 使用as可以解决多个模块下标识符冲突问题
-
模糊导入
# 模糊导入,导入该模块中__all__列表指定的内容
# 不建议使用:
# 1.不知道导入了什么内容
# 2.多个模块中有同名的内容无法处理
from random import * -
自定义模块
- 新建一个文件(文件名不要与其他模块同名)
- 新建的文件名(除了后缀)就是模块名
- 导入的方式与其他模块一样
- 模块名(文件名)就是命名空间,同一模块下的标识符不能同名,不同的模块下的标识符可以同名
- 多个模块有相同标识符,可以直接导入模块,也可以使用as起别名
-
测试模块
# 直接执行此模块,值为__main__
# 被其他模块导入,值为模块名
# print(‘模块名:’, name)# 模块测试内容可以这么写 # 当直接运行此模块时会执行,当被其他模块导入时不会执行 if __name__ == '__main__': print('模块测试内容')
-
包的使用
- 定义:具有__init__.py文件的多个模块的文件夹
- 说明:
- init.py是一个文件作为包的标志,即使该文件内容为空
- 包文件可以减少导入的复杂度
-
第三方模块安装
-
工具:pip
-
使用:
pip -h/–help # 查看帮助
pip install 包名==版本 # 安装指定的包(可以指定版本)
pip install -r requirements.txt # 读取文件内容,根据内容进行安装
pip uninstall 包名 # 卸载指定的包
pip list # 查看已安装的包
pip show 包名 # 查看指定的包
pip freeze # 查看当前系统安装的包及版本
pip freeze > requirements.txt # 将系统环境冷冻 -
说明:
- 安装出错的原因通常是没有连网或安装目录没有写的权限
- 软件安装目录:C:\Program Files\Python36\Lib\site-packages
- 若安装一直失败,可以先从https://www.pypi下载下来然后再安装,如:pip install xxx.whl
- 也可以使用pycharm进行软件包的安装
- 若觉得网速不好,可以改为国内的软件源
-
面向对象
面向对象
- 与面向过程对比
- 面向过程:数学逻辑的映射,学会做个好员工
- 面向对象:生活逻辑的映射,学会做个好领导
- 生活实例
- 类: 人 手机 电脑
- 对象: 小明、老王 你的手机、我的手机 我的电脑、你的电脑
- 官方定义
- 类:具有相同特征(属性和行为)事物的抽象
- 对象:某个类的具象
- 编程语言
- 类:是一种自定义的数据类型
- 对象:某个类类型的变量
基础语法
-
类的定义
class 类名:
pass -
使用说明:
-
定义类的关键字是class
-
类名:原则上符合标识符命名规范即可,但是通常都采用大驼峰风格命名,如:UserName
-
类名后不要忘记’:’
-
类的内容要进行整体缩进
-
属性可以通过变量体现,行为通过函数体现
-
成员访问:
- 属性:对象.属性名
- 方法:对象.方法名()
- 创建对象:类名加小括号
-
示例:
定义类
class Person:
# 行为通过函数体现# 吃饭 def eat(self): print('毛氏红烧肉,听说很好吃!') # 睡觉 def sleep(self): print('喜欢睡觉也是生活态度!')
创建对象
p = Person()
print§
属性可以动态添加
p.name = ‘ergou’
p.age = 22
print(p.name, p.age)调用成员方法
p.eat()
p.sleep()
-
-
self使用
class Person:
def run(self):
# self表示当前对象,就是调用该方法的对象
print(’{}每天以2m/s的速度奔跑5km’.format(self.name))def introduce(self): # 访问成员属性 print('我叫{},今年18岁'.format(self.name)) # 调用成员方法 # self的名字可以修改,但是通常都不改,调用方法时该参数不传 self.run() lulu = Person() lulu.name = '露露' # lulu.run() lulu.introduce() yanbo = Person() yanbo.name = '彦博' # yanbo.run() yanbo.introduce()
-
__str__方法
class Person:
# 打印对象时默认打印:类名+地址
# 重写该方法,打印对象时会打印该方法的返回值
# 该方法必须返回一个字符串
# 使用str方法强制类型转换时也会调用该方法
def str(self):
return ‘我是{},今年{}岁’.format(self.name, self.age)p = Person() p.name = '勒布朗.詹姆斯' p.age = 34 print(p) s = str(p) print(s)
-
__init__方法
class Cat:
def str(self):
return ‘name:{},age:{},color:{}’.format(self.name, self.age, self.color)# 构造方法:创建对象后会自动调用,可以进行初始化设置 def __init__(self, name, age, color): # print('__init__') self.name = name self.age = age self.color = color # 这种方式比较繁琐 # jiafei = Cat() # jiafei.name = '加菲' # jiafei.age = 2 # jiafei.color = '橘黄色' # print(jiafei) jiafei = Cat('加菲', 2, '橘黄色') print(jiafei)
-
__del__方法
class Pig:
# 析构方法:当对象释放时,系统会自动调用
# 该方法一般做资源释放操作,如:断开数据库连接、文件关闭
def del(self):
print(‘大师兄,我不行了’)bajie = Pig() del bajie print('八戒,一路走好!')
-
思考:小明手里有两张牌,左手♥K,右手♠A,小明交换两手的牌后,手里分别是什么?
-
先找到对象:♥K、♠A、左手、右手、小明
-
根据对象抽象类:人、手、牌
-
设计相关的类,需要根据功能反复完善
-
# 牌的类 class Poker: def __init__(self,color,number): self.color = color self.number = number def __str__(self): return '{}{}'.format(self.color,self.number)
#创建两张牌
p1 = Poker(‘♥’,‘K’)
p2 = Poker(‘♠’,‘A’)#手的类
class Hand:
def init(self,poker=None):
self.poker = pokerdef hold_poker(self,poker): self.poker = poker
#创建两只手
left_hand = Hand(p1)
right_hand = Hand(p2)#人的类
class Person:
def init(self,name,left_hand,right_hand):
self.name = name
self.left_hand = left_hand
self.right_hand = right_hand#展示牌 def show(self): print('{}张开手'.format(self.name),end=' ') print('左手:{}'.format(self.left_hand.poker),end=' ') print('右手:{}'.format(self.right_hand.poker)) #交换手中的牌 def swap(self): self.left_hand.poker,self.right_hand.poker =self.right_hand.poker,self.left_hand.poker print('{}交换手中的牌'.format(self.name))
#创建小明对象
xiaoming= Person(‘小明’,left_hand,right_hand)#展示手中的牌
xiaoming.show()#交换周中的牌
xiaoming.swap()#展示手中的牌
xiaoming.show()
-
常用内置函数
-
内置函数:在类中,特定的时刻会自动触发的函数
-
init、del、str
-
setattr、getattr、delattr
class Person:
def init(self, name):
self.name = name
# print(‘初始化对象’)# 当设置属性时会自动调用 def __setattr__(self, key, value): # print(key, value) self.__dict__[key] = value # 当获取不存在的属性时会自动触发 def __getattr__(self, item): if item == 'age': return 18 else: return '你猜' # 销毁对象的指定属性时会自动触发 def __delattr__(self, item): print(item, '属性即将销毁') xiaoming = Person('小明') # xiaoming.name = '小明' print(xiaoming.age) print(xiaoming.height) print(xiaoming.__dict__) del xiaoming.name print('over')
-
setitem、getitem、delitem
class Person:
# 将对象当做字典操作,添加或设置属性时自动触发
def setitem(self, key, value):
# print(key, value)
self.dict[key] = value# 将对象当做字典操作,根据键获取值时会自动触发 def __getitem__(self, item): # print(item) return self.__dict__.get(item) # 将对象当做字典操作,根据键销毁属性时会自动触发 def __delitem__(self, key): print(key, '属性即将销毁') del self.__dict__[key] xiaoming = Person() # xiaoming.name = '小明' # print(xiaoming.name) xiaoming['name'] = '小明' print(xiaoming['name']) del xiaoming['name'] print(xiaoming['name'])
-
call
class Person:
# 将对象当做函数调用,该方法会自动触发
def call(self, *args, **kwargs):
# print(‘call’, args)
return sum(args)p = Person() # 将对象当做函数调用,必须重写类的call方法 ret = p(1, 2, 3) print(ret) def test(): pass # 判断一个对象是否可以调用 print(callable(p)) print(callable(test)) # 判断一个对象是否是函数 from inspect import isfunction print(isfunction(p)) print(isfunction(test)) # 判断对象是否拥有指定属性,若对象可以调用,那么一定拥有__call__属性 print(hasattr(p, '__call__')) print(hasattr(test, '__call__'))
练习
-
设计学生和班级类
- 学生:姓名、年龄、成绩、学号
- 班级:班级名、所有学生
- 功能:实现向班级内添加学生、删除学生、查看学习信息、按照指定方式排序
-
#学生类 class Student: def __init__(self,name,num,age,score): self.name = name self.num = num self.age = age self.score = score def __str__(self): return '姓名:{} 学号:{} 年龄:{} 成绩:{} '.format(self.name,self.num,self.age,self.score) #班级类 class Class: def __init__(self,name): self.name = name #用于保存学生信息列表 self.stu_list = [] # 用于保存学生信息 便于快速查找 self.stu_dict = {} #添加学生 def add_stu(self,stu): self.stu_list.append(stu) self.stu_dict[stu.num] = stu #查看学生信息 def show(self): for s in self.stu_list: print(s) #删除学生 def del_stu(self,num): #从字典中删除 s = self.stu_dict.pop(num) #从列表中删除 self.stu_list.remove(s) #查找学生 def get_stu(self,num): return self.stu_dict.get(num) #学生排序 def sort_stu(self,key=None,reverse=False): self.stu_list.sort(key=key,reverse=reverse) #创建班级对象 c = Class('ZZ-PY1807') from random import randint for i in range(10): name = 'stu'+str(i) num = 100+i age = randint(20,30) score = randint(0,100) #创建学生对象 stu = Student(name,num,age,score) #添加到班级 c.add_stu(stu) print(c.get_stu(101)) # c.sort_stu(key=lambda s:s.score,reverse=True) # c.show()
-
将歌词解析封装成类,要求:通过一个根据时间戳返回歌词的方法
-
提示:歌词类、管理类
-
[ti:蓝莲花] [ar:许巍] [al:留声十年绝版青春北京演唱会] [00:-01.70]蓝莲花 [00:-00.70]演唱:许巍 [00:00.00] [00:00.70]没有什么能够阻挡 [00:06.01]你对自由的向往 [00:11.43]天马行空的生涯 [00:16.99]你的心了无牵挂 [00:21.20] [02:11.55][01:50.60][00:22.63]穿过幽暗的岁月 [02:16.93][01:55.60][00:27.81]也曾感到彷徨 [02:22.21][02:01.09][00:33.13]当你低头的瞬间 [02:27.62][02:06.33][00:38.32]才发觉脚下的路 [02:31.64][02:10.23][00:42.37] [02:32.97][00:43.79]心中那自由的世界 [02:38.23][00:49.50]如此的清澈高远 [02:43.30][00:54.31]盛开着永不凋零 [02:47.70][00:58.50]蓝莲花 [02:53.95][03:00.06][01:05.41]
import os
-
歌词类
class Lrc:
def __init__(self, sec, lrc):
self.sec = sec
self.lrc = lrc
def __str__(self):
return '{}:{}'.format(self.sec, self.lrc)
管理类
class LrcManager:
def __init__(self, lrc_file):
# 保存歌词信息
self.lrc_dict = {}
# 保存歌曲信息
self.song_dict = {}
# 时间信息列表
self.time_list = []
# 保存歌词文件
self.lrc_file = lrc_file
# 调用解析函数
self.jiexi()
def jiexi(self):
# 判断传递是否是歌词文件
if os.path.isfile(self.lrc_file):
fp = open(self.lrc_file, 'rb')
# 读取所有的内容
self.lrc_file = fp.read()
self.lrc_file = self.lrc_file.decode('utf-8')
# 按照换行进行切割
lrc_list = self.lrc_file.splitlines()
# 。。。
# 根据时间戳返回对应歌词
def get_lrc(self, sec):
for t in self.time_list:
if t < sec:
return self.lrc_dict[t]
return self.lrc_dict[self.time_list[-1]]
# 面向对象
### 面向对象三大特点
- 封装:既是对数据结构的封装,又是处理数据的方法的封装。
- 继承:强调的是父子类的关系
- 多态:不同对象调用相同的方法,有不同的响应。
### 类的继承
- 相关概念
- 继承:父类的属性和方法,子类可以直接拥有,称为继承。
- 派生:子类在父类的基础上衍生出新的特征(属性或行为),称为派生。
- 总结:其实他们是一回事,知识描述问题的角度不同(继承侧重相同点,派生侧重不同点)
- 继承语法
```python
# class Animal:
# 当没有写父类时,默认继承自object
class Animal(object):
def __init__(self, name):
self.name = name
def run(self):
print('小动物喜欢一天到晚跑个不停')
# 定义一个子类,继承自Animal
class Dog(Animal):
pass
d = Dog('旺财')
# 可以直接拥有父类的属性
print(d.name)
# 也拥有父类的行为
d.run()
-
派生示例
class Animal:
def run(self):
print(‘一天到晚跑个不停’)class Cat(Animal): def eat(self): print('猫喜欢吃鱼') c = Cat() c.run() # 添加的属性 c.name = '加菲' print(c.name) # 衍生的方法 c.eat()
-
方法重写
class Animal:
def run(self):
print(‘小动物喜欢到处跑’)def eat(self): print('小动物喜欢吃东西') class Cat(Animal): # 父类方法完全不合适,覆盖重写 def run(self): print('猫喜欢走猫步') # 父类的方法不够完善,需要添加完善 def eat(self): # 保留父类方法的内容 # Animal.eat(self) # 不建议使用 # super(Cat, self).eat() super().eat() # 推荐使用 # 添加完善的内容 print('猫喜欢吃鱼') c = Cat() c.eat() c.run()
-
多继承:一个类可以有多个父类
class A:
def test(self):
print(‘in class A func test…’)class B: def test(self): print('in class B func test...') def eat(self): print('in class B func eat ...') class C(A, B): def eat(self): # 默认的方式找父类,跟不重写方法时的顺序是一样的, # 按照书写的先后顺序,默认是写在前面的类的方法 # super().eat() # 明确指定调用哪个父类的方法 B.eat(self) c = C() c.test() c.eat()
-
权限管理
class Person:
def init(self, name, age):
self.name = name
# 定义私有属性
self.__age = agedef test(self): # 私有属性和方法可以在类的内部使用 print(self.__age) self.__hello() # 定义私有方法 def __hello(self): print('for test') class Man(Person): def show(self): # 私有属性和方法在子类也不可以使用 print(self.__age) p = Person('老王', 38) print(p.name) # 属性前添加连个下划线,类的外部不能使用 # print(p.__age) # 默认在添加两个下划线的属性名前添加了'_类名' # print(p.dict) # 强烈建议不要这样使用 # print(p._Person__age) p.test() # p.__hello() m = Man('小明', 18) # m.show()
-
类属性
class Person:
# 类属性,属于整个类
# nation = ‘中国’# 限制对象可以使用的属性,可以提高效率,节约存储空间 __slots__ = ('name', 'age', 'nation') def __init__(self, name): # 成员属性,属于某个对象 self.name = name # 成员属性,当不存在会会试着找一下类属性 # self.nation = 'xxx' def test(self): pass # 通过类名访问类属性 # print(Person.nation) p = Person('王大花') # 可以通过对象访问类属性,但是不建议 print(p.name) # print(p.nation) p.age = 20 # p.height = 180 # 特殊的类属性 # 类名字符串 print(Person.__name__) # 父类组成的元组 print(Person.__bases__) # 类相关的信息 print(Person.__dict__) print(Person.__slots__)
-
类方法
-
说明
- 提通过类名进行调用
- 定义时需要使用装饰器classmethod
-
作用:
- 可以创建对象或者简洁的创建对象
- 可以对外提供简单易用的接口
-
示例1:
class Person:
# 成员方法,通过对象进行调用
def eat(self):
print(‘红烧鸡腿我喜欢吃’)# 类方法,通过类名进行调用 @classmethod def test(cls): # cls表示当前类 print(cls, '类方法') # 创建对象 @classmethod def create(cls): obj = cls() obj.age = 1 return obj
p = Person()
p.eat()
Person.test()创建或者简洁的创建对象
p2 = Person.create()
print(type(p2)) -
示例2:
class Number:
def init(self, num1, num2):
self.num1 = num1
self.num2 = num2def add(self): return self.num1 + self.num2 def sub(self): return self.num1 - self.num2 def mul(self): return self.num1 * self.num2 def div(self): if self.num2 == 0: return None return self.num1 / self.num2 # 对外提供简单易用的接口 @classmethod def pingfanghe(cls, num1, num2): n1 = cls(num1, num1) n12 = n1.mul() n2 = cls(num2, num2) n22 = n2.mul() n3 = cls(n12, n22) return n3.add()
计算3^2 + 4^2
n1 = Number(3, 3)
n12 = n1.mul()
n2 = Number(4, 4)
n22 = n2.mul()
n3 = Number(n12, n22)
ret = n3.add()
print(ret)
print(Number.pingfanghe(3, 4))
-
-
静态方法
-
说明:
- 通过装饰器staticmethod修饰
- 通过类名进行调用
-
示例:
class Person:
# 静态方法:没有cls参数
@staticmethod
def test():
print(‘static method test …’)# 静态方法:可以创建对象 @staticmethod def create(): p = Person() p.age = 1 return p Person.test() p = Person.create() print(type(p))
-
总结:
- 凡是静态方法能够解决的问题类方法都能解决
- 若方法中没有涉及类名的操作,可以使用静态方法代替类方法
-
多态特性
-
定义:不同的对象,调用相同的方法,会有不同的响应
-
示例:
class Animal:
def run(self):
print(‘小动物走道都不一样’)class Cat(Animal): def run(self): print('猫都的是猫步') class Dog(Animal): def run(self): print('狗一般都走S型') def func(obj): obj.run() func(Cat()) func(Dog())
属性函数
-
说明:可以将成员方法当做属性一样访问
-
作用:获取时以及设置指定属性时都可以进行人为干预,可以保护特定属性
-
示例:
class User:
def init(self, username, password):
self.username = username
self.__password = password# 可以将方法像访问属性一样访问 @property def test(self): return 'hello' # 保护指定的属性 @property def password(self): print('大哥,有人想偷看密码') return '哈哈,让你偷看,没门' # 在设置对应属性时会自动调用 @password.setter def password(self, password): print('密码设置', password) # 人为干预密码的设置过程,如:加密存储密码 self.__password = 'xxx' + password + 'yyy' u = User('大狗', '123456') # u.test() # print(u.test) print(u.password) u.password = '654321' print(u.__dict__)
虚拟环境
- 为什么要使用虚拟环境?
- 在同一个环境下,不同软件依赖同一软件包的不同版本,为了进行环境隔离就出现了虚拟环境
- 虚拟环境创建工具:virtualenv
- pip install virtualenv
- 创建虚拟环境
- virtualenv 虚拟环境目录名
- 激活虚拟环境
- 虚拟环境目录\Scripts\activate.bat
- 退出虚拟环境
- 虚拟环境目录\Scripts\deactivate.bat
- 快速复制一个虚拟环境
- 冷藏现有的虚拟环境:pip freeze > requirements.txt
- 创建一个新的虚拟环境:virtualenv venv
- 激活虚拟环境:venv\Scripts\activate.bat
- 安装依赖:pip install -r requirements.txt
- 虚拟环境管理工具:virtualenvwrapper-win
- 安装:pip install virtualenvwrapper-win
- 说明:默认会将虚拟环境保存在C:\Users\用户名\Envs目录下
- 查看虚拟环境:lsvirtualenv
- 创建虚拟环境:mkvirtualenv
- 启动虚拟环境:workon 虚拟环境名
- 退出虚拟环境:deactivate.bat
面向对象
抽象基类(了解)
-
说明:
- 抽象基类就是为了统一接口而存在的
- 抽象类不能进行实例化(创建对象)
- 继承自抽象类的子类必须实现抽象类中的抽象方法
-
示例:
from abc import ABC, abstractmethod# 抽象基类 class Animal(ABC): # 定义抽象方法:规定接口 @abstractmethod def run(self): pass # 抽象基类无法实例化 # a = Animal() class Cat(Animal): # 子类中必须实现抽象基类的抽象方法,才能实例化 def run(self): print('猫喜欢走猫步') c = Cat()
特殊函数
-
示例1
d = {‘name’: ‘xiaoming’, ‘age’: 20}# 返回对象的字符串表示形式 r = repr(d) print(r, type(r)) # 执行有效的python代码字符串 d2 = eval(r) print(d2, type(d2)) a = 10 b = 20 c = eval('a + b') print(c)
-
示例2:
class Person:
def init(self, name, age):
self.name = name
self.age = age# print打印对象,str方法转换时都会触发 def __str__(self): print('__str__') return '姓名:{} 年龄:{}'.format(self.name, self.age) # 返回对象的字符串表示形式,使用repr函数处理时会自动触发 def __repr__(self): return "Person('{}', {})".format(self.name, self.age) p = Person('王大花', 18) # print(p) # s = str(p) r = repr(p) print(r) p2 = eval(r) print(p2, type(p2))
内置方法
-
构造和析构
init、del__ -
干预属性操作
setattr、getattr、delattr -
支持字典操作
setitem、getitem、delitem -
对象支持函数调用
call -
打印输出或str转换
str -
对象的字符串表示,调用repr方法时触发
repr
运算符重载
-
算术运算符
-
示例:
class Number:
def init(self, num):
self.num = num# 对象出现在'+'的左边时会自动触发 def __add__(self, other): print('__add__') return self.num + other # 对象出现在'+'的右边时会自动触发 def __radd__(self, other): print('__radd__') return self.num + other # +=运算时自动触发,若没有实现会调用__add__ def __iadd__(self, other): print('__iadd__') # 返回新的Number对象 # return Number(self.num + other) # 返回处理后的原始对象 self.num += other return self
n = Number(10)
print(id(n))ret = n + 20
ret = 20 + n
print(ret)
n += 50 # n = n + 50
print(id(n)) -
自行测试
加法:add、radd、iadd
减法:sub、rsub、isub
乘法:mul、rmul、imul
除法:truediv、rtruediv、itruediv
求余:mod、rmod、imod
-
-
关系运算符
class Number:
def init(self, num):
self.num = num# 大于 > def __gt__(self, other): print('__gt__') return self.num > other # 小于 < def __lt__(self, other): print('__lt__') return self.num < other # 等于 ==, 判断是否相等,当不实现__ne__时,!=运算也会触发 def __eq__(self, other): print('__eq__') return self.num == other # 大于等于 >= def __ge__(self, other): print('__ge__') return self.num >= other # 小于等于 <= def __le__(self, other): print('__le__') return self.num <= other # 不等于 != def __ne__(self, other): print('__ne__') return self.num != other n = Number(20) print(n > 10) print(n < 10) print(n == 10) print(n != 10)
内存管理
-
引用计数
-
python中所有的数据都是通过类来实现的,对象的管理是通过引用计数实现的
-
当创建一个对象赋值给一个变量时,引用计数为1,当多一个变量指向该对象时,计数值加1;当少一个变量指向对象时,计数值减1。计数值减到0时会调用__del__方法释放存储空间
-
不可变变量引用计数是没有意义的
-
示例:
import sys# 不可变变量的引用计数没有意义 a = 10 print(sys.getrefcount(a)) lt = [1, 2, 3] lt2 = lt # 本身此时引用计数为1,但是该方法也引用了一次 print(sys.getrefcount(lt)) del lt2 print(sys.getrefcount(lt))
class Person:
def del(self):
print(‘对象即将释放’)p = Person()
print(sys.getrefcount§)
del p
print(‘over’)
-
-
函数传参
-
对不可变变量来说,传递的是值,函数中不可能改变传递的参数
-
对于可变变量及自定义的类创建的对象,传递的是引用,函数中可以操作原对象
-
示例:
def test(a):
a += 1num = 100
对于不可变数据传递的是值
test(num)
print(num)def test2(lt):
lt[0] = 10lt = [1, 2, 3]
test2(lt)
print(lt)
-
-
深浅拷贝
import copylt = [1, 2, [3, 4]] # 赋值会增加一个引用,访问的都是同一数据 lt2 = lt # 浅拷贝:只拷贝对象本身,里面的元素只会增加一个引用 # lt2 = lt.copy() # 专门的拷贝函数,也是浅拷贝,等价于上面的拷贝 lt2 = copy.copy(lt) # 深拷贝:拷贝对象本身,对象中的元素也进行拷贝 # lt2 = copy.deepcopy(lt) lt[0] = 100 lt2 = 30 print(lt) print(lt2) print(id(lt)) print(id(lt2)) # 判断是否是同一对象的多个引用 print(lt is lt2)
数据持久化存储
-
说明:持久化存储方案,普通文件、数据库、序列化
-
示例:
import pickleclass Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return 'name:{} age:{}'.format(self.name, self.age) xiaoming = Person('xiaoming', 20) # print(xiaoming) # 序列化:会将对象转换为bytes # s = pickle.dumps(xiaoming) # print(s) # 反序列化:从bytes中解析出对象 # xm = pickle.loads(s) # print(xm, type(xm)) # 直接保存到文件 # fp = open('data.txt', 'wb') # pickle.dump(xiaoming, fp) # fp.close() # 从文件中读取对象 fp = open('data.txt', 'rb') xm = pickle.load(fp) print(xm, type(xm))
异常处理
相关概念
- 错误:程序运行之前的语法问题,如:关键字出错、缩进不齐、括号不成对等
- 异常:程序运行过程中出现的问题,如:除数为0,对象属性不存在,字典的键不存在,下标越界
异常处理
-
说明:异常处理可以理解为特殊的流程控制语句,可以提高代码的健壮性。
-
语法:
try:
print(‘正常代码’)
a = 3 / 0
print(‘执行结束’)
except Exception as e:
# 捕获异常,可以做出异常处理
print(‘出现异常’, e)print('OVER')
-
多异常处理:
# try:
# # print(a)
# # a = 3/0
# d = {}
# print(d[‘name’])
# except NameError as e:
# print(‘NameError:’, e)
# except ZeroDivisionError as e:
# print(‘ZeroDivisionError:’, e)
# except Exception as e:
# print(‘Othre error:’, e)try: # print(a) # a = 3 / 0 d = [1, 2, 3] print(d[4]) except (NameError, ZeroDivisionError) as e: # 将某些异常放在一起进行统一处理 print('name or zero:', e) except Exception as e: print('其他异常')
-
完整写法
try:
print(‘正常代码’)
print(a)
except Exception as e:
print(‘出现异常’, e)
else:
# 没有异常时会执行
print(‘正常结束’)
finally:
# 无论有无异常都会执行
print(‘最后执行’)print('OVER')
-
手动抛出异常
try:
print(‘正常执行’)
# 根据业务逻辑分析,手动抛出异常
raise Exception(‘手动抛出的异常’)
print(‘执行结束’)
except Exception as e:
print(‘出现异常:’, e)print('OVER')
-
异常嵌套
print(‘我要去上班,什么事也阻止不了我上班的脚步’)
try:
print(‘我准备骑电动车去上班’)
raise Exception(‘不知道那个缺德的家伙把我充电器拔掉了’)
print(‘骑电动车提前到达公司’)
except Exception as e:
print(‘电车异常:’, e)
try:
print(‘我准备坐公交去上班’)
raise Exception(‘等了20分钟没有公交车,果断放弃’)
print(‘乘坐公交准时到达公司’)
except Exception as e:
print(‘公交异常:’, e)
print(‘我准备打车去公司’)
print(‘打车还是快,还是能够提前到达公司’)print('热情饱满的开始一天的工作')
-
自定义异常类
# 自定义异常类
class MyException(Exception):
def init(self, msg):
self.msg = msgdef __str__(self): return 'MyException:' + self.msg # 异常处理函数 def deal(self): print('按照特定的方案处理异常') try: print('正常运行') raise MyException('自定义异常') except MyException as e: print(e) # 特定的处理方案 e.deal() except Exception as e: print('Exception', e) print('OVER')
-
特殊场景
-
当进行文件操作时,无论过程是否出现异常,最后一定要关闭文件
-
使用with语句,保证文件关闭,无论中间是否出现异常
-
示例:
‘’’
fp = open(‘xx.txt’, ‘r’)
content = fp.read(1024)
print(content)…
最后一定要关闭文件
fp.close()
‘’’with open(‘00-text.txt’, ‘r’) as fp:
content = fp.read(1024)
# …
# 结束时不需要考虑文件的关闭问题
# 无论中间是否出现了异常,一定会确保文件关闭
-
邮件与短信
邮件发送
-
简介:
- 邮件服务器:用户名、密码
- 相关协议:
- SMTP:简单邮件传输协议,默认端口是25
- POP3:邮局通讯协议
- IMAP:交互式邮件存取协议
-
用途:网站注册激活、通知、找回密码、营销等
-
库:smtplib
-
示例:
import os
import smtplib
from email.mime.text import MIMEText# 邮件服务器 mail_server = 'smtp.1000phone' # 用户名 mail_username = 'lijie@1000phone' # 密码,通过环境变量获取,可以避免隐私信息的暴露 # 或授权码,QQ邮箱需要使用授权码 mail_password = os.getenv('MAIL_PASSWORD', '123456') # 邮件内容 content = '请点击右边链接已完成激活' # 创建用于发送的邮件消息对象 # 参数1:邮件内容 # 参数2:内容类型,plain表示普通文本,html表示网页 message = MIMEText(content) # 设置主题 message['Subject'] = '账户激活' # 设置发送者 message['From'] = mail_username # 创建用于发送邮件的对象 # SMTP:邮件不加密,端口25 # SMTP_SSL:邮件加密传输,端口465,QQ邮箱必须使用加密 mail = smtplib.SMTP(mail_server) # 身份认证 mail.login(mail_username, mail_password) # 发送给谁 to = '13213692850@163' # 发送邮件 mail.sendmail(mail_username, to, message.as_string()) # 结束 mail.quit()
-
说明:
- 邮箱服务器配置
- 创建邮件消息对象MIMEText
- 创建用于发送邮件的对象smtplib.SMTP
- 使用邮件发送对象发送邮件
-
QQ邮件发送特别提醒:
- 密码不是QQ登录密码,而是授权码,需要开启SMTP服务并设置
- 必须使用加密传输,也就是创建SMTP_SSL对象发送邮件
预备知识
-
http.client:可以发送http请求
import http.client# 创建对象(相当于一个浏览器) connect = http.client.HTTPConnection('www.baidu') # 发送请求 connect.request(method='GET', url='http://www.baidu') # 获取响应 resp = connect.getresponse() # 打印响应的内容 print(resp.read().decode('utf-8'))
-
json和XML
-
说明:使用非常广泛的数据传输格式,现在JSON使用居多
-
JSON使用:
import jsond = {‘name’: ‘xiaoming’, ‘age’: 18}
将字典转换为JSON字符串
s = json.dumps(d)
print(s, type(s))
将JSON字符串转换为字典
d2 = json.loads(s)
print(d2, type(d2))
-
-
urllib.parse
from urllib.parse import urlencode, urlparse, parse_qsd = {'name': 'xiaoming', 'age': 18} # name=xiaoming&age=18 # 将字典数据进行URL编码 print(urlencode(d)) url = 'https://www.baidu/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=python&rsv_pq=df80f3db0000abd0&rsv_t=a542qF5GDdQDk6bhs2c3yr7BGToMf0ge1e2b%2BnpWm0lY4ZV8ICYY1yM48FI&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101' # 解析URL p = urlparse(url) # 提取请求字符串 print(p.query) query_str = 'like=sport&like=music&like=games&name=ergou' # 解析请求字符串:将请求字符串转换为字典 # d2 = parse_qs(p.query) d2 = parse_qs(query_str) print(d2)
短信发送
-
说明:注册登录验证码、通知消息、营销短信、面向接口的开发等。
-
平台:阿里、秒嘀、云之讯、…
-
认识:云之讯(www.ucpaas)
-
示例:
# 账户sid
sid = ‘b5c6fd1d02071a766009475f0478e0ac’# 认证令牌 token = '2426bff7df8ff95f59fcbcdce3362c58' # 应用ID appid = 'fac78e7f7f0647c7a47c4809ff564f5c' # 模板ID templateid = '29735' # 参数 param = 'stu.1000phone,123456,5' # 接收手机号 mobile = '18134411879' # 参数字典 data = { "sid": sid, "token": token, "appid": appid, "templateid": templateid, "param": param, "mobile": mobile, } # 将字典转换为JSON字符串 import json json_data = json.dumps(data) # print(json_data) # 创建'浏览器'对象 import http.client connect = http.client.HTTPConnection('open.ucpaas') # 接口地址 url = 'https://open.ucpaas/ol/sms/sendsms' # 请求头 header = { 'Accept': 'application/json', 'Content-Type': 'application/json;charset=utf-8', } # 发送请求 connect.request(method='POST', url=url, body=json_data, headers=header) # 获取响应 resp = connect.getresponse() # 打印响应内容 print(resp.read().decode('utf-8'))
练习 见第四周第一天代码
-
邮件短信发送都需要封装成函数
-
终端银行系统
- 类:银行卡、用户类、操作类
- 说明:属性和方法自行添加
正则表达式
应用场景
- 特定规律字符串的查找,切割、替换等
- 特定格式(邮箱、手机号、IP、URL等)的校验
- 爬虫项目中,提取特定内容
使用原则
- 只要使用字符串函数能够解决的问题就不要使用正则
- 正则的效率比较低,同时会降低代码的可读性
- 世界上最难理解的三样东西:医生的处方、道士的神符、码农的正则
- 提醒:正则是用来写的,不是用来读的;在不清楚功能的情况下,不要阅读别人的正则
基本使用
- 说明:正则的解析不是我们来做的,需要借助re模块
- 相关函数:
-
match:只从开头进行匹配,匹配到就返回结果对象,没有找到返回None
-
search:从任意位置匹配,功能同上,都是单次匹配(找到就停)
m = re.search(‘abc’, ‘hadajabcadjlae’)if m:
# 返回匹配的内容
print(m.group())
# 返回匹配内容的位置
print(m.span()) -
findall:全部匹配,返回所有匹配到的结果列表,没有找到返回空列表
f = re.findall(‘abcd’, ‘abcasjdlaabcaksjd;abcasdjla’)
print(f) -
compile:创建正则表达式对象,可以让创建正则对象和内容匹配分开操作
可以先生成正则表达式对象,然后再进行匹配
c = repile(‘cba’)
print(type©)
从开头匹配
m = c.match(‘cbasdhaj;acbaalsdk’)
从任意位置匹配
m = c.search(‘casdhaj;acbaalsdk’)
if m:
print(m.group())匹配所有
f = c.findall(‘ahkjdcbasdkjalcbasakldjacba’)
print(f)此方式可以分开操作,比较灵活
-
正则语法
-
单个字符
普通字符:简单理解就是一对一的完全匹配
[]:中间的任意一个字符
[abc]:abc的任意一个字符
[0-9]:任意的数字字符
[a-zA-Z]:任意的字母
[^0-9]:非数字字符
. :除’\n’以外的任意字符
\d:数字字符,等价于[0-9]
\D:非数字字符,等价于[^0-9]
\w:匹配字(数字、字母、下划线)
\W:匹配非字(\w相反的内容)
\s:空白字符(\n、\r、\t、空格)
\S:非空白字符(\s相反的内容)
\b:词边界(开头、结尾、空格、标点)
\B:非词边界(\b相反的内容) -
次数限定:修饰前面的单个字符出现的次数
*:任意次
+:至少一次
?:至多一次
{m}:指定m次
{m,n}:m <= 次数 <=n
{m,}:至少m次
{,m}:至多m次 -
边界限定
-
^:以指定的内容开头
-
$:以指定的内容结尾
-
示例:
import re只从开头匹配
f = re.findall(’^hello’, ‘asjdhelloaskd’)
只从结尾匹配
f = re.findall(‘world$’, ‘asjdhelloaskworld’)
同时限制开头和结尾
f = re.findall(’^\w*$’, ‘asjdhelloaskworld’)
print(f)
-
-
优先级与整体
import re# |:表示或,拥有最低的优先级 # ():可以表示一个整体 s = re.search('hell(o|w)orld', 'akdhahellworld') if s: print(s.group())
-
分组匹配
-
示例1:
import rec = repile(’(\d+)([a-z]+)(\d+)’)
s = c.search(‘agaj123sdgewsgdf456adjsd’)
if s:
# 0:表示完整匹配内容,之后的数字表示第几组,也就是第几个()匹配的内容
print(s.group(0), s.span(0)) #123sdgewsgdf456 (5, 20)
print(s.group(1), s.span(1)) #123 (5, 8)
print(s.group(2), s.span(2)) #sdgewsgdf (8, 17)
print(s.group(3), s.span(3)) # 456 (17, 20) -
示例2:
import re固定匹配
c = repile(’ \w+ ’)
动态匹配:匹配两次嵌套的标签
c = repile(’<[a-z]+><[a-z]+>\w+</[a-z]+></[a-z]+>’)
无名分组:\1、\2分别表示前面的第一组、第二组匹配的内容
c = repile(r’<([a-z]+)><([a-z]+)>\w+</\2></\1>’)
命名分组:给分组()起名字
c = repile(r’<(?P[a-z]+)><(?P[a-z]+)>\w+</(?P=two)></(?P=one)>’)
s = c.search(‘
百度一下 ’)if s:
print(s.group())
# 返回所有组的信息,是一个元组
print(s.groups())
# 返回分组的字典,键是组的名字,值时匹配的内容
print(s.groupdict())
-
-
findall
import re# 按照正则进行匹配,但是添加()后,结果只显示()匹配的内容 f = re.findall('A(abc)A', 'asdjAabcAasdjAabcAsdkabca') print(f)
-
贪婪匹配
-
贪婪:最大限度的匹配。正则的匹配默认是贪婪的
-
非贪婪:只要满足条件,能少匹配就少匹配。可以使用’?'取消贪婪
-
示例:
import re.+?:取消至少一次的贪婪匹配
c = repile(‘a.+?b’)
.*?:取消任意多次的贪婪匹配
c = repile(‘a.*?b’)
s = c.search(‘sdhaasdajasksdbsdjbsdk’)
if s:
print(s.group())
-
-
匹配模式
-
说明:匹配模式就是对默认的匹配原则进行整体的修饰
-
示例:
import rere.I:表示忽略大小写
s = re.search(r’hello’, ‘Hello’, re.I)
re.M:多行处理,默认会把字符当做一行处理
s = re.search(r’^hello’, ‘asdkasj\nhelloajsdhkas’, re.M)
string = ‘ hello ’
string = ‘’’
hello ''' # re.S:是.可以匹配任意,作为单行处理(忽略\n) s = re.search(r' .*? ', string, re.S)if s:
print(s.group())
-
-
字符转义
-
匹配凡是跟正则语法相关的字符都需要需要进转义
-
示例:
import repython \\d \\d r’\d’
re \d \d \d
实际 \d \d \d
推荐使用,否则需要写很多\
c = repile(r’\d’)
s = c.search(’\d’)
if s:
print(s.group())匹配’\b’字符串
c = repile(r’\b’)
\b本身有特殊含义
s = c.search(r’\b’)
if s:
print(‘成功’, s.group())
在定义字符串的开头添加’r’表示原始字符串,可以轻松解决很多关于转义的问题
-
-
正则切割
import rec = repile(r'\d') string = '正则其实不难1但是学完之后2发现什么也不出来3是这样吧' # 字符串是固定切割,不能解决某类的匹配切割问题 # print(string.split('1')) # 按照正则进行切割 ret = c.split(string) print(ret) # 整体方案 print(re.split(r'\d', string))
-
正则替换
string = ‘helloadjasdhelloskdjalkhellosdjka’
# 字符串替换
new_string = string.replace(‘hello’, ‘world’, 2)
print(new_string)import re s = 'how1are2you' # 正则替换 # s2 = re.sub(r'\d', ' ', s) # 替换时可以传递一个函数,使用函数的返回值进行替换 def double(s): return str(int(s.group()) * 2) # return 'xxx' # 使用专门的处理函数,可以人为的干预替换过程 s2 = re.sub(r'\d', double, s) print(s2)
练习
-
匹配手机号
-
'''import re ret = repile(r'1[3-9]+\d{9}') s = ret.search('dgads18939472276') if s: print('是手机号',s.group())'''
-
匹配邮箱
-
'''import re ret = repile(r'1[3-9]+\d{9}') s = ret.search('dgads18939472276') if s: print('是手机号',s.group())'''
-
匹配URL
-
import re c = repile(r'https?:\/\/([0-9a-zA-Z]+\.)+[a-zA-Z]+(:\d+)?[/a-zA-Z0-9\._]+(\?.*)?') url = 'https://www.baidu:443/s/a/b/index.html?ie=utf-8&f=8' a = c.search(url) if a: print(a.group()) '''
匹配IP
import rec = repile(r'(((25[0-5]|2[0-4]\d{2})|([1-9]?\d))\.){3}((25[0-5]|2[0-4]\d{2})|([1-9]?\d))') ipv4 = '0.0.0.0' ipv4 = '255.255.255.0' s = c.search(ipv4) if s: print(s.group())
网络编程
相关概念
- OSI七层模型:开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架。它从低到高分别是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
- TCP/IP:在OSI七层模型的基础上简化出来的一套网络协议族,共有4层,得到了广泛使用。
- TCP:传输控制协议
- 有连接的,数据传输是可靠的(数据检查)
- 传输速度稍慢,三次握手、四次挥手
- UDP:用户数据报协议
- 无连接的,数据传输是不可靠的
- 传输速度较快
- IP地址:计算机的唯一标识
- windows查看IP:ipconfig
- ping:查看网络连通性
- 示例:ping 域名/IP
- 端口号:每个应用都有自己的端口号
-
范围:0~65535
-
公认端口:0~1023
http: 80
https: 443
smtp: 25
ftp: 21
ssh: 22 -
其他端口:1024~65535
-
- 网络编程核心
- IP + 端口号
- 库:socket
TCP协议
- 说明:面向连接的、数据可靠、三次握手、四次挥手、传输速度稍慢
- 原理:见图片《tcp.png》
- 示例:模拟http协议请求百度服务器的数据,见01-tcp-http.py
- TCP协议的服务器与客户端:见02-tcp-server.py 03-tcp-client.py
UDP协议
- 说明:面向无连接、数据不可靠、传输速度较快,适应于对数据要求不严格的情况
- 原理:见图片《udp.png》
- 示例:模拟飞秋数据,见04-udp-feiqiu.py
- UDP协议的服务器与客户端:见05-udp-server.py 06-udp-client.py
mini-web服务器
- 能够完成简单的请求处理
- 使用http协议
- 目的:加深对网络编程的认识,为学习WEB做铺垫
基础总结
多进程WEB服务器
- 加深对HTTP协议的认知
- 加深网络编程的了解
- 为学习后面的WEB内容做铺垫
- 练习:自己实现路由地址与视图函数的对应,
- 要求根据对应的请求路由地址,调用对应的视图函数处理
- 可以使用正则匹配 或者 使用装饰器
- 要求根据对应的请求路由地址,调用对应的视图函数处理
图片处理
-
说明:通常对于图片的操作有这些操作(缩放、旋转、翻转、裁剪、滤镜、画图等)
-
扩展库:PIL,只支持PY2,在PY3中使用需要安装pillow库
-
安装:pip install pillow
-
预备知识:
- 颜色:R(红)、G(绿)、B(蓝)、A(透明度)
- 坐标:(0,0)表示图片的左上角,向右表示水平的正方向,向下表示垂直方向的正方向
-
缩放操作
from PIL import Image# 打开图片 img = Image.open('erha.jpg') # 修改尺寸,在原图上修改 # img.thumbnail((200, 300)) # 修改尺寸,返回新的对象 img.resize((200, 200)).show() # 展示图片 # img.show() # 保存图片,指定文件名(要带后缀) # img.save('erha200_300.jpg')
-
画图操作
from PIL import Image, ImageDraw, ImageFont# 新建图片 img = Image.new('RGB', (300, 300), 'red') # 创建画笔 draw = ImageDraw.Draw(img) # 画点(一个像素) draw.point((150, 150), fill=(0, 255, 0)) # 画线 draw.line(((0, 0), (100, 100)), fill=(0, 0, 255), width=5) # 创建字体对象 font = ImageFont.truetype('xdxwz.ttf', 30) # 画字 draw.text((200, 200), 'A', fill=(255, 255, 0), font=font) img.show()
-
画验证码
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from random import randintdef rand_color(is_light=False): if is_light: return (randint(128, 255), randint(128, 255), randint(128, 255)) return (randint(0, 127), randint(0, 127), randint(0, 127)) def rand_string(length=4): code = '' for i in range(length): code += str(randint(0, 9)) return code # 获取一个浅色背景 back_color = rand_color(is_light=True) # 创建图片 img = Image.new('RGB', (200, 50), back_color) # 创建字体 font = ImageFont.truetype('xdxwz.ttf', 30) # 创建画笔 draw = ImageDraw.Draw(img) # 生成随机验证码 code = rand_string() # 画字符 for i in range(len(code)): draw.text((15+50*i, -5), code[i], font=font, fill='black') # 画干扰点 for i in range(5000): x = randint(0, 200) y = randint(0, 50) draw.point((x, y), fill=rand_color()) # 添加滤镜,会生成新的图片对象 # img = img.filter(ImageFilter.GaussianBlur) # 展示 img.show()
PY2与PY3的区别
- 见PDF文档Python2.x与Python3.x的区别.pdf
简单的数据结构
-
排列组合
import itertools# 排列:从m个元素中去n个元素,所有的可能就是排列(有序) # 当m等于n时称为全排列 # it = itertools.permutations([1, 2, 3], 3) # 组合:没有顺序的排列 # it = itertoolsbinations([1, 2, 3, 4], 2) # 笛卡尔成绩:多个序列中的组合 # it = itertools.product([1, 2], [3, 4], [5, 6]) # 序列一样的情况 it = itertools.product([1, 2], repeat=3) # 与上式等价 # it = itertools.product([1, 2], [1, 2], [1, 2]) for i in it: print(i)
-
计数器与队列
from collections import Counter, dequec = Counter([1, 2, 3, 4, 2, 1, 2, 1, 3, 4, 2]) print(c) # 转换为字典 print(dict(c)) # 获取出现次数最多的元素及次数 print(c.most_common(1)) # 双向队列 d = deque([1, 2, 3]) # 从右侧添加 d.append(4) # 从左侧实现 d.appendleft(5) # 从右侧弹出元素 print(d.pop()) # 从左侧弹出元素 print(d.popleft()) # 从右边扩充序列 d.extend([7, 8, 9]) # 从左侧扩充序列 d.extendleft(['a', 'b', 'c']) # 循环移动:正数表示右移,负数表示左移 # d.rotate(1) d.rotate(-1) print(d) print(list(d))
-
链表
- 添加
- 追加
- 删除
- 统计
- 展示
更多推荐
python前端基础知识总结 及部分练习题
发布评论