python 装饰器和property

一.  理解和实现装饰器

所谓装饰器, 就是在代码执行期间, 在不改变原有代码(类或者函数)的情况下, 为之动态附加功能.

例如, 在调用函数之前做一些计算, 在函数调用之后输出日志.

如何实现一个装饰器呢, 这里就需要使用到前面学习的知识闭包函数了.

1. 装饰器的原型

import time
def decorator(func):  # 将原函数作为参数传入
    def newfunc():
        # 调用之前
        stime = time.perf_counter()
        func()  # 调用原函数
        # 调用之后
        etime = time.perf_counter()
        print(‘called %s, used %s‘ % (func.__name__, etime-stime))
    # 将新函数返回
    return newfunc

def func():
    print("原始函数被调用了")

func = decorator(func)  # 手动的把新函数赋值给旧函数
func()  # newfunc()

2. 装饰器的 @语法糖

在装饰器原型中, 我们是手动的调用 expand 函数, 而在 python 中, 应该使用 @语法糖, 将装饰器 decorator 至于函数的定义处:

@decorator  # 相当于 func = expand(func)
def func():
    print("原始函数被调用了")

这时候, 我们就可以这样调用了

func()

3. 被装饰函数带有参数的装饰器

如果一个需要被装饰的函数有参数, 那么, 在装饰器的返回函数中, 也应该有有相应的参数, 否则会产生错误

import time
def decorator(func):  # 将原函数作为参数传入
    def newfunc(arg, *args, **kwargs):
        # 调用之前
        stime = time.perf_counter()
        func(arg, *args, **kwargs)  # 调用原函数
        # 调用之后
        etime = time.perf_counter()
        print(‘called %s, used %s‘ % (func.__name__, etime-stime))
    # 将新函数返回
    return newfunc

@decorator
def func(arg, *args, **kwargs):
    print("原始函数被调用了")

func(‘‘)  # newfunc()

4. 带有返回值的装饰器函数

import time
def decorator(func):
    def newfunc(arg, *args, **kwargs):
        # stime = time.perf_counter()
        return func(arg, *args, **kwargs)  # 执行原函数, 并返回原函数的返回值
        # etime = time.perf_counter()
        # return etime-stime  # 给原函数添加返回值功能
    return newfunc

@decorator
def func(arg, *args, **kwargs):
    return "原始函数被调用了"

print(func(‘‘))  # 0.0005786

5. 装饰器需要传参数

如果装饰器本身需要传入参数, 那么就要再嵌套一层闭包

import time
def log(name):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(‘%s call %s, on %s‘ % (name, func.__name__, time.strftime("%Y.%m.%d %H:%M:%S")))
            return func(*args, **kwargs)  # 执行原函数, 并返回原函数的返回值
        return wrapper  # 实际返回函数
    return decorator

@log(‘trent‘)  # 相当于执行了 func = log(‘trent‘)(func)
def func():
    print("原始函数被调用了")

func()

6. 原函数丢失, 用 wraps 找回

在以上的案例中, 我们会发现, 原函数被新函数替代, 原函数的签名__name__丢了, 文档__doc__等等也丢了, 取而代之的是返回的新函数的东西

def decorator(func):
    def wrapper(*args, **kwargs):
        pass
    return wrapper

@decorator
def func():
    pass

print(func.__name__)  # wrapper

而我们需要的是原函数, 而不是新的函数, 所以需要使用 functools.wraps 来将原函数的东西赋值给新的函数, 那么我们以上的例子就应该写为:

import time
from functools import wraps
def log(name):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(‘%s called %s on %s‘ % (name, func.__name__, time.strftime("%Y.%m.%d %H:%M:%S")))
            return func(*args, **kwargs)  # 执行原函数, 并返回原函数的返回值
        return wrapper  # 实际返回函数
    return decorator

7. 装饰器的优化 @decorator

多层嵌套的装饰器, 不是很直观, 甚至很复杂, 那么我们就需要第三方库来优化, 让装饰器更具有可读性.

使用内置的装饰器: @decorator, 基本能够满足需求

import time
from decorator import decorator
def log(name):
    @decorator
    def dcrt(func, *args, **kwargs):
        print(‘%s called %s on %s‘ %
              (name, func.__name__, time.strftime("%Y.%m.%d %H:%M:%S")))
        return func(*args, **kwargs)
    return dcrt

@log(‘trent‘)
def func():
    pass

func()

被装饰之后, 我们去查看一下它的源码:

import inspect
print(inspect.getsource(func))

执行结果(是原函数的源码):

@log(‘trent‘)
def func():
    pass

8. 一个强大的装饰器包 wrapt

wrapt 比较完善, 而且能够实现平常没有想到的装饰器, 使用的原型:

import wrapt
@wrapt.decorator
def pass_through(wrapped, instance, args, kwargs):
    return wrapped(*args, **kwargs)

@pass_through
def function():
    pass

这里需要注意它的四个参数, 这四个参数是必须要有的, 而且 args 和 kwargs 不带星号, 在返回之时才带星号

由于小弟功力尚浅, 很少用 wrapt 这样的装饰器, 对此暂不做深入的演示, 如果你有兴趣, 可参考 wrapt 的文档: http://wrapt.readthedocs.io/en/latest/quick-start.html

由于在 python 中, 一切皆为对象, 函数形式的装饰器与类形式的装饰器相差不大, 所以对类的装饰器不做赘述.

二.  常用的内置装饰器

以上内容的装饰器优化中, 使用的 @decorator 装饰器, 是其中的一个内置装饰器. 以下将介绍更多的常用的内置装饰器

