一:函数的定义
1)函数的简单使用,无参函数
def f1(): # 定义函数指定函数名
print("hello") # 指定功能
f1() # 调用函数,才能执行函数体里面的功能
语法结构
def 函数名(参数1,参数2.....): ''' 函数的文档注释 ;:param 参数1:参数1的作用 ;:param 参数2:参数2的作用 ;:return 返回值的描述 ''' 代码1 代码2 ..... return 返回值
2)函数传参
x = 3 y = 2 def max(x,y): if x > y: print(x) else: print(y) max(x,y)
3)空函数,pass
def foo(x,y):
pass
pass只是一个占位符,设计整个程序框架的时候,构思用的
二、函数的返回值
1)获取函数返回值
def max2(x,y): if x > y: return x else: return y ret = max2(3,2) print(ret)
2)利用函数返回值,反复利用。类型与while循环的方式
def max(x,y): if x > y: return x else: return y def max3(x,y,z): res1 = max(x,y) res2 = max(res1,z) return res2 print(max3(11,22,5))
调用时使用返回值
# 比较,3,10,18,8的大小 def max(x,y): if x > y: return x else: return y res = max(max(max(3,10),18),8) print(res)
3)对于函数返回值的注意点
1、返回值没有类型限制
2、返回值没有个数限制,可以用逗号分开多个值 一次以元组的形式返回
3、 可以没有不写 return ,默认返回None
三、函数的参数的传递,调用
1)形参,实参,位置参数
def foo(x,y,z = 3): print(x,y,z) foo(1,2) foo(1,2,5) foo(1,y= 8,z=10) foo(1,z = 3,y= 8)
注意事项
1、默认参数必须放在形参参数后面
2、 形参一定要放在关键字参数前面,比如 1,z = 3,y= 8
3、 同一个形参,只能被赋值一次
2)默认参数的使用
m = 10 def func(x,y = m): print(x) print(y) m = 1111 func(1)
注意事项
1、默认参数的值制作定义阶段被赋值一次就固定死了,定义之后改变没有影响
2、默认参数应该被设置成不可变的类型
例子,默认参数假设设置成可变类型
def func(name,hobby,l=[]): l.append(hobby) print(name,l) func('user','read') func('user1','play') func('user2','eat') # user ['read'] # user1 ['read', 'play'] # user2 ['read', 'play', 'eat']
修改调整,每次调用的默认参数,都是独立的,不相同的
def func(name,hobby,l=None): if l is None: l = [] l.append(hobby) print(name,l) func('user','read') func('user1','play',['music','movie']) func('user2','eat')
四、动态参数的使用
1)函数的动态参数一,一个*,转为元组
def foo(x,y,*z): print(x,y) print(z) foo(1,2,3,4,5,6)
对于实参中 * 的用法
# 实参使用* 相当于打打散了 def foo(x,y,*z): print(x,y) print(z) foo(1,*(2,3,4,5,6)) # # foo(1,2,3,4,5,6) def fo(x,y,z): print(x,y) print(z) fo(1,*(2,3))
2)动态参数二,二个*,转为字典
def k1(**b): #a = (123, 456) print(b,type(b)) #k1(123,"aegag",456,34,[11,53,55]) # 会报错 k1(k1=123,k2=456) # 返回结果 {'k1': 123, 'k2': 456} <class 'dict'>
3)动态参数的组合
def m1(p,*a,**aa): print(p,type(p)) print(a,type(a)) print(aa,type(aa)) m1(445,888,677,k4=888) # 返回结果 # 445 <class 'int'> #(888, 677) <class 'tuple'> #{'k4': 888} <class 'dict'>
4)元组的动态参数的标准定义,*args
def f1(*args): print(args,type(args)) li = [11,22,33] f1(li) #返回结果 ([11, 22, 33],) <class 'tuple'> f1(*li) #返回结果 (11, 22, 33) <class 'tuple'>
5)列表的动态参数的标准定义,**kwargs
形成使用**,实参也可以使用**
def foo(x,y,**kwargs): print(x) print(y) print(kwargs) foo(1,a=2,y=3,f=6) foo(1,**{'a':2,'y':'3','f':6})
小例题
1、求任意的个数的数字的和
2、求连续数字的积
def my_sum(*args): res = 0 for n in args: res += n return res print(my_sum(1,25,34,44,32)) def fat(n): ret = 1 for i in range(1,n+1): ret = ret*i return ret print(fat(5))
3、形参,实参,带* 的综合利用。重点
def index(name,gender): print('welcome %s gender is %s' %(name,gender)) # 参数传递,wrapper(*args,**kwargs) 接收到的参数全部给 index(*args,**kwargs) def wrapper(*args,**kwargs): index(*args,**kwargs) # 参数传递过程 wrapper(*args,**kwargs) == index(*args,**kwargs) >= index(name,gender) # 参数传递根据最小化接收参数给参数 index(name,gender) wrapper('user','male')
五、名称空间与作用域
1)内容归纳
1 名称空间Namespaces
存放名字与值绑定关系的地方
2 名称空间的分类
内置名称空间:
存放python解释器自带名字,比如内置的函数名:len,max,sum
创建:随着python解释器启动而创建
销毁:随着python解释器关闭而销毁
全局名称空间
存放文件级别的名字,比如x,f1,z
创建:文件开始执行时则立即创建
销毁:文件开始执行完毕时则销毁
局部名称空间
存放函数内的名字,强调函数的参数也属于局部的
创建:函数执行时才临时创建
销毁:函数执行完毕则立即销毁
3 名称空间的加载顺序
内置名称空间---》全局名称空间-----》局部名称空间
加载的目的是为了吧名字存起来,然而存起的目的就是为取
那么但凡查找一个名字一定会从三种名称空间之一找到
4、名称空间的查找名字顺序
局部名称空间====》全局名称空间====》内置名称空间
名字的查找关系是在函数定义阶段就已经固定死的,也调用位置无关
5、作用域:域=范围
全局范围:内置名称空间中的名字,全局名称空间中的名字
特点:全局有效,全局存活
局部范围:局部名称空间中的名字
特点:局部有效,临时存活
定义在全局作用域的名字称为全局变量
定义在局部作用域的名字称为局部变量
2)对于名称空间的例子
def f1(): print(len) f1() # <built-in function len> len = 99 def f2(): print(len) def f3(): len = 1 print(len) len = 10 f1() # 10 f2() # 10 f3() # 1
3)对于作用域的例子
x = 100 def ff(): print(x) def hh(): x = 11111 ff() ff() x = 1000 hh()
查看全局作用域的名字
x=111111111111111
print(globals()) #查看全局作用域中的名字
4)globals和nonlocal
对于globals 定义修改全局变量
x=99 def foo(): global x # 强行修改全局变量 x=100 foo() print(x)
nonlocal定义修改局部变量
def f1(): # x=10 def f2(): def f3(): nonlocal x # nonlocal会从当前外一层开始查找一直找到最外层的函数,如果还没有则报错 x=11 f3() f2() # print(x) f1()
六、函数对象的使用,函数可以当做变量去使用
1)函数可以被赋值
def foo(): print('from foo') f=foo # print(f) f()
2)可以当做参数传给一个函数
def foo(): print('from foo') def bar(func): #func=foo # print(func) func() bar(foo)
3)可以当做函数的返回值
def foo(): print('from foo') def bar(func): #func=foo return func #return foo f=bar(foo) print(f)
4)可以当做容器类型元素
def foo(): print('from foo') l=[foo,] print(l) l[0]() d={'foo':foo} d['foo']()
例子,实现函数的各个功能
def get(): print('from get') def put(): print('from put') def ls(): print('from ls') def login(): print('from login') def cd(): print('from cd') func_dic={ "1":[get,'下载'], "2":[put,'上传'], "3":[ls,'浏览'], "4":[login,'登录'], "5":[cd,'切换目录'] } def run(): while True: for k in func_dic: print(k,func_dic[k][1]) choice=input('>>>: ').strip() if choice == 'q':break if choice in func_dic: func_dic[choice][0]() run()
七、闭包函数
闭包函数就是:函数嵌套+名称空间与作用域+函数对象
1、什么是闭包函数
1、定义在函数的内函数
2、该函数体代码包含对该函数外层作用域中名字的引用,
强调:函数外层指的不是全局作用域
满足上述两个条件,那么该内部函数就称之为闭包函数
1)闭包函数缺陷,只能在函数体内用
def outter(): x = 1 def inner(): print(x) inner() outter()
2)闭包函数修整,函数外调
def outter(): x = 1 def inner(): print(x) return inner f = outter() # f = inner f() def foo(): print('from foo') f() foo()
3)闭包函数爬虫应用
例一,不使用闭包函数时
import requests #pip3 install requests def get(url): response=requests.get(url) if response.status_code == 200: print(response.text) get('https://www.python.org') get('https://www.python.org')
例二,使用闭包函数时
import requests def outter(url): # url='https://www.baidu.com' def get(): response=requests.get(url) if response.status_code == 200: print(response.text) return get baidu=outter('https://www.baidu.com') python=outter('https://www.python.org') python() python()
八、装饰器
装饰就是修饰,器指的就是工具
装饰器本身可以是任意可调用的对象
被装饰的对象也可以是任意可调用的对象
装饰器——》函数
被装饰的对象=》函数
装饰器是用来为被装饰对象添加新功能的一种工具
必须遵循:
1、不能修改被装饰对象的源代码
2、不能修改被装饰对象的调用方式
例题1:为下面函数增加功能,计算该函数运行的时间
1)初步实现装饰器功能
def index(): time.sleep(1) print('welome to index') start_time=time.time() index() stop_time=time.time() print('run time is %s'%(stop_time - start_time))
2)普通函数版修改
def index(): time.sleep(1) print('welome to index') # 传参,传要修饰的函数 def wrapper(func): start_time=time.time() func() stop_time=time.time() print('run time is %s'%(stop_time - start_time)) wrapper(index)
3)闭包函数修改版
def index(): time.sleep(1) print('welome to index') return 123 def outter(func): def wrapper(): start_time=time.time() res = func() stop_time=time.time() print('run time is %s'%(stop_time - start_time)) return res return wrapper index = outter(index) # f = wrapper res = index() print(res)
4)修正被装饰函数的传参问题,并加上装饰器特殊语法 @
def outter(func): def wrapper(*args,**kwargs): start_time=time.time() res = func(*args,**kwargs) stop_time=time.time() print('run time is %s'%(stop_time - start_time)) return res return wrapper @outter def home(name): time.sleep(1) print('welome %s to home' %name) return 123 home('user')
例题2:给函数加入用户认证功能。并不重复认证
import time current_user={'login':False} def outter(func): def wrapper(*args,**kwargs): if current_user['login']: return func(*args, **kwargs) user = input("username>>>: ").strip() pwd = input("password>>>: ").strip() if user == 'user' and pwd == '123': current_user['login'] = True return func(*args,**kwargs) return wrapper @outter def index(): time.sleep(1) print('welcome to index') return 1234 @outter def home(name): time.sleep(2) print('welcome %s to home page' %name) index() home('user')
例题3:给函数加入用户认证功能。实现多种方式认证。3层闭包函数应用
import time current_user={'login':False} def auth(engine): def outter(func): def wrapper(*args,**kwargs): if current_user['login']: return func(*args, **kwargs) user = input("username>>>: ").strip() pwd = input("password>>>: ").strip() if engine == 'file': if user == 'user' and pwd == '123': current_user['login'] = True return func(*args,**kwargs) elif engine == 'mysql': print('基于mysql数据库的认证') elif engine == 'ldap': print('基于ldap的认证方式') return wrapper return outter @auth('mysql') def index(): time.sleep(1) print('welcome to index') return 1234 @auth('ldap') def home(name): time.sleep(2) print('welcome %s to home page' %name) index() home('user')
九、递归函数
1)函数递归调用的意义
1 函数的递归调用? 指的是在调用一个函数的过程中,又直接或者间接地调用该函数本身,称之为函数的递归调用 2、递归应该分为两个明确的阶段:回溯,递推 回溯,一层一层地调用下去 回溯阶段一定要有一个明确的结束条件,并且每一次回溯问题的规模都应该减少(否则就变成了单纯的重复,没有任何意义) 递推,结束当前层的调用,进而往前一层一层地结束 强调:递归的本质就是一个重复的过程,但是没进入下一次递归调用,问题的规模都应该有所减少 3、递归vs循环 递归是一个重复的过程,比起来循环的实现方式, 递归的优点是只需要把控住回溯结束的条件或者是进入下一次递归调用的条件,具体循环多少次则无需考虑
2)直接调用
import sys # print(sys.getrecursionlimit()) sys.setrecursionlimit(500) # 直接调用 def f1(n): print('from f1',n) f1(n+1) f1(1)
3)间接调用
def f1(): print('from f1') f2() def f2(): print('from f2') f1() f1()
4)递归调用简单算法
def f1(n): if n == 5: return print('from f1',n) f1(n+1) f1(1) def age(n): if n == 1: return 18 return age(n-1)+10 print(age(5))
5)循环打印列表
l=[1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,]]]]]]]]]]]] def tell(l): for item in l: if type(item) is not list: print(item) else: tell(item) tell(l)
6)递归调用二分法计算
l=[11,23,43,57,63,83,97,101,118,211,399] #该列表中的数字是按照从小到大的顺序依次排列 def search(num,l): print(l) if len(l) == 0: print('not exits') return mid_index=len(l) // 2 if num > l[mid_index]: #in the right search(num,l[mid_index+1:]) elif num < l[mid_index]: #in the left search(num,l[:mid_index]) else: print('find it') search(13,l
十、作业,实现ATM加购物车功能
1、额度 15000或自定义
2、实现购物商城,买东西加入 购物车,调用信用卡接口结账
3、可以提现,手续费5%
4、每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息
5、支持多账户登录
6、支持账户间转账
7、记录每月日常消费流水
8、提供还款接口
9、ATM记录操作日志
10、提供管理接口,包括添加账户、用户额度,冻结账户等。。。
11、用户认证用装饰器
1)单文件练习操作
info = {'Anni': {'password': '123', 'money': 10000}, 'lisi': {'password': '1234', 'money': 10000}, 'Alex Li': {'password': '12345', 'money': 10000}, 'Wxx': {'password': '123456', 'money': 10000}} product_list = [['Iphone7',5800], ['Coffee',30], ['疙瘩汤',10], ['Python Book',99], ['Bike',199], ['ViVo X9',2499], ] water_money = [] login_list = [] money_where = [] def login(): while True: user = input("请输入用户名: ") pwd = input("请输入密码: ").strip() if user in info and pwd == info[user]['password']: print('登录成功') login_list.append(user) break else: print('登录失败') def registered(): while True: user = input("请输入你要注册的账号: ").strip() pwd = input("请输入验证密码: ").strip() pwd2 = input("请再次输入验证密码: ").strip() if user not in info and pwd == pwd2: info.update({user:{'password':pwd,'money':10000}}) print('注册成功') login() break elif user in info: print("该账号已经被注册") else: print("密码错误") def check_money(): ''' 查看余额 ''' username = login_list[0] money = info[username]['money'] print("%s还有%s元"%(username,money)) def turn_meney(*args,**kwargs): ''' 转账操作 :param args: :param kwargs: :return: ''' username = login_list[0] print("你正在执行转账操作") to = input("请输入汇款人姓名: ") if to != username and to in info: change_money=input("请输入转账金额: ") if change_money.isdigit(): change_money = int(change_money) if info[username]['money'] - change_money >= 0: info[username]['money'] -= change_money info[to]['money'] += change_money print("%s向%s转%s"%(username,to,change_money)) print("%s还有%s"%(username,info[username]['money'])) money_where.append("%s向%s转%s元"%(username,to,change_money)) else: print("转账失败") else: print("正确输入") else: print("请正确输入转账人信息") def return_money(*args,**kwargs): ''' 还款 :param args: :param kwargs: :return: ''' username = login_list[0] reimbursement = 10000 - info[username]['money'] if reimbursement == 0: print("你的额度正常,不需要还款") if reimbursement > 0: remoney = input("请输入还款金额:") if remoney.isdigit(): remoney = int(remoney) if remoney <= reimbursement: info[username]['money'] += remoney print("%s的额度为%s" %(username,info[username]['money'])) money_where.append("%s还款%s元" %(username,remoney)) else: print("请正确输入") def take_money(): ''' 取钱 :return: ''' username = login_list[0] ta_money = input("请输入你的取钱金额:") if ta_money.isdigit(): ta_money = int(ta_money) if info[username]['money'] - ta_money >= 0: info[username]['money'] -= ta_money print("%s还有%s"%(username,info[username]['money'])) money_where.append("%s取款%s元"%(username,ta_money)) else: print("金额不足") else: print("请正确输入") new_shooping = [] def go_shopping(): username = login_list[0] while True: count = 0 count_list = [] for i in product_list: count += 1 print(count,'\t',i[0],'价格为',i[1]) count_list.append(count) print("q","\t","退出") shopping = input("请输入你购买的商品序号:") if not shopping.isdigit(): print("请正确输入序列号") break if shopping == 'q':break if int(shopping) in count_list: int_shopping = int(shopping)-1 shopping_money = product_list[int_shopping][1] if info[username]['money'] - shopping_money >= 0: info[username]['money'] -= shopping_money new_shooping.append([product_list[int_shopping][0],product_list[int_shopping][1]]) money_where.append("%s购买商品消费%s元"%(username,shopping_money)) else: print("余额不足") else: print("该商品不存在") def money_going(): if len(money_where) == 0: print("你的账号无流水情况") else: print("你的账号流水情况如下") for where in money_where: print(where) def shopping_list(): if len(new_shooping) == 0: print("你无任何消费") else: print("你购买的商品如下") for goods in new_shooping: print(goods[0],'价格为',goods[1],'元') print("欢迎再来") login_dic = { "1":[login,'\t登录'], "2":[registered,'\t注册'], "q":['','\t退出'] } func_dic={ "1":[check_money,'\t查看余额'], "2":[turn_meney,'\t转账'], "3":[return_money,'\t还钱'], "4":[take_money,'\t取钱'], "5":[go_shopping,'\t购物'], "6":[shopping_list,'\t购买清单'], "7":[money_going,'\t流水'], "q":['','\t退出'] } function_dic = [login_dic,func_dic] count = function_dic[0] def run2(count): print("请登录") while True: for k in count: print(k,count[k][1]) choice=input('>>>: ').strip() if choice == 'q':break if choice in count: count[choice][0]() count = function_dic[1] print("欢迎进入ATM系统") run2(count) def run(): while True: for k in login_dic: print(k,login_dic[k][1]) choice=input('>>>: ').strip() if choice == 'q':break if choice in login_dic: login_dic[choice][0]() while True: for g in func_dic: print(g, func_dic[g][1]) choice = input('>>>: ').strip() if choice == 'q': break if choice in func_dic: func_dic[choice][0]() # run()
可优化点,return返回值,参照修改
def interactive(): """接收用户输入的用户名、密码""" uname=input('username>>>: ').strip() group=input('group>>>: ').strip() pwd=input('password>>>: ').strip() return uname,group,pwd def auth(uname,group,pwd): """认证用户名与密码是否正确""" if uname == 'user' and pwd == '123' and group == 'group1': return True,uname,group else: return False,uname,group def index(res): """如果认证成功,则打印欢迎界面""" if res[0]: print('部门:%s 员工:%s 登陆成功' %(res[2],res[1])) else: print('部门:%s 员工:%s 登陆失败' % (res[2], res[1])) def run(): uname,group,pwd=interactive() # 接收用户输入,返回用户输入的信息 res=auth(uname,group,pwd) # 验证用户输入的信息 index(res) # 打印验证结果 run()
2)企业级文件操作
第一步:项目流程图 第二步:创建该有的文件夹 bin 执行文件夹 start.py 启动文件 conf 配置文件 settings.py 配置文件 lib 自定义共享库 common.py 共享的库 core 整个代码的核心逻辑 src.py 核心逻辑 db 数据相关文件 db.txt 存放的数据 log 日志 access.log 相关日志 第三步:写逻辑核心文件 src.py def run(): while True: choice = input('>>> ').strip() if choice in func_dic: pass else: pass 第四部:写执行文件,导入核心文件 import sys import os print(__file__) # abspath 有这个属性可以规范化目录 # os.path.dirname() 上一层目录 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from core import src if __name__ == '__main__': src.run() 第五步:配置文件写入各个路径,方法类似于第四步。目的,其他文件可直接利用配置文件中存在的路径 import os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DB_PATH=os.path.join(BASE_DIR,'db','db.txt') # 数据路径 LOG_PATH=os.path.join(BASE_DIR,'log','access.log') # 日志路径 data_time = time.strftime('%Y-%m-%d %H:%M:%S') # 当前时间 第六步:核心逻辑文件写入数据的操作方法 from conf import settings with open(settings.DB_PATH,'a',encoding='utf-8') as f: f.write('%s:%s\n' %(uname,pwd))