# 函数 ## 概念: 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。 ## 函数规则 - 函数代码块以def关键词开头,后面依次写出函数名、括号、括号中的参数和冒号。 - 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。 - 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。 - 函数内容以冒号起始,在缩进块中编写函数体。 - return 表达式结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。 - 只要有return 表达式后面的代码都不会再执行。 ## 语法 Python 定义函数使用 def 关键字,一般格式如下: ![img](https://pic3.zhimg.com/80/v2-0ea426004830a893b4afc4612e85fde6_720w.jpg) ## 参数 ### 必须参数 必需参数必须传入函数。调用时的数量必须和声明时的一样。 ![img](https://pic2.zhimg.com/80/v2-2df6ddb648e6b5029fd98579901438d9_720w.jpg) 如果不传参数,会报错。门需要钥匙开门,没带钥匙怎么可以打开。 ![img](https://pic3.zhimg.com/80/v2-734118bd3180bd7a59fac6a813d37596_720w.jpg) ### 默认参数 调用函数时,如果没有传递参数,则会使用默认参数。 ![img](https://pic2.zhimg.com/80/v2-b802fbdfd709e8f81fbbad2acbb627ad_720w.jpg) 输出结果:参数num,str='求平方的值',调用函数只传一个参数5,其实程序自己把默认值str='求平方的值'也传入了,我们看不到而已。 ![img](https://pic3.zhimg.com/80/v2-7545dca5a742e43d49d6fb4813876f46_720w.jpg) **调用函数时,修改默认值**。 ![img](https://pic4.zhimg.com/80/v2-27d213eefef17acc2eeb46fa7df3e777_720w.jpg) 输出结果: ![img](https://pic2.zhimg.com/80/v2-8d2034f68c01db5f35fd137cf230d60d_720w.jpg) ### 不定长参 定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。 > **加了星号\*的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。** 如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。 ![img](https://pic2.zhimg.com/80/v2-b9c474ccb4870411022a544f9da23b15_720w.jpg) 输出结果: ![img](https://pic2.zhimg.com/80/v2-9b9f3998cf17073a21f4cd50872b8c85_720w.jpg) 传入多个参数输出结果: ![img](https://pic4.zhimg.com/80/v2-f3bc1b80f435774e6627da74d2c81c63_720w.jpg) 函数一个必须参数和一个可变的元组参数。传入3个参数减去一个必须参数,剩下的2个参数都放到可变的元组参数中,所以不定长参数有两个元素。 ![img](https://pic3.zhimg.com/80/v2-902384999ebd5794e5177e9aff9bcd06_720w.jpg) > **加了两个星号\**的参数会以字典的形式导入。** 如果在函数调用时没有指定参数,它就是一个空字典。我们也可以不向函数传递未命名的变量。 ![img](https://pic3.zhimg.com/80/v2-1d3848c3e4335ebbdde88c8825ab7dae_720w.jpg) 输出结果: ![img](https://pic1.zhimg.com/80/v2-b53ef43d4255b5156c6b508f71538cac_720w.jpg) 传入参数输出结果: ![img](https://pic2.zhimg.com/80/v2-007d4e04576ddc680fdc7ef026522f31_720w.jpg) 两个星号**的参数会把赋值形式的参数变为字典形式。 ![img](https://pic1.zhimg.com/80/v2-c3c6941fc7e7f3591060b4981103153c_720w.jpg) ### 匿名函数 所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。 - lambda 只是一个表达式,函数体比 def 简单很多。 - lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。 > **lambda 函数的语法只包含一个语句:** ![img](https://pic4.zhimg.com/80/v2-dd248e23ede0028953df3f75a12e1bc7_720w.jpg) ![img](https://pic1.zhimg.com/80/v2-8e46daf58100497b9fa0a77d5d692a24_720w.jpg) --- # 回调函数是什么: ![img](https://pic4.zhimg.com/80/v2-9ec652f31e47eb98b7106a0c450d9c0f_720w.jpg) ![img](https://pic3.zhimg.com/80/v2-11c6c5e6e8ecfe975a4b3fff41b7a312_720w.jpg) 在Python中,已经没有指针这个说法了,一般都是说函数名。简单来说就是定义一个函数,然后将这个函数的函数名传递给另一个函数做参数,以这个参数命名的函数就是回调函数。 ```python3 def my_callbcak(args): print(*args) def caller(args, func): func(args) caller((1,2), my_callbcak) 结果: # 1 2 ``` 其中:my_callback是回调函数,因为它作为参数传递给了caller **延伸:** 带额外状态信息的回调函数,这里讲下异步处理有关的回调函数 ```python def apply_ascyn(func, args, callback): result = func(*args) callback(result) def add(x, y): return x + y def print_result(result): print(result) apply_ascyn(add, (2, 3), callback=print_result) 结果: 5 ``` 这里带额外信息的回调函数是print_result。 注意:这里print_result只能接收一个result的参数,不能传入其他信息。当想让回调函数访问其他变量或者特定环境的变量值的时候会遇到问题。 解决办法: 1、为了让回调函数访问外部信息,使用一个绑定方法来代替这个简单函数。 ```python3 def appy_async(func, args, *, callback): result = func(*args) callback(result) def add(x ,y): return x + y class ResultHandler(object): def __init__(self): self.sequence = 0 def handle(self, result): self.sequence += 1 print("[{}] Got: {}".format(self.sequence, result)) r = ResultHandler() appy_async(add, (2,3), callback=r.handle) 结果: [1] Got: 5 ``` 2、使用闭包代替上面的类来实现 ```python3 def apply_async(func, args, *, callback): result = func(*args) callback(result) def add(x ,y): return x + y def make_handler(): sequence = 0 def handler(result): nonlocal sequence sequence += 1 print("[{}] Got:{}".format(sequence, result)) return handler handler = make_handler() apply_async(add, (2,3), callback=handler) 结果: [1] Got:5 ``` 3、使用协程 ```python3 def apply_async(func, args, *, callback): result = func(*args) callback(result) def add(x, y): return x + y def make_handler(): sequence = 0 while True: result = yield sequence += 1 print("[{}] Got:{}".format(sequence, result)) handle = make_handler() next(handle) apply_async(add, (2,3), callback=handle.send) 结果: [1] Got:5 ``` # 上下文 **Flask** 项目中有两个上下文,一个是应用上下文(app),另外一个是请求上下文(request)。请求上下文 **request** 和 应用上下文 **current_app** 都是一个[全局变量](https://so.csdn.net/so/search?q=全局变量&spm=1001.2101.3001.7020),所有请求都共享的。 例子: 创建一个工具文件,进一步理解 “所有请求共享全局变量 **current_app**”。 Utils.py ```python utils.py def log_a(username): print("log a %s" % username) def log_b(username): print("log b %s" % username) ``` 1 index.py ```python from utils import log_a,log_b @app.route("/") def index(): username = session.get('username') log_a(username) log_b(username) return "这是首页" ``` ## 使用 g 对象实现 utils.py ```python from flask import g # 不需参数 def log_a(): print("log a %s" % g.username) def log_b(): print("log b %s" % g.username) ``` index.py ```python @app.route("/") def index(): username = session.get('username') g.username = username # 不需传参 log_a() log_b() return "这是首页" ```