函数基础
1 什么是函数
函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段。
2 为什么使用函数
不使用函数的结果:
- 组织结构不清晰,可读性差;
- 代码冗余;
- 可维护性、扩展性差。
函数能提高应用的模块性和代码的重复利用率。
3 如何使用函数
原则:先定义 后调用。
定义函数的过程:
- 在内存中申请空间来保存函数体的代码;
- 将该内存地址交给函数名;
- 定义函数时不会执行函数体代码,但会检测函数体语法。
调用函数的过程
- 通过函数名找到函数的内存地址;
- 加括号就意味着要执行函数体代码。
def test():
undef # 变量undef虽然没有定义,但此处不存在语法错误,不会报错。
print('不会报错')
test() # 报错,执行函数体代码时找不到变量undef的引用值。
3.1 函数定义
定义函数就相当于将一段代码封装起来,然后将内存地址交给函数名。
函数名是对这段代码的引用,这和变量的定义是相似的。
函数的命名应该反映出函数的功能,一般使用动词。
以 def 关键词开头,后接函数名和圆括号()
圆括号()可以放入形式参数
函数体代码以冒号起始,并且缩进
return [表达式] 用于结束函数,可以返回一个值给调用方。
不带表达式的return相当于返回 None。
def 函数名(形参列表):
"""文档描述(可选)"""
函数体
return 返回值(可选)
3.2 函数定义分类
3.2.1 无参函数
函数定义时参数列表为空。
3.2.2 有参函数
函数定义时包括参数列表。
3.2.3 空函数
函数体代码为pass或…
可以用于构思代码。
def func(x, y):
pass
3.3 函数调用
3.3.1 语句形式
函数名 + 括号
一般不需要函数体的返回值
def hello():
print('Hello!')
hello()
3.3.2 表达式形式
- 赋值表达式
def add(x, y):
return x + y
a = 1
b = 2
res = add(a, b)
- 运算表达式
def add(x, y):
return x + y
a = 1
b = 2
res = add(a, b) * 25
3.3.3 参数形式
函数调用可以作为参数
def add(x, y):
return x + y
a = 1
b = 2
res = add(add(a, b), 25)
3.4 函数返回值
return是函数结束的标志,用于退出函数。
函数体代码一旦运行到return就会立刻终止函数的运行,
并将return后的表达式当做本次运行的结果返回。
- 返回None
函数体内没有return
return 或者 return None - 返回一个值
def test():
return [1, 2, 3]
res = test()
print(res, type(res)) # [1, 2, 3] list
- 返回多个值
用逗号分隔开多个值,会以元组类型返回。
def test():
return 1, 2, 3
res = test()
print(res, type(res)) # (1, 2, 3) tuple
4 练习
4.1 编写文件修改功能
调用函数时,传入三个参数:修改的文件路径,要修改的内容,修改后的内容。
import os
def modify(file_path, raw_txt, modified_txt):
"""
用于修改文件。
:param file_path: 修改的文件路径
:param raw_txt: 要修改的内容
:param modified_txt: 修改后的内容
:return: None
"""
if not os.path.exists(file_path):
print('文件不存在。')
return
new_path = r'.{}.swap'.format(file_path)
with open(file_path, mode='rt', encoding='utf-8') as f1, \
open(new_path, mode='wt', encoding='utf-8') as f2:
for each_line in f1:
f2.write(each_line.replace(raw_txt, modified_txt))
os.remove(file_path)
os.rename(new_path, file_path)
4.2 编写tail工具
import time
import os
def tail(filepath):
"""
用于查阅正在改变的文件内容
:param filepath: 目标文件的路径
:return: None
"""
if not os.path.exists(filepath):
print('文件不存在。')
return
with open(filepath, mode='rb') as f:
f.seek(0, 2)
while 1:
end_line = f.readline()
if len(end_line) == 0:
time.sleep(0.5)
else:
print(end_line.decode('utf-8'))
4.3 编写登录功能
import os
def read_file(filepath):
if not os.path.exists(filepath):
print('用户数据文件不存在。')
return
user_dict = {}
with open(filepath, mode='rt', encoding='utf-8') as user_f:
for each_line in user_f:
un, pw = each_line.strip().split(':')
user_dict[un] = pw
return user_dict
def check_login(user_dict):
un_input = input('请输入用户名:').strip()
if un_input not in user_dict:
print('用户名不存在。')
else:
pw_input = input('请输入密码:').strip()
if user_dict[un_input] != pw_input:
print('密码错误。')
else:
print('登陆成功。')
def login(filepath):
filepath = r'{}'.format(filepath)
user_dict = read_file(filepath)
if user_dict is not None:
check_login(user_dict)
login('./user_info.txt')
4.4 编写注册功能
import os
def read_file(filepath):
if not os.path.exists(filepath):
print('用户数据文件不存在。')
return
user_dict = {}
with open(filepath, mode='rt', encoding='utf-8') as user_f:
for each_line in user_f:
un, pw = each_line.strip().split(':')
user_dict[un] = pw
return user_dict
def append_file(filepath, new_user_info):
with open(filepath, mode='at', encoding='utf-8') as user_f:
user_f.write(new_user_info)
return True
def check_register(user_dict):
while 1:
un_input = input('请输入用户名:').strip()
if un_input in user_dict:
print('用户名已存在,禁止注册。')
else:
while 1:
pw_input = input('请输入密码:').strip()
repw_input = input('请再次输入密码:').strip()
if pw_input != repw_input:
print('两次输入的密码不相同。')
else:
return '{un}:{pw}\n'.format(un=un_input, pw=pw_input)
def register(filepath):
filepath = r'{}'.format(filepath)
user_dict = read_file(filepath)
if user_dict is not None:
new_user = check_register(user_dict)
register_result = append_file(filepath, new_user)
if register_result:
print('注册成功。')
register('./user_info.txt')
4.5 编写ATM程序实现下述功能
数据来源于文件db.txt
- 充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改;
- 转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱;
- 提现功能:用户输入提现金额,db.txt中该账号钱数减少;
- 查询余额功能:输入账号查询余额;
- 用户登录成功后,内存中记录下该状态,上述功能以当前登录状态为准,必须先登录才能操作。
import os
INFO_PATH = r'./db.txt'
'''
db.txt格式为 用户名:密码:余额,例如:
A:AA:10000
B:BB:10000
'''
def read_file():
if not os.path.exists(INFO_PATH):
print('用户数据文件不存在。')
return
user_dict = {}
with open(INFO_PATH, mode='rt', encoding='utf-8') as user_f:
for each_line in user_f:
# 用户名,密码,存款
un, pw, dep = each_line.strip().split(':')
user_dict[un] = {'pw': pw, 'dep': int(dep)}
return user_dict
def check_login(user_dict):
un_input = input('请输入用户名:').strip()
if un_input not in user_dict:
print('用户名不存在,请核对用户名后重新登录。')
return None
else:
pw_input = input('请输入密码:').strip()
if user_dict[un_input]['pw'] != pw_input:
print('密码错误,请核对用户名和密码后重新登录。')
return None
else:
print('登陆成功。')
return un_input
def login():
user_dict = read_file()
if user_dict is not None:
while 1:
un = check_login(user_dict)
if un is not None:
return un
def write_file(new_dict):
new_str = ''
for each_un in new_dict:
each_pw = new_dict[each_un]['pw']
each_dep = new_dict[each_un]['dep']
new_str += '{un}:{pw}:{dep}\n'.format(un=each_un, pw=each_pw, dep=each_dep)
with open(INFO_PATH, mode='wt', encoding='utf-8') as f:
f.write(new_str)
def save_money(un, user_dict):
while 1:
money = input('请输入存钱金额:')
if not money.isdigit():
print('只接受数字。')
else:
money = int(money)
break
user_dict[un]['dep'] += money
write_file(user_dict)
print('存钱完成')
def withdraw_money(un, user_dict):
deposits = int(user_dict[un]['dep'])
if deposits == 0:
print('账户余额为0,退出取钱功能。')
return
while 1:
money = input('请输入取出金额:')
if not money.isdigit():
print('只接受数字。')
else:
money = int(money)
if deposits < money:
print('账户余额不足。')
else:
break
user_dict[un]['dep'] -= money
write_file(user_dict)
print('取钱完成')
def transfer_money(un, user_dict):
deposits = int(user_dict[un]['dep'])
if deposits == 0:
print('账户余额为0,退出转账功能。')
return
while 1:
money = input('请输入转账金额:')
if not money.isdigit():
print('只接受数字。')
else:
money = int(money)
if deposits < money:
print('账户余额不足。')
else:
break
while 1:
other_un = input('请输入转账目标用户:')
if other_un not in user_dict:
print('用户名错误,请重新确认后再输入。')
else:
break
print('''
注意,这里不能保证事务的四个特性,
如果因某些原因导致数据错误, Agon 老师一赔十,他有钱 :)
''')
user_dict[un]['dep'] -= money
user_dict[other_un]['dep'] += money
write_file(user_dict)
print('转账完成')
def check_money(un, user_dict):
deposits = int(user_dict[un]['dep'])
print('您的账户余额为:{deposits}'.format(deposits=deposits))
def quit(un, user_dict):
print('感谢使用,再见。')
return True
def atm():
un = login()
print('''
充值功能: 1
提现功能: 2
转账功能: 3
查询余额功能: 4
退出程序: 5
''')
while 1:
while 1:
num_input = input('请输入操作编号:')
if not num_input.isdigit():
print('注意,只能输入整数。')
cmd_num = int(num_input)
if cmd_num < 1 or cmd_num > 5:
print('注意,只能输入功能编号,其它数字无效。')
else:
break
while 1:
user_dict = read_file()
switch = {
1: save_money,
2: withdraw_money,
3: transfer_money,
4: check_money,
5: quit,
}
quit_flg = switch.get(cmd_num)(un, user_dict)
if quit_flg:
return
break
atm()