"""
文件的修改:了解
函数 ******
"""
"""
1、可变与不可变类型
2、dict方法补充
3、set数据类型:去重,无序,for迭代取值,运算 & | ^ -
4、字符编码:编码演变 ascii -> utf-8
字符 -> 字节 -> 2 ** 8(256)-> 8个二进制位 => 计算机最新的存储单位 字节
编码:encode() 解码:decode()
5、文件处理:
1.open()操作系统打开硬盘空间
2.f=open() python将数据加载到内存
3.f.read|write 操作文件
4.f.close() 自带 flush
5.del f
三步骤:打开文件 操作文件 关闭文件 => with open() as f: 操作文件的逻辑 => 自动close
文件的复制:
with open('1.txt', 'r', encoding='utf-8') as rf:
with open('2.txt', 'w', encoding='utf-8') as wf:
for line in rf:
wf.write(line)
wf.flush()
操作模式:
主:r | w | a
从:b | t | +
"""
# 模式选取:rb+, ab+,不能出现w(清空文件内容)
# with open('test.txt', 'rb+') as f:
# f.write(b'abc') # 默认从头 一个一个字节 替换
# f.write('呵呵'.encode('utf-8'))
# with open('test.txt', 'ab+') as f:
# f.write(b'abc') # 默认从尾 一个一个字节 添加
# f.write('呵呵'.encode('utf-8'))
# with open('test.txt', 'rb+') as f:
# print(f.read(3).decode('utf-8'))
#
# # offset偏移字节,whence开始偏移的位置
# # whence:0从头开始偏移 2从尾开始偏移 1从当前游标所在位置
# f.seek(6, 1)
# f.write('心情'.encode('utf-8'))
# f.seek(-6, 1)
# f.write('人'.encode('utf-8'))
# a默认不能改变游标位置
# with open('test.txt', 'ab+') as f:
# f.seek(3, 1)
# f.write('昨'.encode('utf-8'))
# 总结:文件修改的默认一定是 rb+
# 什么是函数
"""
解决问题的工具 - 解决问题需要多个步骤 - 一个整体 - 给该整体命名(工具名字) - 通过名字就能表明使用的工具 - 完成对应的事
函数:可以解决 "特定" 功能的代码块,要给代码块进行命名(函数名),通过函数名来调用(使用)函数
"""
# 为什么要有函数
'''
1. 避免代码的冗余
2. 让程序代码结构更加清晰
3. 让代码具有复用性,便于维护,极大降低开发成本
'''
# 在哪用函数
# 所有要复用的代码块都可以封装成函数,进行复用
# 怎么用函数
# 通过 函数名(参数们) => 参数个数:0~n
# 求两个数中的大值:max 参数个数:2~n, 1个有值的容器
print(max(1, 10, 5, 30))
print(max([1]))
# 没有参数的:
l = list()
print(l)
# input()函数
函数的定义
# def就是声明有缩进函数的 关键字 # fn就是函数名,就是使用函数的 符号 # 使用函数功能:函数名() 来调用函数 # 注:函数的声明不会调用函数(函数体不能执行) def fn(): n1 = input('n1:') n2 = input('n2:') print(n1 + n2) # 函数名 + ()是调用函数,加()目的是传参,即使不需要参数,也必须加() fn()
函数的分类
# 空函数:函数体未设定,可以用pass填充
def fn1():
pass
# fn1()
# 有参函数:内部逻辑(函数体)需要外接的数据
def fn2(a):
print('外键的参数%s' % a)
# fn2(10)
# 无参函数:内部逻辑(函数体)不需要外接的数据
def fn3():
num = input('num: ')
print('内部自己的逻辑产生的数据%s' % num)
# fn3()
# 有返回值函数:通过return将内部数据反馈给外界
def fn4():
num = 10 # 内部数据需要给外界用
return num
result = fn4()
print(result)
# 无返回值函数:没有return或return后不跟数据,默认返回None
def fn5():
num = 100 # 内部数据不需要给外界用
print(num)
return
result = fn5()
print(result)
# 总结:
# 1.内外数据交互:外界通过参数将外界数据传给内部,内部通过返回值将内部数据反馈给外界
# 2.函数都有返回值,可以自定义,系统默认返回None
# 1.没有return默认返回None:函数内部的值都不需要反馈给外界
def fn1():
pass
# 先执行拿到结果,在输出(使用)结果
res = fn1()
print(res)
# 直接执行并输出(使用)结果
print(fn1())
# 2.空return默认返回None:用来主动结束函数
def fn2(n1, n2): # 只做两个数字的加法
if not (isinstance(n1, int) and isinstance(n1, int)):
print('数据不合法')
return
print(n1 + n2)
fn2('10', 20)
fn2(10, 20)
# 3.一个值的return:将内部一个值反馈给外界,外界可以接收值,重复使用
def fn3(n1, n2):
sum = n1 + n2
return sum
result = fn3(100, 200) # result: 300
print(result * 10)
# 4.多个值的return:将内部多个值反馈给外界,外界可以接收值,重复使用
def fn4(n1, n2):
sum = n1 + n2
low = n1 - n2
jump = n1 * n2
fall = n1 / n2
return sum, low, jump, fall
# return [sum, low], [jump, fall] # ([88, 44], [1452, 3.0])
# 注:返回多个值本质是将多个值加压成元组返回
# print(fn4(66, 22))
s, l, j, f = fn4(66, 22)
print(f)
# 1.没有return默认返回None:函数内部的值都不需要反馈给外界
def fn1():
pass
# 先执行拿到结果,在输出(使用)结果
res = fn1()
print(res)
# 直接执行并输出(使用)结果
print(fn1())
# 2.空return默认返回None:用来主动结束函数
def fn2(n1, n2): # 只做两个数字的加法
if not (isinstance(n1, int) and isinstance(n2, int)):
print('数据不合法')
return
print(n1 + n2)
fn2('10', 20)
fn2(10, 20)
# 3.一个值的return:将内部一个值反馈给外界,外界可以接收值,重复使用
def fn3(n1, n2):
sum = n1 + n2
return sum
result = fn3(100, 200) # result: 300
print(result * 10)
# 4.多个值的return:将内部多个值反馈给外界,外界可以接收值,重复使用
def fn4(n1, n2):
sum = n1 + n2
low = n1 - n2
jump = n1 * n2
fall = n1 / n2
return sum, low, jump, fall
# return [sum, low], [jump, fall] # ([88, 44], [1452, 3.0])
# 注:返回多个值本质是将多个值加压成元组返回
# print(fn4(66, 22))
s, l, j, f = fn4(66, 22)
print(f)
# 函数必须先定义后调用 - python是解释型语言
# fn()
# 外界数据要传递给内部 - 参数
def fn(num): # 外界传递 100 就是100,传递 'abc' 就是 'abc',形式上的
print(num)
print(num)
print(num)
print(num)
# number = input("num: ")
# fn()
num = input("num: ") # 外界的 num 才是数据的产生点,实际上的
fn(num)
# 形参:形参没有实际的值,值来源于实参,函数定义时 () 中出现的变量
# 实参:实参具有实际的值,值提供给形参,函数调用时 () 中出现的变量或值
# 实参的分类:
# 1、位置实参(positional)
# 2、关键字实参(keyword-only)
def fn(a, b):
print(a, b)
# 位置实参传参
fn(10, 20) # 10 -> a | 20 -> b
n1 = 100
n2 = 200
fn(n2, n1) # n2 -> a | n1 -> b
# 关键字实参传值
fn(b=n1, a=n2) # n2 -> a | n1 -> b
def func(a, b, c):
print(a, b, c)
# func(100, b=200, 300) # 100ok 200ok 300nook
# func(100, a=200, c=300) # 按位置拿到值的形参就不能再被关键字进行传参
func(100, c=200, b=300) # 正确的
func(100, b=200, c=300) # 提倡
# 总结:
# 1、函数传递参数的实参形参个数要统一
# 2、位置实参传参:按位(安装顺序)传参
# 3、关键字实参传值:根据形参名,指名道姓传递值,传递顺序可以任意
# 4、如果位置与关键字实参同时存在,必须位置在前,关键字在后
# 1、无值位置形参
# 2、有值位置形参(默认参数)
# 3、可变长位置形参
# 4、无值关键字形参
# 5、有值关键字形参
# 6、可变长关键字形参
# 位置与关键字的分水岭: * 前的是位置,后是关键字
def fn1(a, b, *, x, y):
print(a, b, x, y)
fn1(a=10, b=20, x=100, y=200)
# 总结:
# 1、关键字形参必须有关键字实参传递
# 2、位置形参可以由位置或关键字实参传值
# i、位置实参只能给位置形参传值
# ii、关键字实参能给位置及关键字形参传值
# 无值的
def fn2(a, b, *, x, y):
print(a, b, x, y)
fn2(a=10, b=20, x=100, y=200)
# 总结:
# 1、*前的a,b是无值的位置形参,必须要被传值,可以由位置或关键字实参传值
# 2、*后的x,y是无值的关键字形参,必须要被传值,只能由关键字实参传值
# 有值的
def fn3(a=10, *, x=100):
print(a, x)
fn3()
fn3(x=888)
fn3(a=666)
fn3(x=888, a=666)
fn3(333, x=777)
# 总结:
# 1、有值的形参均可以不用被传值,没有被传值时采用默认值
# 2、可以给部分有默认值形参传值,被传值的形参采用所接受到的值,没有被传值的有默认值形参采用默认值
# 可变长
# *还是分水岭
def fn4(a, *args, x):
pass
fn4(10, x=100)
# *和**是 指针符号,args、kwargs才是变量名
def fn5(*args, **kwargs):
print(args)
print(kwargs)
fn5()
fn5(1, 2, 3, x=10, y=20, z=30)
# 总结:
# 1、args用元组来接受值,kwargs用字典来接受值
# 2、args接收所有位置参数,kwargs接收所有关键字参数
形参运用
# 六种形参共存:必须按照以下顺序定义
# 无值位置、有值位置、可变长位置、有无值关键字、可变长关键字
def fn(a, b=10, *c, d, e=100, f, **g):
print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
# fn(10, 20, 30, 40, d=50, f=70, x=100, y=200, z=300, e=60)
fn(a=10, b=20, c=30, d=50, f=70, x=100, y=200, z=300, e=60)
# 总结:
# 1、可变长位置形参:是接收 无值与有值位置形参 未接收完的所有 位置实参
# 2、可变长位置形参要接收到值,前方所有的位置形参必须被传值,所以前方出现有值位置形参没有多大意义
# 3、可变长关键字形参:是接收 前方所有 未接收完的 关键字实参
# 常见组合
def fn1(a, b=20):
pass
def fn2(a, *, host, port):
pass
def fn3(a, *, host='localhost', post):
pass
def fn4(*, host='localhost', post):
pass
def fn5(a, *args):
pass
def fn6(*args, **kwargs): # *****
pass
def fn7(a, *args, x, **kwargs):
pass
# 打散传值
def func(*args, **kwargs):
print(args)
print(kwargs)
# func(1, 2, 3, x=10, y=20, z=30)
ls = [1, 2, 3]
dic = {'x': 10, 'y': 20, 'z': 30}
# func(ls, dic) # (ls, dic) {}
# *ls会把ls打散(解压) => 1, 2, 3
# **dic会把dic打散(解压) => x=10, y=20, z=30
func(*ls, **dic) # == func(1, 2, 3, x=10, y=20, z=30)
func(*[4, 5, 6], **{'name': 'owen', 'sex': 'male'})
函数的嵌套调用
# 求两个数值的大值
def max_two(n1, n2):
# 从n1,n2中判断大者返回
if n1 > n2:
return n1
return n2
print(max_two(100, 88))
# 求三个数值的大值
def max_three(n1, n2, n3):
if n2 < n1 > n3:
return n1
if n1 < n2 > n3:
return n2
if n1 < n3 > n2:
return n3
print(max_three(10, 30, 20))
# 函数的嵌套调用:在被调用的函数内部,调用其他函数
def max_three(n1, n2, n3):
res = max_two(n1, n2)
return max_two(res, n3)
print(max_three(10, 30, 20))
# 求四个数值的大值
def max_four(n1, n2, n3, n4):
res = max_three(n1, n2, n3)
return max_two(res, n4)
print(max_four(10, 30, 20, 40))
函数对象(函数名)
# 对象:对象就是存放地址的变量
# 函数名是存放函数地址的变量:函数对象
def fn():
print('fn run')
print(fn)
a = 10 # a是 整型对象
ls = [1, 2] # ls是 列表对象
# a和ls是对象,fn也是对象,使用本质没有多大区别
# 但是a与ls与fn之间又有本质区别:使用方式不一样
# a就是用来做算术运算的
# ls是用来存储多个值的 ls.append() ls[0] ls.pop(index)
# fn是用来加()调用拿到功能执行结果的 fn(参数列表)
# 函数对象的应用场景
"""
# 1 可以直接被引用
# 2 可以当作函数参数传递
# 3 可以作为函数的返回值
# 4 可以作为容器类型的元素
"""
def fn():
print('fn run')
fn()
a = 10
r1 = a
r1 += 1
print(r1)
# 1、可以直接被引用:将函数对象直接赋值给另一个变量(对象),该变量就可以加括号调用函数
r2 = fn
r2()
# 注:这个不是函数的引用,这是调用fn函数,拿到返回值给r3
r3 = fn()
############################这里不是很明白########################
# 2、可以作为函数的参数
def new_fn(arg):
print(arg)
# 如果能调用(是函数),就可以加()调用
if callable(arg):
arg()
new_fn(fn)
#################################################################
# 3、可以作为函数的返回值
def func():
return fn
res = func()
res()
func()()
# 4、作为容器对象的成员
ls = [10, 'abc', fn()]
ls[2]()
dic = {
'method': fn
}
dic['method']()
# 总结:
# 1、函数名可以被任意引用
# 2、函数名一旦加()就是执行函数拿到函数的结果
# 需求:
# 从键盘录入运算指令,完成数据的运算 五则运算
# 指令正确:完成对应的运算,指令错误:重新输入指令,指令为Q或q退出系统
def add(n1, n2):
print("选择了加法运算")
return n1 + n2
def low(n1, n2):
print("选择了减法运算")
return n1 - n2
def jump(n1, n2):
print("选择了乘法运算")
return n1 * n2
# 指令与函数的对应关系 映射
method_map = {
'add': add,
'low': low,
'jump': jump
}
# 运算,给我运算方法与运算数据,我来帮你完成运算
def computed(fn, num1, num2):
return fn(num1, num2)
# 获取运算方法
def get_method(cmd):
return method_map[cmd]
is_over = False
while not is_over:
n1 = int(input('num1: '))
n2 = int(input('num2: '))
result = None
while True: # 指令可能不是一次性成功
cmd = input('cmd:') # add => 调用add函数 | low => 调用low函数
if cmd.lower() == 'q': # q的指令是要结束系统(双层循环)
print('退出系统')
is_over = True # 内外循环可以通过变量建立起关联
break
if cmd not in method_map:
print('指令错误')
continue
# result = method_map[cmd](n1, n2) # 该句没有执行,result默认值为0
# fn = method_map[cmd]
fn = get_method(cmd) # 有语义,根据指令得到对应的功能(函数)
result = computed(fn, n1, n2) # 有语义,该步是完成运算的,采用fn运算函数,提供n1,n2运算参数
break # 有执行结果,指令循环就可以结束了,代表本次运算有结果了
# 0、空字符串、None、()、[]、{}都代表假,其他代表真
if result is not None:
print("运算结果:%s" % result)
# 名称空间:存放名字与内存空间地址对应关系的容器
"""
# cpython解释器启动 => 加载名称空间
a = 10
a = 100
print(a)
def fn():
x = 30
print(x)
print(locals())
print(12345)
def fn1():
x = 300
print(x)
print(globals())
globals()['fn']()
fn()
fn1()
"""
# 三种名称空间
# Built-in:内置名称空间;系统级,一个;随解释器执行而产生,解释器停止而销毁
# Global:全局名称空间;文件级,多个;随所属文件加载而产生,文件运行完毕而销毁
# Local:局部名称空间;函数级,多个;随所属函数执行而产生,函数执行完毕而销毁
# 加载顺序: Built-in > Global > Local
print(max(1, 2))
# max = 100
# print(max)
# del max
#
# print(max(20, 30))
# 作用域:名字起作用的范围
# 内置加载了一个max:内置作用域
# max = 8 # 全局作用域
def fn():
# max = 88 # 嵌套作用域(局部)
def inner():
# max = 888 # 局部作用域
print(max)
inner() # 该函数变量在fn函数内部声明,所以在内部使用,同fn中定义的max,在fn中使用
fn()
# 变量的访问顺序(名字查找顺序)
# Local > Enclosing > Global > Built-in
"""
# Built-in:内置作用域 - 任何位置都起作用,但是最后被查找
# Global:全局作用域 - 在本文件中任何位置都起作用
# Enclosing:嵌套作用域 - 在自身函数与它嵌套的函数内部起作用
# Local:局部作用域 - 在自身函数内部起作用 - 最先被查找
"""
# 总结:
# 1、知道变量名字访问到变量值的完整路径:名称空间 => 栈区 => 堆区
# 2、明确名字的作用范围、查找顺序、生命周期
"""
# num = 10
# global: 在局部想修改全局变量(局部与全局变量统一) 或 在局部定义全局变量
def fn():
global num
num = 100
print(num) # 100
fn()
print(num) # 10 => global num => 100
"""
# nonlocal: 在被嵌套的局部想修改嵌套它的局部变量(嵌套作用域的变量统一)
"""
def outer():
num = 10
def inner():
nonlocal num
num = 100
print("inner:", num) # 100
inner()
print("outer:", num) # 10 => nonlocal num => 100
outer()
"""
num = 1
def outer():
global num
num = 10
def inner():
global num
num = 100
inner()
print(num) # 100
outer()
print(num) # 100