匿名函数与变量作用域
for i in [lambda :x for x in range(10)]:
print(i())
的结果是什么?
可以看出,[lambda :x for x in range(10)]
生成的是一个函数列表,相当于[(lambda :x) for x in range(10)]
,即对从0
到9
的每个x
生成一个不要输入参数的匿名函数,这个匿名函数返回x
。
但是这里所有的
x
都共同指向for x
的x
,而x
在for
循环最后被赋值为9
,所以最终调用匿名函数的输出都是9
。换成普通函数对照下,可以看到同样的,随着引用的变量的值的变化,函数返回值也发生了改变。
那么为什么第一张图中的头一个输入语句的输出中匿名函数的调用结果会不同呢。因为我们使用了默认参数
(x=x)
定义函数,函数里面的x
引用的就不是函数外头的那个x
了。即使外部x
发生变化也不会对函数有影响了,如下图。而默认参数的使用也是有风险的,如下图参数x
默认为一个生成器,而如果不给函数传新参,它的每次调用指向的都是同一个默认值,直到这个生成器用完抛出异常。
最后,回顾下,这个输出是不是很清楚了。
此外,python的变量作用域(影响你的变量指向的是谁)在代码执行前确定,也就是在python解释器将这段python代码编译为字节码时确定。
函数相关
-
指向函数的变量和函数本身的区别
-
函数能被存储在数据结构中
-
函数作为参数
-
函数嵌套
-
按条件返回函数(函数作为返回值)
-
函数工厂(由参数构造特定的函数并返回)
-
披着'函数'皮的'对象'
-
查看是否可调用
试验代码
# 指向函数的变量和函数本身的区别
def yell(text):
return text.upper() + '!'
yell('hello')
bark = yell
bark('woof')
del yell
yell('hello?')
bark.__name__
bark.__qualname__
# 函数能被存储在数据结构中
funcs = [bark, str.lower, str.capitalize]
funcs[0]('hey')
# 函数作为参数
def greet(func):
greeting = func('Hi, I am a Python program')
print(greeting)
def yell(text):
return text.upper() + '!'
greet(yell)
def whisper(text):
return text.lower() + '...'
greet(whisper)
list(map(yell, ['hello', 'hey', 'hi']))
# 函数嵌套
def speak(text):
def whisper(t):
return t.lower() + '...'
return whisper(text)
speak('Hello, World')
speak.whisper
# 按条件返回一个函数
def get_speak_func(volume):
def whisper(text):
return text.lower() + '...'
def yell(text):
return text.upper() + '!'
if volume > 0.5:
return yell
else:
return whisper
get_speak_func(0.3)
speak_func = get_speak_func(0.7)
speak_func('Hello')
# 函数工厂
def make_adder(n):
def add(x):
return x + n
return add
plus_3 = make_adder(3)
plus_5 = make_adder(5)
plus_3(4)
plus_5(4)
# 披着'函数'的皮的'对象'
class Adder:
'''
将一个对象的实例作为函数调用,意味着调用它的__call__方法
'''
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
plus_3 = Adder(3)
plus_3(4)
callable(plus_3)
callable(yell)
callable(False)