修饰符给Python函数调用增加了多少开销

修饰符给Python函数调用增加了多少开销,python,performance,decorator,Python,Performance,Decorator,我一直在为我的挂架应用程序使用计时装饰器,为特定功能提供实时计时信息。我通过创建一个decorator实现了这一点&只需将它附加到我想要的控制器中的任何函数 然而,有人指出,装饰程序可能会给调用增加相当大的开销,并且它们的运行速度比未装饰的函数慢2-3倍 首先,我希望执行一个修饰过的函数比执行一个未修饰过的函数需要更长的时间,但是我希望开销在千分之一秒之内&与SQL插入调用相比可以忽略不计。decorator本身使用time.time()进行简单的计时计算&一些非常简单的聚合 装饰器会给系统增加

我一直在为我的挂架应用程序使用计时装饰器,为特定功能提供实时计时信息。我通过创建一个decorator实现了这一点&只需将它附加到我想要的控制器中的任何函数

然而,有人指出,装饰程序可能会给调用增加相当大的开销,并且它们的运行速度比未装饰的函数慢2-3倍

首先,我希望执行一个修饰过的函数比执行一个未修饰过的函数需要更长的时间,但是我希望开销在千分之一秒之内&与SQL插入调用相比可以忽略不计。decorator本身使用time.time()进行简单的计时计算&一些非常简单的聚合


装饰器会给系统增加大量开销吗?我找不到任何东西来支持它。

使用decorator增加的开销应该只是一个额外的函数调用

装饰器所做的工作并不是开销的一部分,因为您可以选择向装饰对象添加等效代码


因此,装饰功能可能需要两倍的时间才能运行,但这是因为装饰者正在做一些重要的工作,这些工作与未装饰的功能花费的时间大致相同。

需要知道的是,装饰者有一个简单的效果:

@decorator
def f():
    …
只是语法上的糖

def f():
    …
f = decorator(f)
因此,如果decorator不做任何事情,那么在调用decorator函数时就不会有任何开销(不过调用
decorator(f)
确实需要一点时间),比如

如果装饰者做了什么,你只会得到装饰者涉及的任何时间开销。这通常包括一个额外的函数调用(修饰函数的调用),如

因此,就其本身而言,修饰一个函数并不会为您想要做的事情增加太多开销:原则上,您可以消除的唯一明显开销是不在修饰的函数中调用
func()
,而是复制它的完整代码,但代码的易读性会受到影响(易读性和灵活性是装饰师确实存在的一些原因)

装饰师会给系统增加大量的开销吗?我找不到任何东西来支持这一点

它们几乎不增加可测量的开销。零

需要注意的是,decorator只运行一次来创建修饰函数。 一次

修饰函数有两个部分

  • 无论添加了什么装饰。这不是开销

  • 加上原始函数。这不是开销


  • 根本没有真正的开销。您可能——稍微小心一点——能够测量一个额外函数调用的开销,并将其作为修饰函数的一部分返回,但这几乎是无法测量的小开销。而且这可能远远小于不使用修饰的替代设计。

    -1 Python中的函数调用开销不是Insignfi不能。建议将
    func()
    的代码复制到decorator中首先会破坏decorator的全部功能。如果有什么不同的话,我更愿意将decorator的代码复制到
    func()
    ,但是,如果我们这样做,那么使用decorator的简单性就会被破坏,
    func()
    的代码被装饰行为污染了。你真的不能说“如果装饰器不做任何事情,你就没有任何开销”。装饰器对代码跟踪等很有用,但它们是以在运行时增加函数调用为代价的。@Paul:的确,函数调用开销在Python中相对重要(从来没有说过别的!)我同意这样一个事实,将
    func()
    的代码放在装饰器中会破坏装饰的整体意义(如我所写).因此,我们完全同意!我只是给出了一些要点,让原始海报能够准确地理解装饰师的开销来自何处。我的主要反驳是你的说法:“如果装饰师什么都不做,你就没有任何开销。”这听起来像是你忽略了额外的函数调用。我去删除了我的否决票,但除非你对你的答案进行一些编辑,否则我不会让我这样做。@Paul:谢谢你,我明白了。为了解释你的评论,我把答案做得更精确了。装饰本身的开销是可以测量的,但不接近2-3倍。这不考虑ac计算装饰行为,这可能非常耗时,具体取决于您正在做什么(数据库更新、月球上的反弹信号等)。同样,月球上的反弹信号为+1,但保留+2供将来评论:“同步月球信号反弹”
    decorator = lambda func: func
    @decorator
    def f():
        …
    
    def decorator(func):
        def decorated_func():
            print "Before calling function", func  # Some overhead (but that's normal)
            func()  # This will be a second function call, after the call to decorated_func()
        return decorated_func