函数进阶


1. 名称空间的作用域

作用域:名称空间所能够作用的范围

  • 内置名称空间
    程序任何阶段,任何位置,均可使用
  • 全局名称空间
    程序任何阶段,任何位置,均可使用
  • 局部名称空间
    一般只在各自的局部名称空间中有效

2. global 与 nonlocal关键字使用

  • global关键字

    x = 111
    def index():
    	# 局部修改全局变量,需要使用关键字声明
    	global x
    	x = 222
    
    index()
    print(x)  # 222
    
    # 在局部想要修改可变类型,不需要global关键字
    name_list = ['josh', 'duke']
    def index():
    	name_list.append('kd')
    
    index()
    print(name_list)  # ['josh', 'duke', 'kd']
    

    如果:想要在局部修改全局数据

    1. 如果数据为不可变类型,则需要关键字global声明。
    2. 如果数据为可变类型,则无需关键字global声明。
  • nonlocal关键字

    def index():
    	x = 11
    	def func():
    		x = 22
    	func()
    	print(x)
    
    index()  # 11
    
    def index():
    	x = 11
    	def func():
    		# 内部局部修改外部局部
    		nonlocal x
    		x = 22
    	func()
    	print(x)
    
    index()  # 22
    

    如果:想在内部局部修改外部局部数据

    1. 如果数据为不可变类型,则需要关键字nonlocal声明。
    2. 如果数据为可变类型,则无需关键字nonlocal声明。

3. 函数对象(函数名)

函数名主要由四种用法。。

  • 用法一:函数名可以当作变量名赋值

    def index():
    	print('from index')
    
    # print(index)  # 函数名就是一个内存地址
    a = index  # a就函数名,函数名遇到括号就会调用
    a()  # from index
    # 本质就是在调用index函数
    
  • 用法二:函数名还可以当作函数的实参

    def index():
    	print('from index')
    
    def func(a):
    	print(a)
    	print('from func')
    
    func(index)
    """
    from func"""
    
  • 用法三:函数名可以当作函数的返回值

    def index():
    	print('from index')
    	return index
    
    res = func()  # 调用func并接收其返回值
    print(res)  # 函数index
    res()  # 执行函数index >>> from index
    
  • 用法四:函数名可以当作容器类型(内部可以存放多个数据)的元素

    def index():
    	print('from index')
    
    l = [1, 2, 3, index]
    print(l)
    """[11, 22, 33, ]"""
    l1 = [1, 2, 3, index()]
    print(l1)
    """from index
    [11, 22, 33, None]"""
    

4. 函数的嵌套调用

嵌套调用:函数内部调用其他函数。

def index():
	func()
	print('from index')
	
def func():
	index()
	print('from func')
	
func()  # 层数过多,一直循环,报错。
def my_max(a, b):
	if a > b:
		return a
	return b

def many_max(x, y, z, c):
	# 所谓的白嫖主义
	res = my_max(x, y)
	res1 = my_max(res, z)
	res2 = my_maz(res1, c)
	return res2

ret = many_max(12, 33, 55, 78)
print(ret)  # 78

5. 函数的嵌套定义

函数嵌套定义:函数体内部定义其他函数

def index():
	name = 'joshua'
	def func():  # 函数内部定义其他函数
		print('from func')
	
index()


"""
应用场景:
	将复杂的功能全部隐藏起来,暴露一个简单的接口。
"""

def all_func(choice):
	
	def register():
		print('注册功能')
		
	def login():
		print('登录功能')
		
	def transfer():
		print('转账功能')
		
	def shopping():
		print('购物功能')
	
	if choice == '1':
		register()
		
	if choice == '2':
		login()
		...
	...
# 在以上类似的场景中可以用到函数嵌套定义。

6. 闭包函数(重点-不难)

闭:定义在函数内部的函数。
包:内部函数引用了外部函数名称空间中的名字。

只有符合上述 两个 特征的函数才可以称为“闭包函数”。

注意:

def outer():
	def index():
		print('from index', x)
	return index

res = outer()
x = 33
res()  # from index 33
# 此函数没有引用外部函数名称空间中的名字,
# 故,不是闭包函数。
  • 闭包函数其实是给函数传参的第二种方式

    # 传参方式一:函数体代码需要用到数据,直接在括号内定义即可。
    def my_max(a, b):
    	if a > b:
    		return a
    	return b
    
    # 方式二:利用闭包函数
    def outer(x, y):
    	def my_max():
    		if x > y:
    			return x
    		return y
    	return my_max
    
    res = outer(22, 56)
    print(res())  # 56
    
  • 闭包的实际应用

    import requests
    
    # 爬取百度首页数据
    def outer(url):
    	def get_content():
    		res = requests.get(url)
    		if res.status_code == 200:
    			with open(r'xxx.html','rb') as f:
    				f.write(res.content)
    	return get_content
    
    res = outer('https://www.baidu.com')
    res()
    res()
    ...
    

闭包的作用:

  1. 可以给函数体传参
  2. 让内部函数参数不受外部的影响。

7. 装饰器的概念

  • 什么是装饰器???
    器:指工具。
    装饰:给被装饰对象添加额外的功能。

  • 装饰器的原则
    开放封闭原则
    开放:对扩展开放
    封闭:对修改封闭

  • 装饰器核心思想
    在 不改变被装饰对象内部代码原有调用方式 的基础上,添加额外的功能。

"""
装饰器并不是一个新知识
	而是由之前学的:名称空间,函数对象,闭包函数组合而来的。
"""

# def index():
# 	print('from index')

# index()

# 统计index函数的执行时间
import time

print(time.time())  # 获取的结果是时间戳,
# (运行代码的那一刻距离1970-1-1所经历的秒数)
time.sleep(3)  # 让程序原地阻塞 3 秒

def index():
	print('from index')
	time.sleep(2)
	
start_time = time.time()
index()
end_time = time.time()
print(end_time - start_time)