目录
1、函数定义
2、函数参数
3、作用域
4、闭包
5、装饰器
6、lambda表达式
7、生成器
8、递归
使用 def 语句来定义函数,紧跟着的是函数的名字,后面带一对小括号,冒号下面就是函数体,函数体是一个代码块,也就是每次调用函数时将被执行的内容。
>>> def myfunc(name, times):
... for i in range(times):
... print(f"I love {name}.")
...
>>> myfunc("Python", 5)
I love Python.
I love Python.
I love Python.
I love Python.
I love Python.
有时候,我们可能需要函数干完活之后能给一个反馈,这在 BIF 函数中也很常见,比如 sum() 函数会返回求和后的结果,len() 函数会返回一个元素的长度,而 list() 函数则会将参数转换为列表后返回。只需要使用 return 语句,就可以让咱们自己定制的函数实现返回。
>>> def div(x, y):
... z = x / y
... return z
...
>>> div(4, 2)
2.0
位置参数:参数位置固定,实参按照形参传递。关键字参数:指定具体值。默认参数:如果没有传入实参,就使用默认参数,如果使用默认参数把他们放在最后。
>>> def myfunc(s, vt, o):
... return "".join((o, vt, s))
...
>>> myfunc("我", "打了", "小甲鱼")
'小甲鱼打了我'
>>> myfunc("小甲鱼", "打了", "我")
'我打了小甲鱼'
#位置参数
>>> myfunc(o="我", vt="打了", s="小甲鱼")
'我打了小甲鱼'
#关键字参数
>>> myfunc(o="我","打了","小甲鱼")
SyntaxError: positional argument follows keyword argument
"""同时使用位置参数和关键字参数,要注意位置参数必须在关键字参数前"""
>>> def myfunc(s="苹果", vt, o="小甲鱼"):
SyntaxError: non-default argument follows default argument
"""使用默认参数必须放在最后面"""
>>> def myfunc(vt, s="苹果", o="小甲鱼"):
... return "".join((o, vt, s))
...
>>> myfunc("拱了")
'小甲鱼拱了苹果'
#默认参数放最后
对于只能使用位置参数的函数,我们举例子为abs()函数,例如我们使用help(abs)和help(sum)帮助文档我们可以看到函数的参数里有反斜杠。这表示反斜杠左侧必须是位置参数,不能是关键字参数,而对于反斜杠右侧就随意了。
>>> help(abs)
Help on built-in function abs in module builtins:
abs(x, /)
Return the absolute value of the argument.
>>> help(sum)
Help on built-in function sum in module builtins:
sum(iterable, /, start=0)
Return the sum of a 'start' value (default: 0) plus an iterable of numbers
When the iterable is empty, return the start value.
This function is intended specifically for use with numeric values and may
reject non-numeric types.
>>> abs(-1.5)
1.5
>>> abs(x = -1.5)
Traceback (most recent call last):
File "", line 1, in
abs(x = -1.5)
TypeError: abs() takes no keyword arguments
对于只能使用关键字参数,利用*号、参数 a 既可以是位置参数也可以是关键字参数,但参数 b 和参数 c 就必须是关键字参数。
>>> def abc(a, *, b, c):
... print(a, b, c)
>>> abc(1,2,3)
Traceback (most recent call last):
File "", line 1, in
abc(1,2,3)
TypeError: abc() takes 1 positional argument but 3 were given
>>> abc(1,b=2,c=3)
1 2 3
>>> abc(a=1,b=2,c=3)
1 2 3
收集参数:不限制参数,即在形参前面加*,形参使用叫打包,实参使用叫解包。即指定一个参数,调用的时候可以传回任意数量的参数。如果收集参数后面还有指定的其他参数,那么在调用的时候要用关键字参数来指定。收集参数也可以将参数打包成字典,做法是加两个**,对于这种情况传递参数只能用关键字参数,因为字典的键值对
def myfunc(*arge):
print("有%d个参数。"%len(arge)) #print("有{}个参数".format(len(arge)))
#print(f"有{len(arge)}个参数")
print("第二个参数是:%s"%arge[1]) #print("第二个参数是{}".format(arge[1]))
#print(f"第二个参数是{arge[1]}")
myfunc("小甲鱼","不二如是")
有2个参数。
第二个参数是:不二如是
def myfunc(*args,a,b):
print(args,a,b)
myfunc(1,2,3,a = 4,b = 5)
(1, 2, 3) 4 5
>>> def myfunc(a, *b, **c):
... print(a, b, c)
...
>>> myfunc(1, 2, 3, 4, x=5, y=6)
1 (2, 3, 4) {'x': 5, 'y': 6}
同样*和**也可以用在实参上,在实参上对应的解包。
>>> args = (1, 2, 3, 4)
>>> def myfunc(a, b, c, d):
... print(a, b, c, d)
...
>>> myfunc(*args)
1 2 3 4
>>> args = {'a':1, 'b':2, 'c':3, 'd':4}
>>> myfunc(**args)
1 2 3 4
局部作用域:一个变量定义在函数里面,作用域仅限于函数,为局部变量。
全局作用域:在任何函数外部定义的变量,作用域是全局的。
注意下面的x并非同一个变量,只是由于作用域不同,同名不同样。
>>> x = 880
>>> def myfunc():
... x = 520
... print(x)
...
>>> myfunc()
520
>>> print(x)
880
global语句:我们在函数内部无法修改全局变量的值,除非使用global语句破除限制。
>>> x = 880
>>> def myfunc():
... global x
... x = 520
... print(x)
...
>>> myfunc()
520
>>> print(x)
520
嵌套函数,想要调用内部的函数必须先通过外部的函数
>>> def funA():
... x = 520
... def funB():
... x = 880
... print("In funB, x =", x)
... funB()
... print("In funA, x =", x)
...
>>> funA()
In funB, x = 880
In funA, x = 520
nonlocal语句:通常我们无法在嵌套函数的内部修改外部函数变量的值,除非使用 nonlocal 语句破除限制:
>>> def funA():
... x = 520
... def funB():
... nonlocal x
... x = 880
... print("In funB, x =", x)
... funB()
... print("In funA, x =", x)
...
>>> funA()
In funB, x = 880
In funA, x = 880
LEGB规则:
即:局部-嵌套-全局-内置
"""在局部作用域中找到e"""
def f():
def h():
e = 3
print(f"e={e}")
h()
f()
e=3
"""在嵌套函数外的嵌套作用域中找到e"""
def f():
e = 2
def h():
print(f"e={e}")
h()
f()
e=2
"""从全局作用域中找"""
e=1
def f():
def h():
print(f"e={e}")
h()
f()
e=1
"""从内置函数中找到e"""
from math import e
def f():
def h():
print(f"e={e}")
h()
f()
e=2.718281828459045
>>> def funA():
... x = 520
... def funB():
... print(x)
... return funB
>>> funA()
.funB at 0x0000014C02684040>
>>> funA()()
520
>>> funny = funA()
>>> funny
.funB at 0x0000014C02684550>
>>> funny()
520
LEGB规则中的E,对于嵌套函数来说,外层函数的作用域是会通过某种形式保存下来,尽管函数已经调用完了,但是外层作用域的变量会保存下来,不会像局部作用域那样调用完就消失。
闭包:利用嵌套函数实现工厂的功能。
>>> def power(exp):
... def exp_of(base):
... return base ** exp
... return exp_of
...
>>> square = power(2)
>>> cube = power(3)
>>> square
.exp_of at 0x000001CF6A1FAF70>
>>> square(2)
4
>>> square(5)
25
>>> cube(2)
8
>>> cube(5)
125
exp接收的是power传入的值,然后return返回的是内部嵌套exp_of 的引用,所以可以利用这个引用进行计算,以下代码为带记忆功能的函数。利用内层函数能够记住外层函数的作用域这个特性,并且使用nonlocal语句修改外层函数作用域里面的变量。
def outer():
x = 0
y = 0
def inner(x1,y1):
nonlocal x,y
x+=x1
y+=y1
print(f"现在,X={x},Y={y}")
return inner
move = outer()
move(1,2)
现在,X=1,Y=2
move(-2,-2)
现在,X=-1,Y=0
把函数作为参数给另一个函数,类似 f 字符串,避免对之前的代码进行改动,直接外层进行添加。详细了解参照知乎抖音和小甲鱼相关介绍。
def myfunc():
print("正在调用函数")
def report(func):
print("开始调用")
func()
print("调用完毕")
report(myfunc)
开始调用
正在调用函数
调用完毕
import time
def time_master(func):
def call_func():
print("开始运行程序...")
start = time.time()
func()
stop = time.time()
print("结束程序运行...")
print(f"一共耗费了 {(stop-start):.2f} 秒。")
return call_func
@time_master
def myfunc():
time.sleep(2)
print("I love FishC.")
myfunc()
一行流表达式。传统定义的函数,函数名就是一个函数的引用,而 lambda 表达式,整个表达式就是一个函数的引用。
lambda 是一个表达式,因此它可以用在常规函数不可能存在的地方。如下y[0]是lambda表达式的函数然后小括号里面传参数。
>>> def squareX(x):
... return x * x
...
>>> squareX(3)
9
"""同上"""
>>> squareY = lambda y : y * y
>>> squareY(3)
9
>>> y = [lambda x : x * x, 2, 3]
>>> y[0](y[1])
4
>>> y[0](y[2])
9
利用map函数和filter函数,map函数第一个参数要求是一个函数的引用,第二个参数是序列类型,然后把第二个参数挨个传给第一个参数,运算之后构成一个迭代器。filter对指定的对象的每一个元素进行计算并返回结果为真的元素,回顾python-09。
>>> list(mapped = map(lambda x : ord(x) + 10, "FishC"))
[80, 115, 125, 114, 77]
>>> list(filter(lambda x : x % 2, range(10)))
[1, 3, 5, 7, 9]
让函数退出后还能保留状态,一个是全局变量(污染空间)一个是闭包(麻烦),还有生成器。
在 Python 中,使用了 yield 语句的函数被称为生成器(generator)。定义一个生成器,很简单,就是在函数中,使用 yield 表达式代替 return 语句即可。
生成器一次只下一个蛋。
>>> def counter():
... i = 0
... while i <= 5:
... yield i
... i += 1
>>> counter()
>>> for i in counter():
... print(i)
...
0
1
2
3
4
5
"""斐波那契数列"""
>>> def fib():
... back1, back2 = 0, 1
... while True:
... yield back1
... back1, back2 = back2, back1 + back2
...
>>> f = fib()
>>> next(f)
0
>>> next(f)
1
>>> next(f)
1
>>> next(f)
2
>>> next(f)
3
>>> next(f)
5
>>> next(f)
8
>>> next(f)
13
>>> next(f)
21
只要我们调用 next(f),就可以继续生成一个新的斐波那契数,由于我们在函数中没有设置结束条件,那么这样我们就得到了一个永恒的斐波那契数列生成器。
函数自己调用自己的过程。要让递归正常工作,必须要有一个结束条件,并且每次调用都将向着这个结束条件推进。
下面代码会持续输出 “AWBDYL”,直到你把 IDLE 关闭或者使用 Ctrl + c 快捷键强制中断执行。
>>> def funC():
... print("AWBDYL")
... funC()
...
>>> funC()
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
AWBDYL
...
求一个数的阶乘
"""迭代"""
>>> def factIter(n):
... result = n
... for i in range(1, n):
... result *= i
... return result
...
>>> factIter(5)
120
>>> factIter(10)
3628800
"""递归"""
>>> def factRecur(n):
... if n == 1:
... return 1
... else:
... return n * factRecur(n-1)
...
>>> factRecur(5)
120
>>> factRecur(10)
3628800
"""迭代-斐波那契数列"""
>>> def fibIter(n):
... a = 1
... b = 1
... c = 1
... while n > 2:
... c = a + b
... a = b
... b = c
... n -= 1
... return c
...
>>> fibIter(12)
144
"""递归-斐波那契数列"""
>>> def fibRecur(n):
... if n == 1 or n == 2:
... return 1
... else:
... return fibRecur(n-1) + fibRecur(n-2)
...
>>> fibRecur(12)
144
学习来源于小甲鱼教学