当前位置:  开发笔记 > 编程语言 > 正文

Python装饰器有哪些常见用途?

如何解决《Python装饰器有哪些常见用途?》经验,为你挑选了11个好方法。

虽然我喜欢把自己想象成一个相当称职的Python编码器,但我从来没有能够理解的语言的一个方面就是装饰器.

我知道它们是什么(表面上),我已经阅读了有关Stack Overflow的教程,示例和问题,我理解语法,可以编写自己的,偶尔使用@classmethod和@staticmethod,但我从来没有想过使用装饰器解决我自己的Python代码中的问题.我从来没有遇到过这样的问题,"嗯......这看起来像装饰工作!"

所以,我想知道你们是否可以提供一些你在自己的程序中使用装饰器的例子,希望我会有一个"A-ha!" 一刻,得到他们.



1> RSabet..:

我使用装饰器主要用于计时目的

def time_dec(func):

  def wrapper(*arg):
      t = time.clock()
      res = func(*arg)
      print func.func_name, time.clock()-t
      return res

  return wrapper


@time_dec
def myFunction(n):
    ...


好例子!不知道它做了什么.解释你在那里做什么,以及装饰者如何解决问题将是非常好的.
在Unix下,`time.clock()`测量CPU时间.如果你想测量挂钟时间,你可能想要使用`time.time()`.
好吧,它衡量`myFunction`运行所需的时间......

2> John Fouhy..:

我用它们进行同步.

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

正如评论中指出的那样,从Python 2.5开始,您可以将with语句与threading.Lock(或multiprocessing.Lock自2.6版本)对象结合使用, 以简化装饰器的实现:

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            with lock:
                return f(*args, **kw)
        return newFunction
    return wrap

无论如何,你这样使用它:

import threading
lock = threading.Lock()

@synchronized(lock)
def do_something():
  # etc

@synchronzied(lock)
def do_something_else():
  # etc

基本上,它只是把lock.acquire()/ lock.release()在函数调用的两侧.


可能是合理的,但装饰者本质上是混乱的,尤其是.来到你身后的第一年的新手,并尝试修改你的代码.简单地避免这种情况:只需将do_something()将其代码括在"with lock:"下的块中,每个人都可以清楚地看到你的目的.装饰者被那些想要看起来很聪明的人(实际上很多人)大量过度使用,但随后代码变成了凡人,并且得到了充实.
@TaylerJones,代码可读性是我写作时的最高优先级.每次修改代码时,代码读取次数超过7次.难以理解的代码(对于新手或在时间压力下工作的专家)是每次有人访问源树时必须支付的技术债务.
@KevinJ.Rice约束你的代码,以便'第一年的新手'可以更好地理解它是可怕的做法.Decorator语法更容易阅读,并且极大地解耦了代码.

3> Simon..:

我使用装饰器进行类型检查参数,这些参数通过一些RMI传递给我的Python方法.因此,不是重复相同的参数计数,而是一次又一次地异常提升mumbo-jumbo

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

我只是宣布

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

和accepts()为我做所有的工作.


对于任何有兴趣的人,在PEP 318中都有`@ accepted`的实现.
我认为有错字..第一种方法应该接受..你宣称两者都是"myMethod"

4> cdleary..:

装饰器用于任何您希望透明地"包装"其他功能的东西.

Django使用它们在视图函数上包装"需要登录"功能,以及注册过滤器函数.

您可以使用类装饰器将命名日志添加到类中.

任何足够通用的功能,你可以"适应"现有的类或功能的行为是公平的装饰游戏.

还讨论了PEP 318指向的Python-Dev新闻组的用例- 函数和方法的装饰器.



5> Torsten Mare..:

对于nosetests,您可以编写一个装饰器,它提供具有多组参数的单元测试函数或方法:

@parameters(
   (2, 4, 6),
   (5, 6, 11),
)
def test_add(a, b, expected):
    assert a + b == expected



6> DNS..:

Twisted库使用装饰器与生成器相结合,给出异步函数同步的错觉.例如:

@inlineCallbacks
def asyncf():
    doStuff()
    yield someAsynchronousCall()
    doStuff()
    yield someAsynchronousCall()
    doStuff()

使用它,本来可以分解成大量小回调函数的代码可以很自然地编写为单个块,使其更容易理解和维护.



7> MisterMetaph..:

当然,一个显而易见的用途是记录:

import functools

def log(logger, level='info'):
    def log_decorator(fn):
        @functools.wraps(fn)
        def wrapper(*a, **kwa):
            getattr(logger, level)(fn.__name__)
            return fn(*a, **kwa)
        return wrapper
    return log_decorator

# later that day ...
@log(logging.getLogger('main'), level='warning')
def potentially_dangerous_function(times):
    for _ in xrange(times): rockets.get_rocket(NUCLEAR=True).fire()



8> DzinX..:

我主要用它们来调试(打印一个打印其参数和结果的函数的包装)和验证(例如检查一个参数是否是正确的类型,或者在Web应用程序的情况下,如果用户有足够的权限调用一个特定的方法).



9> luc..:

我使用以下装饰器来创建函数threadsafe.它使代码更具可读性.它几乎与John Fouhy提出的类似,但不同之处在于,它只能处理单个函数,并且不需要明确地创建锁定对象.

def threadsafe_function(fn):
    """decorator making sure that the decorated function is thread safe"""
    lock = threading.Lock()
    def new(*args, **kwargs):
        lock.acquire()
        try:
            r = fn(*args, **kwargs)
        except Exception as e:
            raise e
        finally:
            lock.release()
        return r
    return new

class X:
    var = 0

    @threadsafe_function     
    def inc_var(self):
        X.var += 1    
        return X.var


那真的很危险.方法inc_var()是"线程安全的",因为一次只能有一个人调用它.也就是说,由于该方法对成员变量"var"进行操作,并且可能其他方法也可能对成员变量"var"进行操作,并且这些访问不是线程安全的,因为锁不是共享的.以这种方式做事给X类用户带来了错误的安全感.

10> Nikhil Chell..:

装饰器既可用于定义函数的属性,也可用作修改函数的样板; 这是可能的,但反直觉的是他们返回完全不同的功能.看看这里的其他响应,似乎最常见的用途之一是限制其他一些进程的范围 - 无论是日志记录,分析,安全检查等.

CherryPy使用对象分派来匹配对象的URL,最终匹配方法.这些方法的装饰者发出信号,表明CherryPy是否被允许使用这些方法.例如,改编自教程:

class HelloWorld:

    ...

    def secret(self):
        return "You shouldn't be here."

    @cherrypy.expose
    def index(self):
        return "Hello world!"

cherrypy.quickstart(HelloWorld())



11> aatifh..:

我最近在使用社交网络Web应用程序时使用它们.对于社区/团体,我应该授予成员资格以创建新的讨论并回复您必须成为该特定组成员的消息.所以,我写了一个装饰师@membership_required,把它放在我需要的地方.

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有