Published in:2024-10-24 |

函数(二)

一、变量的作用域

回顾:作用域泄露 (在C和C++不存在这个问题)

1
2
3
4
5
6
7
a = 3
b = 5
if a > b:
max = a # ‘局部变量’:理论上代码块结束,max就会被释放,但是Python中并不释放bug
else:
max = b
print(f"{a}{b}中的最大值为:{max}")
1、全局变量
  • 定义:定义在文件的顶头部分,没有任何的缩进
  • 作用域/作用范围:从定义的位置开始到整个文件的结尾
1
2
3
4
5
6
7
# hello.py
a = 5
b = 10 # 全局变量
def f():
print(a,b)

f()
2、局部变量
  • 定义:在函数内部定义的变量
  • 作用域/作用范围:从函数内定义变量的位置开始到函数结束
1
2
3
4
5
6
7
def f():
a = 10
print(a) # 作用范围/可见范围:函数体的内部


f()
print(a) # NameError: name 'a' is not defined 不会发生作用域泄露
3、局部变量和全局变量同名
1
2
3
4
5
6
7
a = 100   # 全局变量
def f():
a = 200 # 这里又定义了一个变量:局部变量 和全局变量同名
print('1111',a) # -> 200

f()
print('2222',a) # -> 100

如果全局变量与局部变量同名,则局部作用域下去访问变量时,访问到是局部变量,此时局部变量量体裁衣隐藏全局变量的值。

二、global和nonlocal

1、global关键字
  • 如何在函数体内修改/访问全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 在函数体内直接访问全局变量(未定义同名局部变量),没问题
g = 100
def f():
print(g)
f() # ->100


# 2. 在函数体内直接赋值
g = 100
def f():
g = 200 # 重新定义了一个局部变量,并不是修改了全局变量
f()
print(g) # ->100


# 3. 在函数体内修改全局变量
g = 100
def f():
g += 1 # 出错 程序会认为你是在修改局部变量g 而g未初始化
f()

如何解决上述的问题3:

1
2
3
4
5
6
7
8
# 想在函数体内去修改全局变量g 

g = 100
def f():
global g # 告诉解释器,这里是要引用全局变量
g += 1
f()
print(g) # -> 101

2、nonlocal关键字

1
2
3
4
5
6
7
8
9
10
a = 100
def func1():
a = 200
def func2(): # inner函数
a = 300
func2()
print(a) # -> 200

func1()
print(a) # -> 100
  • 如果要在func2中修改全局变量a:
1
2
3
4
5
6
7
8
9
10
11
12
a = 100

def func1():
a = 200
def func2(): # inner函数
global a
a = 300
func2()
print(a) # -> 200

func1()
print(a) # -> 300
  • 如果要在func2中修改func1中声明的局部变量a:
1
2
3
4
5
6
7
8
9
10
11
a = 100
def func1():
a = 200
def func2(): # inner函数
nonlocal a
a = 300
func2()
print(a) # -> 300

func1()
print(a) # -> 100

nonlocal是修改外层函数中的局部变量,在下一层的作用域中去引用上一层中的局部变量

三、lambda表达式

  • 什么是lambda表达式

    lambda表达式,又称为匿名函数,是现代各种编程语言争相引入的一种语法,其功能堪比函数,设计却比函数更简洁.

  • 基本形式:

    lambda 参数列表:表达式

  • 说明:

    在lambda关键字之后,冒号左右是参数列表,参数之间使用,号分隔,冒号右边为lambda表达式的返回值(不需要写return)。

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 等号右边声明的是一个匿名函数
    # 将匿名函数赋值给了add
    add = lambda x,y:x+y

    print(add(3,5))


    def f(x,y):
    return x+y
    add = f
    1
    2
    3
    4
    5
    总结:
    1. 一般用于构建匿名函数
    2. lambda书写形式更加简洁、优雅
    3. lambda表达式不能过于复杂
    4. 优先级比较低

四、闭包

