1、首先理解:一切皆对象
def hi(name="yasoob"):
return "hi " + name
print(hi()) # 输出: hi yasoob
'''可以将一个函数赋值给一个变量,比如'''
greet = hi
'''这里没有在hi后面添加小括号,因为并不是在调用hi函数,而是在将它放在greet变量里头。'''
# 运行下如下代码
print(greet()) # 输出: hi yasoob
2、在函数中定义函数
def hi(name='python'):
print('现在是hi()函数--start')
def greet():
return '现在是greet()函数'
def welcome():
return '现在是welcome()函数'
print(greet())
print(welcome())
print('现在是hi()函数--end')
'''无论何时调用hi()函数, greet()和welcome()将会同时被调用。然后greet()和welcome()函数在hi()函数之外是不能访问的'''
hi()
----output----
现在是hi()函数--start
现在是greet()函数
现在是welcome()函数
现在是hi()函数--end
3、从函数中返回函数
def hi(name = 'python'):
def greet():
return '现在是greet()函数'
def welcome():
return '现在是welcome()函数'
if name == 'python':
return greet # 注意返回函数不带(),带上()这个调用就会执行。然而如果不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
else:
return welcome
a = hi()
print(a) # output: <function hi.<locals>.greet at 0x10aad8c10>
print(a()) # output: 现在是greet()函数
注意返回函数不带(),带上()这个调用就会执行。然而如果不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
4、将函数作为参数传给另一个函数
def hi():
print('hi python')
def beforeHi(func):
print('在 hi()函数之前执行。。')
func()
beforeHi(hi)
---output---
在 hi()函数之前执行。。
hi python
到此,可以初步了解到 ---- 装饰器让在一个函数的前后去执行代码,且又不改变函数本身的方法。
5、第一个装饰器
def a_decorator(func):
def wrapper():
print("执行函数前运行代码。。。。")
func()
print('执行函数后运行代码。。。。')
return wrapper
### diff1
def func1():
print('函数func1()')
a_decorator(func1)() ### diff2
---output---
执行函数前运行代码。。。。
函数func1()
执行函数后运行代码。。。。
可使用简便的@符号修饰,不同点为:diff1,diff2。运行结果一致。上述代码可改为:
@a_decorator ### diff1
def func1():
print('函数func1()')
func1() ### diff2
print(func1.__name__)
---output---
执行函数前运行代码。。。。
函数func1()
执行函数后运行代码。。。。
wrapper
上述存在一个问题:
print(func1.__name__)
# output: wrapper
ouput输出应该是"func1",而不是‘wrapper’。这里的函数被wrapper替代了。它重写了func1函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:
from functools import wraps #####
def a_decorator(func):
@wraps(func) ######
def wrapper():
print("执行函数前运行代码。。。。")
func()
print('执行函数后运行代码。。。。')
return wrapper
@a_decorator
def func1():
print('函数func1()')
print(func1.__name__)
----output----
func1
@wraps 接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
6、带参数的装饰器
下面代码能将日志输出到指定的日志文件中。
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile,并写入内容
with open(logfile, 'a') as opened_file:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()