第三周
本周内容(第三周)
文件操作
1.文件的概念:
操作系统显示给用户可以直接操作硬盘的快捷方式,
打开文件的两种方式:
f = open(r'a.txt', 'r', encoding='utf8')
f.close() 关闭打开的文件
-------------------------------------------------------------------------------------
with open(r'a.txt', 'a', encoding = 'utf8') as f:
我们写路径的时候可能会遇到带有特殊含义的特殊符号,所以在文件路径前+r
------------------------------------------------------------------------------------
2. 文件的读写模式
文件读写模式有三种:
r 只读不写,文件不存在报错 # read
w 只写不读,文件不存在自动创建文件 清空文件在写入数据 # write
a 只追加模式 文件不存在自动创建文件,在文件的末尾添加数据
------------------------------------------------------------------------------------
3.文件的操作模式
t模式: 文本模式 全称 rt wt at 必须指定encoding参数,以字符为最小单位
b模式: 二进制模式 全称 rb wb ab 不需要指定encoding参数,以字节为最小单位
------------------------------------------------------------------------------------
4.文件的诸多方法
read() 一次性读取文件内容
readline() 一次只读一行内容
readlines() 一次性读取文件内容,结果是个列表对应每行内容
readable() 判断文件是否是可读的
write() 写入文件
writelines() 一次性将列表数据写入文件
writeable()判断文件是否是可读的
flush() 保存 相当于Ctrl + s
------------------------------------------------------------------------------------
5.文件的光标移动
seek(offset, whence)
offset 是位移量(以字节为单位), whence是模式,默认是0
模式分为三种:
0 让光标移到文件开头处 支持 文本模式和二进制模式
1 让光标停留在当前位置 只支持二进制模式
2 让光标移到文件末尾 只支持二进制模式
with open(r'userinfo.txt','r',encoding='utf8')as f:
print(f.read(1))
f.seek(3,0) # 光标移动3个字节
print(f.read(1))
文件的修改
1.计算机修改硬盘数据的原理
硬盘有两个形态, 占有态 和自由态
当我们在删除数据的时候,是将删除的数据改为自由态,在新数据放到自由态位置时,就会把他给覆盖。变成占有态。
文件数据在硬盘上是写死的,我们没有办法在中间添加新的内容,只能将老数据删除之后重新写新数据。
------------------------------------------------------------------------------------
2.修改文件的两种方式
先将文件内容一次性读写的内存中,使用只写不读模式进行修改,在文件修改过程中同一数据只有一份。 缺点:文件数据过大会导致内存溢出。
a.txt 今天头有点晕
with open(r'a.txt', 'r', encoding=‘utf8’) as f:
data = f.read() 打开文件并用一个变量名绑定文件地址
with open(r'txt', 'w', encoding = 'utf8') as f2:
f2.write(data.replace('今天', '哎呦')) 替换文件中今天为哎呦。
------------------------------------------------------------------------------------
用写的模式打开源文件,再用写的模式打开一个临时文件,一行行读取原文件内容。修改完成后写入临时文件,删除源文件将临时文件重命名为原文件
import os
with open(r'a.txt', 'r', encoding = 'utf8') as read_f,\open(r'a.txt', 'w', encoding = 'utf8') as write_f:
for i in read_f:
write_f.write(i) # 把 i 获取到的内容写入write_f
os.remove('a.txt') # 删除a.txt
os.rename('a.txt.swap', 'a.txt') # 把.a.txt.swap 改名为 a.txt
函数
什么是函数
函数其实就是工具,提前定义好,可以反复拿出来使用
语法结构
1.函数的语法结构:
def 函数名+(参数):
# 函数注释
函数体代码
return 返回值
调用 # 参数和返回值可有可无,根据调用时是否传参来确定要不要填参数
2.函数与循环的区别:
在相同的地方,反复执行相同的代码>>>循环
在不同的地方,反复执行相同的代码>>>函数
函数的定义与调用
定义函数需要使用def关键字.定义时不会执行函数,只会检测语法。
函数在调用阶段才会执行函数体代码。
函数必须先定义后调用。
函数的分类
1.空函数
在我们搭建功能的时候,提醒我们这里是什么功能
def f1():
# 功能
2.无参函数
def f2():
print('111')
定义函数时阔号内没有输入参数。
3.有参函数
def f3(a):
print(a)
定义函数时括号内填写了参数,调用时传参数
函数的返回值
return
在我们调用函数时得到的结果就是返回值
如何获取返回值:
变量名 = 函数调用
def test():
print('今天头疼')
没有 return 关键字,返回值是None
------------------------------------------------------------------------------------
def test():
print('今天头疼')
return
a = test()
print(a)
有return关键词,没返回值
------------------------------------------------------------------------------------
def test():
print('今天头疼')
return '头疼啊'
a = test()
print(a) # 头疼啊
有return关键字后面有返回值
"""
在函数里遇到return 会终止函数体代码,类似于循环里的break
return 后面跟着什么就会返回什么
return 后面有多个数据会组成元组返回
return 后面没有 返回None
没有return 返回 None
"""
形参与实参
定义时小括号内的参数,用来接收参数 --形参
调用时小括号内参数,用来传递参数 -- 实参
关系:
在调用函数的时候 传入实参会与形参临时绑定,函数结束运行自动解绑
形参类似于变量名, 实参类似于 变量的值
函数参数
位置参数
要诀
"""越短的越简单的越靠前
越长的越复杂的越靠后"""
位置参数
位置形参与位置实参必须保证个数相同,位置相同。 依照从左往右的顺序
-------------------------------------------------------------------------------------
位置形参
定义函数阶段小括号内填写
def fo(a,b):
函数体代码
------------------------------------------------------------------------------------
位置实参
def fo(a,b):
函数体代码
fo(1,2)
调用阶段括号内填写,也可以打断顺序,使用a = 1,b = 2的形式,一个形参同时不能多次赋值
默认参数
默认参数也称为 关键字参数
填写好默认参数 实参处可以不传,默认是形参填写的参数。
def foo(a, name = 'tank'):
print(a,name) # 1, tank
foo(1,) # name 默认参数时tank
------------------------------------------------------------------------------------
修改默认参数需要在实参处填写
foo(1, 'jack') # 此时默认参数tank 修改成 jack
------------------------------------------------------------------------------------
关键字参数说白了就是指名道姓的传参。
foo(a = 2 , name = 345)
------------------------------------------------------------------------------------
可以打乱顺序
foo(name=1, a = 2) # 必须使用关键字 不能 (name = 1 ,1)
可变长参数`重要
在参数中带有一个* 或者两个**的(*后面跟着变量名 **也是如此) 我们称为可变参数。
*后面变量名可以随意写,但是一般是由*args **kwargs 因为常用所以一般人都能看懂。
------------------------------------------------------------------------------------
*args
用来接收多余的位置参数 # 结果是元组
------------------------------------------------------------------------------------
**kwargs
用来接收多余的关键字参数,组成字典的方式传给**后面的变量名
def foo(*args, **kwargs):
print(args, kwargs)
foo(1, 2, 3, 4, name=1, a=2) # (1, 2, 3, 4) {'name': 1, 'a': 2}
可变长实参(重要)
* 和 **也可以在实参中使用
*在实参中可以把列表里的数据类似与for循环 取出,一次传递给函数
l1 = [2,3,5,6]
def foo(a,b,c,d):
print(a,b,c,d)
foo(*l1) #2 3 5 6
字典只能取出键,集合取出来是无序的。
------------------------------------------------------------------------------------
** 在实参中可以把字典内的数据以k:v的形式打散成关键字参数,传给函数
d1 = {'name': 'jack', 'age': 18, 'salary': 20000}
def foo(name,age,salary):
print(name,age,salary)
foo(**d1) # jack 18 20000
也可以打乱关键字形参的顺序
名称空间
名称空间的含义
其实就是用来存放 变量名和数据值绑定关系的空间
名称空间的分类,存活周期,作用范围
1.内置名称空间
解释器已经定义好了。里面包含很多文字可以直接拿来用
存活周期:
运行paython解释器时产生
关闭python解释器销毁
作用范围:解释器全局有效
------------------------------------------------------------------------------------
2.全局名称空间
py文件运行时产生,存放文件级别的名字。
存活周期:
运行py文件时产生
关闭py文件时销毁
作用范围:
py文件内全局有效
------------------------------------------------------------------------------------
3.局部内存空间
函数体代码运行时产生的空间
存货周期:
函数体代码运行时产生
函数体代码结束时销毁
作用范围:
函数体代码内有效
名字的查找顺序
当我们在查找名字时要先确定自己的位置在哪里
在函数体代码内
局部名称空间-全局名称空间-内置名称空间
在全局名称空间内
全局名称空间- 内置名称空间
golbal与nonlocal
global
可以在局部名称空间修改全局名称空间内的数据
x = 11
def foo():
global x
x = 22
foo()
print(x) 22
------------------------------------------------------------------------------------
nonlocal
可以在内层局部空间修改外层局部空间的数据
def foo():
x = 11
def foo1():
nonlocal x
x = 22
foo1()
print(x) 22
foo()
函数名的多种用法
什么是函数名
函数名其实就是绑定的一块内存空间,只不过该空间内是一串代码,调用时执行该内存空间内的代码
多种用法
1.可以当做变量名赋值
def f1():
print('变量名赋值')
res = f1
print(res)
res()
调用res = 调用f1 执行函数f1代码
------------------------------------------------------------------------------------
2.可以当做函数的参数
def func():
print('参数用法')
def func1(a):
print(a)
a()
func1(func)
调用函数func1 此时传参func 给a 调用a =调用func
------------------------------------------------------------------------------------
3.可以当做函数的返回值
def func():
print('返回值用法')
def func1():
print('111')
return func
res = func1()
print(res)
res()
调用func1 返回func 与res绑定 调用res=调用func
------------------------------------------------------------------------------------
4.可以当做容器使用
def register(): # 定义函数
print('注册功能')
def login(): # 定义函数
print('登录功能')
def check_all(): # 定义函数
print('查找功能')
def revamp(): # 定义函数
print('修改功能')
def remove(): # 定义函数
print('删除功能')
# 创建一个字典,用编号对应函数功能
func_dict = {
'1': register,
'2': login,
'3': check_all,
'4': revamp,
'5': remove
}
# 循环功能
while True:
# 打印功能供用户选择
print("""
1.注册功能
2.登录功能
3.查找功能
4.修改功能
5,删除功能
""")
choice = input('请输入想要的功能').strip()
if choice in func_dict:
num = func_dict.get(choice)
num()
闭包函数
什么是闭包函数
定义在函数内部的函数,并用到了外部函数名称空间中的名字
闭包函数用法
def f1(name ,age):
def f2():
pringt(name,age)
return(f2)
res = f1('tank',1997)
res()
装饰器
装饰器概念与本质
概念:
在不改变被装饰对象的代码与调用方式的情况下,给被装饰对象添加新的功能。
本质:
其实就是结合了函数参数,名称空间,函数多种用法,闭包函数结合到一起
装饰器模板与语法糖
def outer(func_name):
def inner(*args,**kwargs):
res = func_name(*args,**kwargs)
return res
return inner
语法糖
@outer
def func():
pass
多层语法糖,需要提前定义多个装饰器
@outer1
@outer2
@outer3
def func():
pass
有参装饰器模板
def outer_plus(a):
def outer(func_name):
def inner(*args,**kwargs):
res = func_name(*args,**kwargs)
return res
return inner
return outer
装饰器修复技术
from functools import wraps
ef outer(func):
@wraps(func)
def inner(*args, **kwargs):
print('啥米是装饰器')
res = func(*args, **kwargs)
return res
return inner
@outer
def foo():
print('我才是真正的foo')
修复技术只是用来忽悠你把函数foo改回成真的foo"""不是真的改,其实戴了个面具""" 啥都没变。 没啥用。
递归函数
在函数里直接或间接调用自制==递归函数
递归函数每一次必须比上一次更简单,距离答案更加近。不给返回值会一直循环递归,最大递归深度1000,超过1000报错。
用法:
计算1-100之和。
def func(a):
in a < 1:
return 1
else:
return func(n - 1) + n
res = func(100)
print(res)
二分法
根据我们需要查找的数据在目标数据集里中分查找,没找到的情况下对比大小切分,重复至找到目标数据
l1 =[11,22,33,44,55,66,77,88,99]
def get(l1, target_num):
# 结束条件
if len[l1] == 0:
return
# 中分列表
midder = len[l1] // 2
if target_num > l1[midder]:
#切割操作,保留右边
right_l1 = l1[midder+1:]
# 因为顾头不顾尾的特性,该索引位已做过对比
return get(right_l1, target_num)
elif target_num < l1[midder]:
# 保留左边
left_l1 = l1[:midder]
return get(left_l1, target_num)
else:
print('找到啦')
get(l1, 55)
三元表达式
我们判断条件只需要二选一时可以使用。简化代码
name = 'jack'
res = '真厉害' if name == 'jack' else '不行啊'
print(res) # 真厉害
数据值1 判断条件 数据值2
如果判断条件成立 执行 数据值1 ,判断条件不成立执行 数据值2
生成式
列表生成式
res = [添加的数据,for循环]
l1 = ['jason', 'tank', 'tony']
res = [f'{i}厉害' for i in l1]
字典生成式
res ={k:v形式, for循环k,v enenumerate(目标数据集)}
res = {k:v for k,v in enumerate(l1)}
enumerate 当你在循环一个数据集的时候给你产生从0开始的数字,也可以修改起始号码 在后面+ start= 20
集合生成式
res = {i for i in 'wokao'}
prit(res)
匿名函数
没有函数名的函数,需要使用关键字
lambda
语法结构
lambda 形参:返回值
"""
def func(a, b) 是def的声明部分,return a+b 是实现部分
lambda x,y是声明部分,x * y是实现部分
"""
重要内置函数
1.map()映射
l1 = [12,21,26,31,40]
res = map(laambda x.y:x+y, l1)
-------------------------------------------------------------------------------------
2. max()\min()最大值最小值
res = max(l1) # 40
-------------------------------------------------------------------------------------
3.reduce 传多个值返回一个值
from functools import reduce
res = reduce(lambda a,b:a+b, l1)
-------------------------------------------------------------------------------------
4.zip 拉链
可以把两个列表的数据按照索引位的顺序合在一起,可以有多个,如果有短的,按照短的索引位 后面的不用
l1 = [11, 22, 33, 44, 55]
l2 = ['是我','是你','是他','是狗']
res = zip(l1,l2)
print(list(res))
-------------------------------------------------------------------------------------
filter 过滤
根据我们给的数据值固定条件
l1 = [11, 22, 33, 44, 55]
res = filter(lambda x:x > 22, l1)
-------------------------------------------------------------------------------------
sorted 排序
res = sorted(目标数据集)
常见内置函数
abs()绝对值
有符号的情况下只取数据值 。只限 + -
-------------------------------------------------------------------------------------
all()
所有数据值为True 返回True 只要有一个Flase 返回Flase
-------------------------------------------------------------------------------------
any()
只要有一个数据为True返回True
-------------------------------------------------------------------------------------
bytes() 二进制模式
bin()其他进制转二进制
oct()其他进制转八进制
hex()其他进制转十六进制
int()其他进制转十进制
-------------------------------------------------------------------------------------
callable()
判断变量名是否可以+括号调用。
-------------------------------------------------------------------------------------
chr() 把数字转换成ASCII码对应的字母
ord() 把字母转换成ASCII码对应的数字
A - Z = 65-90 a-z = 97- 122
-------------------------------------------------------------------------------------
dir() 可以查看该数据能用的内置方法
-------------------------------------------------------------------------------------
divmod()
主要用在网站的分页制作上
eg:
def foo(a1,a2):
b1,b2 = divmod(a1,a2) # (计算后的整数,余数)
if b2:
b1 += 1
print(f'需要{b1}页')
foo(要计算的数据数,整除)
-------------------------------------------------------------------------------------
enumerate()枚举
eval() 识别字符串中的python并执行,只能识别简单的
exec() 识别字符串中的python并执行,可以识别复杂的
a1 = 'for i in name:print(i)'
exec(a1)
-------------------------------------------------------------------------------------
hash() 哈希加密 可以把字符串转成遗传你看不懂的数字
id() 查看内存地址 input() 获取用户输入
-------------------------------------------------------------------------------------
isinstance(目标数据,数据类型) 判断数据类型
-------------------------------------------------------------------------------------
map() 映射
max()\min() 最大值最小值
open 打开文件
-------------------------------------------------------------------------------------
pow() 幂指数 次方
print(pow(4,2)) 16
-------------------------------------------------------------------------------------
sum() 求和
print(sum([1,2,3]) 6
迭代对象
可以使用双下__iter__方法的都可以称为迭代对象。
迭代对象范围:
不可迭代对象:
int float 函数对象
可迭代对象:
str list dict set tuple 文件对象
迭代,更新换代的意思
迭代器对象
迭代对象调用双下__iter__方法后就变成了迭代器对象。
含有__iter__, __next__都是迭代器对象
理解:
对于一些有序文件如 列表,字符串,元组,我们可以使用索引取值的方式取出,而字典,集合这写没有索引位的我们没办法用索引取值,有了迭代器以后就可以给字典和集合取值了。注意是取键。
__next__调取数据一次只能调取一个,想要多个数据就要多次执行。获取完会报错
for循环本质
for循环的本质其实就是先调用了__iter__方法,后再用__next__获取数据,获取完会报错,for循环会自动捕捉报错然后处理。
for 变量名 in 迭代对象:
异常处理
在我们编写一段代码时往往在运行时会发生错误,如何处理这些错误呢。
报错位置分为三个区域。
报错代码位置。
报错类型,
报错详情。
我们可以根据报错详情得到报错的原因,然后根据代码的位置快速处理,如果出现多行报错那么只用看最近的一行,可能别的报错都是这行引起的。
报错分为两种:
语法错误 不允许出现
逻辑错误 因为藏得比较少,不容易看到,允许出现
周考核
1.编写⽤用户识别程序
要求:
可循环根据⽤用户输⼊入的姓名不不同输出不不同的身份信息
添加程序结束功能(如⽤用户输⼊入字⺟母q直接结束识别程序)
jason:扫地僧 tony:洗碗⼯ kevin:服务员 jack:配菜员 其他:未识别
# 1 先定义一个循环
while True:
# 2获取用户输入
# 8 增加结束循环条件
username = input('请输入姓名>>>(q)').strip()
if username == 'q':
break
# 3用户等于jason时 打印 扫地僧
if username == 'jason':
print('扫地僧')
# 4用户等于tony时 打印 洗碗工
elif username == 'tony':
print('洗碗工')
# 5 用户等于kevin时 打印 服务员
elif username == 'kevin':
print('服务员')
# 6 用户等于jack时 打印 配菜员
elif username == 'jack':
print('配菜员')
# 7 都不是 打印 未识别
else:
print('未识别')
2.利利⽤用for循环及range⽅方法自动生成链家⼆二手房多⻚页数据网址(十条以上即可)
http = 'https://sh.lianjia.com/ershoufang/pg%s/'
for i in range(0, 200, 1)
print(http % i)
3.编写⽤用户登录程序
温馨提示:
用户名与密码来源于字符串串source_data = 'jason|123'
想办法从中拆分出⽤用户名和密码⽤用于后续账户信息⽐比对
普通要求:
1.验证失败情况下可⼀一直循环验证 成功则直接退出
拔⾼高练习:
1.只允许三次失败机会
2.登录成功后进⼊入内层循环,⽤用户输⼊入任何指令利利⽤用格式化输出
打印正在执⾏行行该⽤用户指令即可,直到⽤用户输⼊入字⺟母q退出内层循环
# 编写用户登录程序
# 5 定义一个计数器
count = 0
# 4 定义循环
while True:
# 6 加入结束条件 3次
if count == 3:
print('你只有三次机会')
break
# 1获取用户输入
usernmae = input('请输入用户名(q)').strip()
passwold = input('请输入密码(q)').strip()
# 2 拆分用户名密码
real_name, real_pwd = source_data.split('|')
# 3 校验用户名密码是否正确
if usernmae == real_name and passwold == real_pwd:
print('用户登陆成功')
# 7添加内层循环
while True:
# 8 获取用户指令
user_input = input('请输入指令(q)').strip()
# 9 加入结束条件
if user_input == 'q':
print('下次在见')
break
print(f'正在执行{usernmae}该用户指令{user_input}')
else:
print('用户名密码错误')
count += 1
continue