在此, 我们想看看这样一个简单的类

class Person():
    def __init__(self, name):
        self.__name = name

    def getName(self):
        return self.__name
    def setName(self, val):
        self.__name = val
    def delName(self):
        del self.__name

    name = property(getName, setName, delName, ‘a document‘)

在此类中, 封装了一个私有属性__name, 并定义了对__name属性的相关操作函数, 那么在我们没有使用 property 之前, 只能通过调用相应的方法才能对属性__name进行相关的操作.

那么我们使用了 property 之后, 我们就可以在外部这样操作:

ps = Person(‘Trent‘)
print(ps.name)  # 相当于调用了ps.getName()函数
ps.name = ‘_trent_‘  # 相当于调用了ps.setName(‘_trent_‘)函数
print(ps.name)
del ps.name  # 相当于调用了ps.delName()函数

那么当变量不断的增多时, 我们就要不断的增加一套一套的 get/set/del 和 property , 这样就会显得臃肿, 啰嗦, 而且有些私有的属性我们没有必要设置一套 get/set/del . 因此可以使用以下几个内置的装饰器来解决

1. @property 属性的获取

2. @setter 属性的赋值

3. @deleter 属性的删除

了解至此, 我们可以把以上的 Person 类改写为这样:

class Person():
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter  # 注意: setter必须带上前缀 公有的属性名.
    def name(self, val):
        self.__name = val

    @name.deleter  # 注意: deleter必须带上前缀 公有的属性名.
    def name(self):
        del self.__name

4. @classmethod

5. @staticmethod

class Person():
    def run():
        print(‘普通方法 run, 只能类调用‘)
    def walk(self):
        print(‘实例绑定方法 walk, 自动传递实例对象self参数‘)
    @classmethod
    def smile(cls):
        print(‘类绑定方法 smile, 自动传递类cls参数‘)
    @staticmethod
    def look():
        print(‘静态方法 look, 无论类和实例对象, 都能调用的方法‘)

在外部使用

ps = Person()
# ps.run()  # 不能用实例对象调用
Person.run()
ps.walk()
# Person.walk()  # 不能使用类调用
ps.smile()
Person.smile()
ps.look()
Person.look()

总结: 类可以调用的方法有 静态方法, 类绑定方法和 普通方法. 实例可以调用的方法有 实例绑定方法, 类绑定方法 和 静态方法.

原文地址:https://www.cnblogs.com/trent-fzq/p/10989489.html

时间: 2024-10-15 05:39:05

python 装饰器和property的相关文章

python装饰器Decorators

http://blog.csdn.net/pipisorry/article/details/41902599 Introduction 装饰器Decorators是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用.概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能.装饰器用于在不改变原函数代码的情况下修改已存在的函数.常见场景是增加一句

Python装饰器的学习笔记(转载)

Python装饰器的学习笔记 2017-05-18 程序员共读 来自:标点符的<Python装饰器的学习笔记> 链接:http://www.biaodianfu.com/python-decorator.html 原文:http://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators-in-python#answer-1594484 装饰器(decorator)是一种高级Python语法.可

Python——装饰器基础

装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自己编写新的装饰器的更多高级语法. ================================================================================= 什么是装饰器 装饰是为函数和类指定管理代码的一种方式.Python装饰器以两种形式呈现: [1]函数装饰器在函数定义的时候进行名称重绑定,提供一个逻辑层来管理函数和方法或随后对它们的调

Python装饰器完全解读

1 引言 装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨——人生苦短,我用Python. 2 初步理解装饰器 2.1 什么是装饰器 在解释什么是装饰器之前,我们有必要回顾一下Python中的一些思想和概念.我们都知道,Python是一门面向对象的语言,Python基本思想就是一些皆对象,数据类型是对象.类是对象.类实例也是对象……对于接下来我们要说的装饰器而言,最重要的是,函数也是对象! 你没看错,函

Python装饰器详解,详细介绍它的应用场景

装饰器的应用场景 附加功能 数据的清理或添加: 函数参数类型验证 @require_ints 类似请求前拦截 数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改 为函数提供额外的数据 mock.patch 函数注册 在任务中心注册一个任务 注册一个带信号处理器的函数 不同应用场景下装饰器实现 函数注册表 简单注册表 funcs = [] def register(func): funcs.append(func) return func @register def a(): r

5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器

一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰器 1.1什么是高阶函数? 1.1.1函数接收的参数,包涵一个函数名. 1.1.2 函数的返回值是一个函数名. 其实这两个条件都很好满足,下面就是一个高阶函数的例子. def test1(): print "hamasaki ayumi" def test2(func): return t

python装饰器通俗易懂的解释!

python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说明一下: 小P闲来无事,随便翻看自己以前写的一些函数,忽然对一个最最最基础的函数起了兴趣: 1 def sum1(): 2 sum = 1 + 2 3 print(sum) 4 sum1() 此时小P想看看这个函数执行用了多长时间,所以写了几句代码插进去了: 1 import time 2 3 def

python装饰器1

第八步:让装饰器带 类 参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # -*- coding:gbk -*- '''示例8: 装饰器带类参数''' class locker:     def __init__(self):         print("locker.__init__() should be not called.")   

Python装饰器由浅入深

装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法.要理解在Python中装饰器的原理,需要一步一步来.本文尽量描述得浅显易懂,从最基础的内容讲起. (注:以下使用Python3.5.1环境) 一.Python的函数相关基础 第一,必须强调的是python是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行它的,只