一般我们都知道,函数只有在调用的时候才会被执行
但是我们在用 def 定义一个函数时,编译器做了什么?或者什么都没做?
实际上,当用 def 定义一个函数时,就创建了一个函数对象,该对象封装了函数体,并将其赋值给函数名这个变量
可以看出,定义一个函数和定义一个其他对象,基本上相同的
需要注意的是,如果我们定义函数时,在函数内部使用了一些变量,我们通常称它为局部变量或本地变量(local),此时这些变量是否分配了内存?
实际上,函数对象封装了函数体,函数体在函数没有被调用之前,是一块处女地
这些局部变量只有在函数被调用时被召唤,在函数调用完时被释放
特别注意,函数的形参也是局部变量
我杜撰的三种函数形式
1. 裸调用 func()
2. 传入参数调用 func(arg1)
3. 传入参数调用,并有返回值 =func(arg1)
实际上,python中任何函数调用都有返回值,当没有return来指定返回值时,返回值为None
func(*args, **kw) #可变参数,可接收任意个参数
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
函数的参数
1. 位置参数
2. key参数
3. 默认值参数
4. 可变参数
5. 可变参数解包
函数调用时的参数传递
a = -2.3
def pa(a):
print(a,id(a))
pa(a)
print(a,id(a))
ab = [3,4]
def pab(ab):
print(ab, id(ab))
pab(ab)
print(ab, id(ab))
#运行反馈
-2.3 5742856
-2.3 5742856
[3, 4] 7162120
[3, 4] 7162120
可以观察到,参数传递都传递的是引用,而没有在函数内部创建新的对象
很多教程对此的描述有错误
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
高阶函数(Higher-order function)
现在要讨论的是 函数的高级用法;
Python中的高阶函数起源于 函数对象可以像其他对象一样被变量(标识符)引用,变量可以指向函数
或者我们可以说,函数名就是一个指向内存中函数体的变量(不知这样描叙是否准确?)
def func(arg2):
print(arg2*5)
fc = func #变量fc指向函数func,或者说函数func赋值给fc,此时fc和func指向了同一函数体
print(func)
print(fc)
fc('b') #与使用func('b')的完全一致
func=7 #将int赋值给函数名func
print(func.__class__)
print(fc)
#运行反馈
#内存中相同的函数体(貌似fc不是直接指向,而是通过func间接指向)
#内存中相同的函数体
bbbbb
#说明函数名其实也只是一个变量
#当func移情别恋;可以看出fc是直接指向,而不是通过func间接指向
既然函数名是变量,那就应该可以像其他变量一样,
可以作为参数 传入另外一个函数,或者作为另外一个函数的返回值 返回调用处
def add(x, y, f): #函数作为参数,传入另外一个函数的栗子
return print(f(x) + f(y))
add(-5,6,abs) #给add函数传入一个内置函数abs
一个函数作为另外一个函数的返回值,隐含了,在一个函数内部定义了另一个函数,即函数的嵌套
def log(func):
def wrapper():
print("
func()
print(">")
return wrapper
@log #装饰器
def now():
print("html",end="")
now()
---------------------------上下完全等同---------------------------
def log(func):
def wrapper():
print("
func()
print(">")
return wrapper
def now():
print("html",end="")
log(now)() #装饰器实际调用过程
装饰器: 是一个函数,一个用来包装函数的函数,一个返回函数的高阶函数;
装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象
装饰器: 接收要被修饰的函数为参数,返回修饰处理闭包的嵌套函数
怎么写一个装饰器
1. 嵌套函数
2. 外层函数接收 被修饰的函数 作为参数,return内部函数
3. 内部函数中调用 作为参数被传递进来的 被装饰的函数,同时进行修饰处理
嵌套函数 外层参数接收被修饰的函数,内层参数接收被修饰函数的参数
如果修饰器本身也需要传递参数,该怎么办呢?
这就需要三层嵌套了
def countdown():
r='hello'
s=3
def next():
return r*s
return next
mx =countdown()
print(mx)
print(mx.__closure__)
print(mx.__closure__[0].cell_contents)
print(mx.__closure__[1].cell_contents)
#运行反馈
.next at 0x00000000007FE9D8>
(, )
hello
3
闭包
嵌套函数中作为外部函数返回值的内部函数,如果内部函数引用了外部函数的变量,这内部函数称为闭包
闭包的3个必要条件: 1. 有嵌套函数 2. 内部函数作为外部函数的返回值 3. 内部函数引用外部函数变量
闭包就是一个函数,只不过在函数内部带上了额外的变量环境
闭包关键特点就是它会记住自己被定义时的环境
仅仅引用了外部变量的函数,并不一定是闭包,