python --- 装饰器

本文介绍了Python装饰器的基本概念,包括理解一切皆对象、在函数中定义函数、返回函数等。装饰器允许在不改变函数本身的情况下,在其前后添加代码。通过示例展示了如何创建装饰器,以及如何使用`@wraps`来保持被装饰函数的元信息。此外,还讨论了带参数的装饰器,展示了一个将日志输出到指定文件的例子。
摘要由CSDN通过智能技术生成

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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值