在一个外函数中定义了一个内函数(内嵌函数),内函数里运用了外函数的临时变量(局部变量),并且外函数的返回值是内函数(的引用)。这样就形成了闭包closure

1
2
3
4
5
6
7
8
9
10
def outer(x):
y = 10

def inner():
print(x+y)

return inner

f = outer(5)
f()
  • 闭包的条件
1
2
3
# 1. 必须是一个内嵌函数
# 2. 内函数引用外函数中的局部变量
# 3. 外函数要返回内函数本身
1
2
3
闭包特点:
- 开辟独立的空间
- 应用:装饰器
  • 临时变量不销毁现象

当外函数调用完毕,理论来说外函数中定义的局部变量应该被释放,但是闭包中,当外函数发现内函数持有我的局部变量时,该局部变量就不会被销毁。

  • 闭包的延时绑定
1
2
3
4
5
6
7
8
9
10
11
12
def fun():
l = []
for i in range(3):
def fun2(x):
print(x+i)
l.append(fun2)
return l

for i in fun():
i(2) # 4 4 4 而不是2 3 4

# 根据延迟绑定,只有当调用内部函数时,才会访问到闭包变量(外函数的临时变量i),而此时i已经变成2了
1
2
3
4
def fun():
return [lambda x:i*x for i in range(4)]

print([m(2) for m in fun()]) # [6, 6, 6, 6]

五、高级函数

Python2中是内置函数,而3中是类

  • filter()

    1
    2
    3
    4
    5
    6
    7
    8
    # 原型:filter(function or None, iterable) --> filter object
    1. 过滤掉iterable中为False的元素,保留为真的元素
    2. 返回的是一个filter对象,是可以迭代
    3. 第一个参数:可以是一个函数/匿名函数,也可以是None
    4. 第二个参数:
    如果第一个参数是None值,则返回iterable中元素为True的值
    如果第一个参数是函数,则它会将iterable中的每一个元素作为参数传递给函数,返回为真的元素
    5. 第一个参数为函数时,函数的返回值必须为bool对象
    1
    2
    3
    4
    5
    6
    # 案例一:
    f = filter(None,[0,2,3,4,5,0]) # 返回的是一个filter对象
    print(f) # 可迭代对象
    print(list(f)) # 转为list

    print(list(filter(None,[0,2,3,4,5,0])))
    1
    2
    3
    # 案例二:
    for i in filter(lambda x:x==0,[0,2,3,4,5,0]):
    print(i) # 0 0
    1
    2
    3
    4
    5
    6
    7
    8
    # 案例三:
    def f(x):
    return x % 2

    for i in filter(f,[0,2,3,4,5,0]):
    print(i) # 3 5

    for i in filter(lambda x:x%2,[0,2,3,4,5,0]):
  • map()

    1
    2
    3
    4
    map : 映射
    # 原型:map(func, *iterables) --> map object
    1. 将可变长参数(可迭代对象)每一个元素,进行两两对应后,通过第一个参数func进行计算,直到每一个元素计算完毕,返回map对象(可迭代对象)
    2. 多个迭代对象,以短的为准
    1
    2
    print(list(map(lambda x,y:x+y,[1,2,3],[4,5,6])))
    # [5, 7, 9]
  • reduce()

    1
    2
    3
    4
    reduce:减少 折叠
    python3: import functools
    # 原型:reduce(function, sequence[, initial]) -> value
    1. 将序列中的每一个元素进行计算,将序列中的两两数据作为function的参数,然后将前两个的计算结果再加上第三个数据...最终得到一个结果
    1
    2
    3
    4
    5
    6
    import functools

    result = functools.reduce(lambda x,y:x+y,range(1,101))
    print(result) # 5050

    # sum(range(1,101))
    1
    2
    3
    import functools
    result = functools.reduce(lambda x,y:x*y,range(1,6))
    print(result) # 求阶乘
    1
    2
    3
    4
    5
    import functools
    def factorial(n):
    return functools.reduce(lambda x,y:x*y,range(1,n+1))

    print(factorial(5))
Prev:
Next: