一、函数对象
python一切皆对象,所以函数也是对象,也可以当做数据被处理
- 函数可以被引用
- 可以当作参数传递
- 返回值可以是函数
- 可以当作容器类型的元素
二、函数闭包
Python 支持函数式编程,所以存在闭包,闭包是由函数及其相关的引⽤环境组合⽽成的实体 , ⼀句话: 闭包 = 函数+引⽤环境,函数式编程中,当内嵌函数体内引⽤到体外的变量 时, 将会连同这些变量(引⽤环境)和内嵌函数体, ⼀块打包成⼀个整体返回。
如果在一个函数的内部定义了另一个函数,外部的我们叫它为外函数,内部的我们叫它内函数,那么闭包就是在一个外函数中定义了一个内函数,内函数里引用了外函数的临时变量,并且外函数的返回值是内函数的引用。
x = 1
def out_func():
x =2
def in_func():
print('in the in_func', x)
return in_func
f = out_func()
f()# 通过调用__closure__属性查看闭包所包裹的外部变量print(f.__closure__, f.__closure__[0].cell_contents)
""" in the in_func 2 (<cell at 0x00A27810: int object at 0x1D9DE320>,) 2"""
三、装饰器----闭包的运用
1 . 什么是装饰器?
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
2 . 装饰器的使用
-
装饰器的框架
def ver_fun(func):
def wrapper(*args, **kwargs): # 引用外部函数变量func
# 需要增添的功能逻辑
func() #这里就是将一开始没有装饰的test运行一次
return wrapper
@ver_fun # 实际上就相当于 test = ver_fun(test),此时的test就是return回来的wrapper
def test():
print('hello world!')test() # 实际上就是wrapper()
- 无惨装饰器

mport time
def timmer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print('函数运行的时间为%s' % (stop_time - start_time))
return wrapper
@timmer
def test():
time.sleep(2)
print('执行完毕')
test()
"""
执行完毕
函数运行的时间为2.000253677368164
"""
当我们调用test函数时,实际上就是在调用wrapper函数,所以当我们的test函数有参数时,wrapper函数也要带上参数,为了统一,我们一般都会在wrapper函数和func函数上加上*args+**kwargs组合,即上
述代码可以修改为

import time
def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
stop_time = time.time()
print('函数运行的时间为%s' % (stop_time - start_time))
return wrapper
@timmer
def test(name, age):
time.sleep(2)
print('执行完毕')
test("jiang", 8)
- 带参数的装饰器
是为装饰器提供多样功能选择的实现提供的,实现原理是三层闭包。如当我们需要不同分认证方式时,可以使用有参装饰器

import os
def file_handle(backend_data, res=None, type='fetch'):
'''
这是一个文件处理的函数,对查找和修改功能中的文件处理部分进行的程序解耦
:return:
'''
if type == 'fetch':
with open('haproxy.conf', 'r') as read_f:
tag = False
ret = []
for each_line in read_f:
if each_line.strip() == backend_data:
tag = True
continue
if tag and each_line.startswith('backend'):
break
if tag:
print(each_line, end='')
ret.append(each_line)
return ret
elif type == 'change':
with open('haproxy.conf', 'r') as read_f, \
open('haproxy.conf_new', 'w') as write_f:
tag = False
write_tag = True
for each_line in read_f:
if each_line == backend_data:
tag = True
continue
if tag and each_line.startswith('backend'):
tag = False
if not tag:
write_f.write(each_line)
elif write_tag:
for record in res:
write_f.write(record)
write_tag = False
os.rename('haproxy.conf', 'haproxy.conf.bak')
os.rename('haproxy.conf_new', 'haproxy.conf')
os.remove('haproxy.conf.bak')
def fetch(data):
backend_data = 'backend %s' % data
return file_handle(backend_data)
def add():
pass
def change(data):
'''
这是修改功能,用户传入一个列表,列表第一个元素为原修改数据,第二个元素为修改后的数据
:param data: 用户输入的列表
:return:
'''
# 提取出用户输入数据中的地址
backend = data[0]['backend']
backend_data = 'backend %s\n' % backend
# 将用户中的server拼接起来
old_server_record = '%sserver %s %s weight %s maxconn %s\n' % (' ' * 8, data[0]['record']['server'],
data[0]['record']['server'],
data[0]['record']['weight'],
data[0]['record']['maxconn'])
new_server_record = '%sserver %s %s weight %s maxconn %s\n' % (' ' * 8, data[1]['record']['server'],
data[1]['record']['server'],
data[1]['record']['weight'],
data[1]['record']['maxconn'])
print('用户想要修改的记录是', old_server_record)
print('用户想要修改后的记录是', new_server_record)
res = fetch(backend)
print(res)
if not res or old_server_record not in res:
return '用户要修改的数据不存在'
else:
index = res.index(old_server_record)
res[index] = new_server_record
res.insert(0, '%s\n' % backend_data)
file_handle(backend_data, res=res, type='change')
def delete():
pass
if __name__ == '__main__':
msg = '''
weibo:查询
2:添加
3:修改
4:删除
5:退出
'''
menu_dic = {'weibo': fetch, '2': add, '3': change, '4': delete}
while True:
print(msg)
user_choice = input("请输入选项:").strip()
if not user_choice: continue
if user_choice == '5': break
user_data = input("请输入你想要的数据:").strip()
if user_choice != 'weibo':
user_data = eval(user_data)
res = menu_dic[user_choice](user_data)
print(res)
- wraps 的使用
我们这里调用help方法查看一下test函数
print(help(test)) """ Help on function wrapper in module __main__: wrapper(*args, **kwargs) None """
可以看到test函数的函数名为wrapper,证明装饰过后的函数函数名和函数的文档搜发生了变化,如果想保留原有函数的属性,除了我们自己手动在装饰器中修改wrapper的__name__和__doc__属性外,我们可
以还调用functools模块提供的装饰器来实现,具体如下:

import time
from functools import wraps
def timmer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
stop_time = time.time()
print('函数运行的时间为%s' % (stop_time - start_time))
return wrapper
@timmer
def test(name, age):
time.sleep(2)
print('执行完毕')
# test("jiang", 8)
print(help(test))
"""
Help on function test in module __main__:
test(name, age)
None
"""
