欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python学习笔记:1.4.3 嵌套函数和装饰器

程序员文章站 2024-01-15 19:51:40
...

本文是学习齐老师的《python全栈工程师》课程的笔记,欢迎学习交流。同时感谢齐老师的精彩传授!

一、课程目标
  • 初步理解函数是对象思想
  • 掌握嵌套函数的编写方法
  • 理解变量作用域
  • 了解简单的装饰器及其用法
二、详情解读

1.函数是对象:

  • 比较函数和字符串的各种表现
    Python学习笔记:1.4.3 嵌套函数和装饰器
    例子:
# 函数也可以作为参数所引用的对象,传给另外一个函数。
def opt(func, iterable):
	return [func(i) for i in iterable]
lst = opt(abs, [-1, -2, -3])
print(lst) # [1, 2, 3]

2.嵌套函数:

  • 返回函数将函数作为返回值,可以返回内置函数对象,也可以返回自定义函数对象。

例子:

def my_func(bf):
	return bf
# 返回内置函数对象 abs
mabs = my_func(abs)
print(abs is mabs) # True 因为它们指向同一个函数对象
print(mabs(-3)) # 3 相当于 abs(-3),

def add(x, y): return x + y
# 返回自定义函数对象
madd = my_func(add)
print(id(madd) == id(add)) # True 等同于 madd is add
print(madd(1,2) # 3
  • 函数体内定义另外一个函数:内嵌的函数不会随着外层函数调用而被执行,它也不能在外层函数所在的空间调用,并且,嵌套函数返回内嵌的函数对象,否则内嵌函数无法被调用

例子:

def foo():
	def bar():
		print('I am in bar')
	print('I am in foo.')
foo() # I am in foo.
bar() # 报错,外层函数没有返回内层函数,所以内层函数只能在foo函数内被调用。
def foo():
	def bar():
		print('I am in bar')
	print('I am in foo.')
	return bar # 注意,这里不加括号!用bar即可,不用bar()
b = foo()
b() # I am in foo. I am in bar.

3.变量作用域:
作用域指的是变量的有效范围,作用域分为函数内部的局部(本地)作用域全局作用域内置作用域。嵌套函数内、嵌套函数之外但在外层函数之内的属于函数内部的局部(本地)作用域。

x = 2000 # 全局作用域
def foo():
	x = 1 # 函数内部的局部(本地)作用域
	def bar():
		y = 2 # 函数内部的局部(本地)作用域
	return bar

内置作用域:下面这些内置函数都属于内置作用域范围
Python学习笔记:1.4.3 嵌套函数和装饰器注意: 全局作用域的变量不能和内置作用域的变量冲突,否则会覆盖掉内置作用域的变量
Python学习笔记:1.4.3 嵌套函数和装饰器
4.划分作用域:
根据代码结构划分不同级别的作用域:(块级)、函数、类、模块、包。Python中,if语句块、for语句块、with上下文管理器等等不能划分变量作用域。函数和类改变作用域:def、class、lambda

if True:
	x = 1
print(x) # 1 因为if语句不能划分作用域,此时x变量是全局变量

def func(): a = 8
print(a) # 报错 因为a在函数func内,属于局部作用域,外部无法调用

5.python解析器搜索变量的规则:

  • 从内向外,逐层搜索,找到则停止。
    Python学习笔记:1.4.3 嵌套函数和装饰器
  • 作用域取决于代码块在整体代码中的位置,例如函数代码块的位置,而与函数调用的位置无关

6.变量掩盖和修改:

  • 如果在函数内部引用了一个和全局变量同名的变量,且不是重新赋值,那函数内部引用的是全局变量。
  • 如果函数内部重新赋值了一个和全局变量名称相同的变量,则这个变量是局部变量,它会掩盖全局变量。
x = 3
def g(): print(x)
g() # 3

def g2(): 
	x = 2
	print(x) # 此时的 x 覆盖了全局变量中的 x 
g() # 2
print(x) # 3  这里的x 是全局变量中的 x

两个关键词:

- global: 指定当前变量使用外部的全局变量。
- nonlocal: 内层函数中的变量使用它外一层函数的变量。
– global修饰的变量可能事先并未存在于全局作用域内,但nonlocal修饰的变量必须已经存在于外层函数,不能只存在于全局。

例子:

x = 1
def foo():
	x += 2
	print(x)
foo() # 报错 函数中的 x += 2,而在函数内 x 并未声明,如果想引用全局变量,必须在函数内用global关键字声明x

# 比如下面这个例子:是正确。
y = 2
def bar():
	global y
	y += 3
	print(y)
bar() # 5 
x = 4 
def foo():
	x = 5
	def bar():
		y = 6
		print(x, y)
	return bar
b = foo() 
b() # 5 6
------------------
x = 6
def foo():
	x = 4
	def bar():
		x = x + 1  # 此处的 x 被重新赋值,所以它是bar函数里的局部变量,而在函数 bar 内并未声明 x
		print(x)
	return bar
b = foo() 
b() # 报错 

# 下面的例子是正确的
x = 6
def foo():
	x = 4
	def bar():
		# 在局部中声明变量 x,这里x=4,当在嵌套函数中想引用外层函数的变量时用nonlocal
		# 此处如果改为 global x,则x引用的是全局变量x=6
		nonlocal x  
		x = x + 1  
		print(x)
	return bar
b = foo()
b() # 5

7.例题讲解:

例题1:

  • 利用嵌套函数,编写实现”一元二次函数“的程序

老师参考:

def parabola(a, b, c):
	def para(x):
		return a * x**2 + b * x + c
	return para
y = parabola(2, 3, 4)
r = y(3)
print('y = 2x^2 + 3x + 4 | x = 3, the result = {0}'.format(r))

运行效果图:
Python学习笔记:1.4.3 嵌套函数和装饰器
8.简单的装饰器:

  • 从嵌套函数到语法糖@
  • 没有参数的装饰器
def book(name):
	return name

def strong_dec(f):
	def wrapper(name):
		return '<strong>{0}</strong>'.format(f(name))
	return wrapper
my = strong_dec(book)
book = my('Learn Python')
print(book)

# 下面用语法糖 @ 符号
def strong_dec(f):
	def wrapper(name):
		return '<strong>{0}</strong>'.format(f(name))
	return wrapper
# my = strong_dec(book)
# book = my('Learn Python')
@strong_dec
def book(name):
	return name
b = book('Learn Python')
print(b)

例题2:

  • 编写一个用于测试函数执行时间的装饰器
def timing_func(func):
    def wrapper():
        start = time.time()
        func()
        stop = time.time()
        return (stop - start)
    return wrapper

@timing_func
def test_list_append():
    lst = []
    for i in range(1, 100000):
        lst.append(i)
        
@timing_func
def test_list_compre():
    [i for i in range(0, 100000)]

a = test_list_append()
print(a)
b = test_list_compre()
print(b)

# tip: 这个例子告诉我们,列表推导式比for循环运行速度快。		
# 至于为什么,请参考这篇文章:
# 《为什么列表推导式会更快》(https://blog.csdn.net/sinat_38682860/article/details/85159505)

运行效果图:
Python学习笔记:1.4.3 嵌套函数和装饰器

三、课程小结
  • 了解了函数是对象
  • 学习了函数和变量的作用域
  • 学习了嵌套函数
  • 学习了简单的装饰器
四、作业
  • 在字典中有 get 方法,但是列表中没有。编写函数,对列表实现类似字典中get方法的功能。

小编参考:

# 待定。。。小编还在思考中。。。>_<