python中函数的定义和使用。
1、函数的分类
python的函数大致可以分三类:内建函数、三方函数、自定义函数。
2、函数的基本使用
- 2.1、函数的定义
语法:def func(): 函数体
- 2.2、函数的调用
func()
3、函数的参数
-
3.1、单个参数
def test(num): print(num ** 2) test(3)
-
3.2、多个参数
语法:def func(参数1, 参数2, 参数3, ...): 函数体
示例:
# 两个参数 def my_sum(a, b): print(a + b) my_sum(2, 3) # 关键字传参 my_sum(b=1, a=5)
-
3.3、不定长参数
- 3.3.1、通过参数前加
*
指明传递的参数在函数体中以元组
的方式使用
语法:
def 函数名(*args): 函数体以元组方式使用args
示例:
def my_sum(*args): sum = 0 for v in args: sum += v print(sum) my_sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- 3.3.2、通过参数前加
**
指明传递的参数在函数体中以字典
的方式使用
语法:
def 函数名(**args): 函数体以字典方式使用args # 使用 函数名(名称1=值1, 名称2=值2, ...)
示例:
def my_sum(**args): print(args) my_sum(name="sz", age=12)
- 3.3.3、参数拆包
元组方式:
def test(*args): # 装包 print(args) # 拆包 print(*args) test(1, 2, 3, 4)
字典方式:
def my_sum(a, b): print(a, b) def test(**args): # 装包 print(args) # 拆包 my_sum(**args) test(a=1, b=2)
- 3.3.1、通过参数前加
-
3.4、缺省参数
语法:def 函数名(形参1=默认值1, 形参2=默认值2, ...): 函数体中,即使没有传递参数,也会使用默认值正常运行
示例:
def my_sum(a=1, b=2): print(a + b) my_sum()
-
3.5、注意
1、在python中参数的传递只有引用传递,没有值传递。
2、如果参数值的数据类型是可变类型,则在函数体中可以改变原件;如果数据类型是不可变类型,在函数体中不会改变原件,如果执行改变操作,则会重新分配空间,原值不会发生任何变化。
4、函数的返回值
- 语法:
def 函数(): 函数体 return 返回值
- 示例:
# 返回一个值 def my_sum(a, b): return (a + b) print(my_sum(1, 3)) print(my_sum("abc", "def")) # 返回多个值 def calculate(a, b): sum = a + b diff = a -b return (sum, diff) print(calculate(1, 3))
5、偏函数
-
5.1、概念
新建一个函数,将部分参数设为默认值来调用旧函数,用于简化函数调用。 -
5.2、创建方法
- 1、手动创建
def test(a, b, c, d=1): print(a + b + c + d) # 手动创建test的偏函数test2 def test2(a, b, c=1, d=2): test(a, b, c, d) test2(1, 2)
- 2、使用内置模块创建偏函数
def test(a, b, c, d=1): print(a + b + c + d) import functools new_func = functools.partial(test, c=1, d=2) new_func(1, 2)
6、高阶函数
- 6.1、概念
当一个函数A的参数,接收的又是另一个函数时,则把这个函数A称为是高阶函数。 - 6.2、示例
- 示例1
def getkey(x): return x["age"] l = [{"name":"as", "age": 15}, {"name":"sd", "age": 16}, {"name":"df", "age": 19}] result = sorted(l, key=getkey) print(result)
- 示例2
def calculate(a, b, func): print(func(a, b)) def sum(a, b): return a + b def diff(a, b): return a - b calculate(6, 3, sum) calculate(6, 3, diff)
7、返回函数
- 7.1、概念
一个函数内部返回的数据是另外一个函数,把这样的操作称为返回函数。 - 7.2、示例
def get_func(f): def sum(a, b, c): return a + b + c def diff(a, b, c): return a - b - c if(f == "+"): return sum elif(f == "-"): return diff r = get_func("+")(1, 2, 3) print(r) r = get_func("-")(1, 2, 3) print(r)
8、匿名函数
- 8.1、概念
匿名函数也称为"lambda函数"
,就是指没有名字的函数。 - 8.1、语法
说明:lambda 参数1,参数2,... : 表达式
- 只能写一个表达式, 不能return;
- 表达式的结果就是返回值;
- 适用于一些简单的操作处理;
- 8.3、示例
示例1:
示例2:r = (lambda a, b : a + b)(3, 2) print(r) func = lambda a, b : a + b print(func(4, 3))
l = [{"name":"as", "age": 15}, {"name":"sd", "age": 16}, {"name":"df", "age": 19}] result = sorted(l, key=lambda x : x["age"]) print(result)
9、闭包
-
9.1、概念
在函数嵌套的前提下,内层函数引用了外层函数的变量,外层函数又把内层函数当作返回值进行返回。这个内层函数和所引用的外层变量,称为闭包。 -
9.2、语法
def test(): a = 10 def test2(): print(a) return test2 func = test() func()
-
9.3、示例
def line_config(content, length): def draw_line(): print("-" * (length // 2) + content + "-" * (length // 2)) return draw_line line_config("闭包", 20)() line_config("test", 20)()
-
9.4、注意事项
1、闭包中,如果要修改引用的外层变量,需要使用nonlocal变量声明,否则当作是闭包内新定义的变量
2、当闭包内,引用了一个后期会发生变化的变量时,一定要注意值的变化
10、装饰器
-
10.1、作用
在函数名及函数体不改变的前提下,给函数附加一些额外的代码。 -
10.2、语法
def prepare(func): def pre(): print("prepare") func() print("done") return pre @prepare def do_something(): print("doing") do_something()
上述代码等同于下面的闭包实现:
def prepare(func): def pre(): print("prepare") func() print("done") return pre def do_something(): print("doing") do_something = prepare(do_something) do_something()
-
10.3、注意事项
装饰器函数的执行时间是立即执行,也就是在@
语句时,已经执行了。 -
10.4、装饰器的叠加
叠加规则: 从上到下装饰,从下到上执行。def prepare(func): def pre(): print("prepare") func() return pre def prepare1(func): def pre(): print("prepare 1") func() return pre def finish(func): def pre(): func() print("done") return pre @prepare @prepare1 @finish def do_something(): print("doing") do_something()
-
10.5、对有参函数进行装饰
def prepare(func): def pre(*args, **kargs): print("prepare") # print(args, kargs) func(*args, **kargs) return pre @prepare def pnum(a): print(a) @prepare def pnum2(a, b): print(a, b) pnum(10) pnum2(10, 11)
-
10.6、对有返回值函数进行装饰
def prepare(func): def pre(*args, **kargs): print("prepare") # print(args, kargs) return func(*args, **kargs) return pre @prepare def pnum(a): return a @prepare def pnum2(a, b): return a, b print(pnum(10)) print(pnum2(10, 11))
-
10.7、带有参数的装饰器
- 实现方法:
1、通过@装饰器(参数)
的方式,调用这个函数,并传递参数;并把返回值再次当作装饰器使用。
2、先计算@后面的内容,把这个内容当做是装饰器。 - 示例:
def get_prepare(num): def prepare(func): def pre(*args, **kargs): print("prepare", num) return func(*args, **kargs) return pre return prepare @get_prepare(100) def pnum(a): return a print(pnum(10))
- 实现方法:
11、生成器
- 11.1、概念
生成器是一个特殊的迭代器(迭代器的抽象层级更高)。 - 11.2、创建方式
- (1)、生成器表达式:
把列表推导式的[]修改为():
l = (i for i in range(1, 100) if i % 2 == 0) print(l) print(next(l)) print(l.__next__())
- (2)、生成器函数
- 函数中包含yield语句,这个函数的执行结果就是生成器。
- yield可以去阻断当前的函数执行,当执行next()函数时会让函数继续执行,当执行下一个yield语句的时候又会被暂停。
def test(): print("start") yield 1 print("a") yield 2 print("b") yield 2 print("c") g = test() print(g) print(next(g))
- (1)、生成器表达式:
- 11.3、send()函数
send()方法有一个参数,指定的是上一次被挂起的yield语句的返回值。相比于.next(),可以额外的给yield语句传值。第一次调用时,需使用g.send(None)。def test(): print("start") for i in range(1, 10): ret = yield i print(i, ret) g = test() g.send(None) g.send("a") g.send("b") g.send("c")
- 11.4、close()函数
后续如果继续调用,会抛出StopIteration异常def test(): yield 1 print("a") yield 2 print("b") yield 3 print("c") g = test() print(g.__next__()) print(g.__next__()) print(g.__next__()) g.close()
12、作用域
-
12.1、变量作用域
变量作用域指的是变量的作用范围,可操作范围。
python是静态作用域,也就是在python中,变量的作用域源于它在代码中的位置。在不同的位置,可能有不同的命名空间。 -
12.2、命名空间
命名空间是作用域的体现形式,不同的具体的操作范围。 -
12.3、python-LEGB
L-Local
: 函数内的命名空间就。作用范围:当前整个函数体范围;
E-Enclosing function locals
: 外部嵌套函数命名空间。作用范围:闭包函数;
G-Global
: 全局命名空间。作用范围:当前模块(文件);
B-Builtin
: 内建模块命名空间。作用范围:所有模块(文件);LEGB规则: 按照 L -> E -> G -> B 的顺序进行查找。
-
12.4、局部区域修改全局变量
需要在局部区域中,将全局变量前加global
。