第八章 函数

 

       - 具有特定功能的代码块

       - 意义:①简化代码重复率

                     ②功能模块化

一. 内置函数

       用法: 函数名[参数]

       返回: seq / None

       print, abs,

二、自定义函数

1. 语法格式

       def 函数名([参数]):

              函数体

              [pass 为占位符]

              [return 返回值]

      

2. 参数使用

       --- 函数的参数只在定义时创建一次,之后再次调用函数,不会给变量新创建内存

(1) 位置参数(必须参数)

       --- 一旦定义,除默认参数必须按照顺序传入,位置固定

       > 位置参数必须放在最前面

      

(2) 默认参数

       --- 给参数赋予默认值,如果不传入,使用默认值

       > 默认形式参数不要使用可变类型,否则重复调时,默认值会被修改

      

(3) 命名关键字参数 - *,

       def 函数名(*, 参数名, 参数名...):

              #'*,',关键字参数和命名关键字参数的传参,必须通过【参数名= 参数值】形式传入

       > 调用

              ①只能【参数名= 参数值】形式传入

              ②顺序不需要固定

       > 优点

              ① 增加程序可读性

              ② 忽略参数的作用

              ③ 当参数有默认值时,等同于默认参数

              ④ 除了指定默认值,必须传入参数

(4) 可变参数 - * args

       --- 用来收集所用的位置参数,打包成一个元组

       def 函数名(* args):

       > args 为元组,因为可变参数函数定义时,可以把零散位置参数打包成元组

       > 对于元组或者列表(args或者自定义传入值),应该使用“*”解包

 

(5) 关键字参数 - ** kwargs

       --- 把命名关键字打包成字典

       def 函数名(** kwargs):

 

(6) 万能参数

              * arg, ** kwargs

注意:

       (1) 位置参数必须在最前面

       (2) 命名关键字参数不能和可变参数放在一起

       (3) 优先顺序:

              位置参数 > 默认参数 > 命名关键字参数 / 可变参数 > 关键字参数

      

       def fu1(a,b,c=0,*args, **kwargs):

       >>> 前三个参数被赋值给abc,多余葡萄普通参数传入args,输入关键字参数,传入kwargs

       def fu2(a,b,c=0,*,d, **kwargs):

       如果有d,关键字参数优先传入d,其他关键字优先传入kwargs

      

3. 返回值

       > return语句的执行,代表函数的结束

       > 返回值只能有一个,如果需要多个值,可以以元组返回;

       > 以下返回值为None

       (1) return

       (2) reutrn None

       (3) 不写

       > 函数最好传入和返回值都使用元组等不可变类型

      

4. 函数中的值传递

       > 不可变类型的值传递

              --- 形参指向传入的实参对象,修改创建新对象,两者互不影响

       > 可变类型的值传递

              --- 形参指向传入的实参对象,直接修改对象,函数对实参发生影响

 

5. 命名空间和作用域

<1> 命名空间

     (1) 概念

       命名空间 : 可以保存名字的容器

                            > 包括:变量名、函数名、类名

                            > 命名空间中,名字以key-value字典结构存储,其中key为变量名,value为内存地址

                            > 每一种命名空间都有固定区域

       对于函数:

              第一次def时,构建命名空间

       对于变量:

              第一次赋值时,构建命名空间

     (2) 分类

       ① 内建命名空间

              --- python解释器启动的时候创建,解释器关闭时销毁

                     如: sum, print

       ② 全局命名空间

              --- 读取模块定义的时候创建,程序运行结束,空间销毁

                     如: 全局变量,顶层函数

       ③ 局部命名空间

              --- 在函数创建时创建,函数执行结束时销毁

                     如: 局部变量,形式参数, 嵌套函数

       注意: 命名空间不存在包含关系,只存在生命周期,或者说作用域不同。

      

       > 各命名空间创建顺序:

         python解释器启动 ->创建内建命名空间 -> 加载模块 -> 创建全局命名空间 ->函数被调用 ->创建局部命名空间

       > 各命名空间销毁顺序:

         函数调用结束 -> 销毁函数对应的局部命名空间 -> python虚拟机(解释器)退出 ->销毁全局命名空间 ->销毁内建命名空间

      

<2> 作用域

       --- 命名空间中的名字起作用的范围

              ① 内建命名空间 --- 整个运行环境所有模块

              ② 全局命名空间 --- 仅限当前py文件,使用其他py文件需导入

              ③ 局部命名空间 --- 仅限函数内部有效

       注意: 作用域不存在包含关系,只是大小不同;

                 文件名,变量名,函数名...不要用内建命名空间变量名

      

<3> 访问原则

     (1) LEGB原则

              > 作用域按照变量的定义位置可以划分为4类:.

              Local     (函数内部)               局部作用域

              Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)

              Global   (模块全局)              全局作用域

              Built-in (内建)                  内建作用域

     (2) 名称的访问

              > 读取 --- LEGB

              > 修改 --- 只从当前最小作用域查找,如果找到修改,找不到创建

                               globla, nonlocal方法可以修改

              > 删除 --- 只能删除当前命名空间名字

     (3) global nonlocal

              global   --- 局部命名空间修改全局命名空间内容

              nonlocal --- 局部命名空间修改外围命名空间内容

     (4) 显示命名空间

              local()   --- 可以显示该语句所在位置的命名空间

              global() --- 显示全局命名空间

                     


	eg.
	def f():
		k = 'asdf'
		def inner():
			nonlocal k
			k = 'qewr'
			# del k 报错,无法删除上一级命名空间
		inner()
		print(k)

 

6. lambda表达式(匿名函数)

       > 头等函数: 变量和函数类型、函数名可以被赋值、传递、和作为返回值

     

     #函数名赋值
	def hello():
		print('hello')
	hello_new = hello
	hello_new()

	# 函数名当成返回值
	def outer():
		def inner():
			print('dsaf')
		return inner
	a = outer()
	a()

	# 函数名当成值被传递
	def hello():
		print('hello')
	def k(m):
		pass
	k(hello)

   

(1) 定义

       lambda参数: 返回值表达式

(2) 使用场景

       函数体比较简单

from numpy import square
li = [1, 2, 4]
li.sort(key = lambda x: x**2)
li.sort(key = square)

7. 递归

       --- 函数调用自身

       (1) 直接递归

       (2) 间接递归

       递归一定要通过条件终止,分为递推回归两个步骤

       > 递归和循环

              1. 递归思路简单,但是效率比循环低

              2. 递归有最大深度(所有函数调用次数),default = 1000

                  最大递归次数通过sys.getrecursionlinit()获取

     

	# 斐波那契数列
	def fb(n):
		if n ==1 or n ==2:
			return 1
		else:
			return fb(n-1)+fb(n-2)

       # for斐波那契数列

       # 多维列表解包

       # 汉诺塔 - 列表

             

8. 函数注释(文档)

       --- 在函数下用三引号

       显示:

              > print(函数名.__doc)

              > help(函数名)

             

       --- 参数形式的标注

              def add(a: int, b:float)->int:

              print(函数名.__annotation__)

      

             

      

      

猜你喜欢

转载自blog.csdn.net/u010359398/article/details/81102798