Сколько накладных расходов добавляют декораторы к вызовам функций Python

TL; DR - вы не можете вообще, но Base1.include Patch может быть достаточно хорошим.


Для вашего примера кода ancestors из Base1 и Base2: (выровнены для ясности)

Base1.ancestors #=> [Base1,        Feature, Object, Kernel, BasicObject]
Base2.ancestors #=> [Base2, Patch, Feature, Object, Kernel, BasicObject]

Base2 имеет дополнительный предок Patch до Feature - результат Feature.prepend Patch.

Ruby не позволяет нам свободно изменять цепочку предков модуля, поэтому мы не можем просто задним числом Patch - Feature задним числом.

Но, к счастью, Patch является первым модулем после класса Base, поэтому мы можем прибегнуть к include для добавления Patch в Base1 вместо:

[111 ]

Очевидно, что это работает только для очень конкретных случаев, а не в целом.

Вот контрпример:

module Feature
  def action ; 'Feature' ; end
end

module Foo
  def action ; "#{super} overridden" ; end
end

module Patch
  def action ; 'Patch' ; end
end

class Base1
  include Feature
  include Foo
end

Feature.prepend(Patch)

class Base2
  include Feature
  include Foo
end

Base1.new.action #=> "Feature overridden"
Base2.new.action #=> "Patch overridden"

Base1.include Patch

Base1.new.action #=> "Patch"

Глядя на предков, выявляется проблема:

Base1.ancestors #=> [Base1, Foo,        Feature, Object, Kernel, BasicObject]
Base2.ancestors #=> [Base2, Foo, Patch, Feature, Object, Kernel, BasicObject]
Base1.include Patch
Base1.ancestors #=> [Base1, Patch, Foo, Feature, Object, Kernel, BasicObject]

Patch и Foo не в порядке.

17
задан dochead 23 August 2010 в 08:06
поделиться

3 ответа

Накладные расходы, добавленные с декоратор должен быть всего лишь одним дополнительным вызовом функции.

Работа, выполняемая декоратором, не является частью накладных расходов, поскольку ваша альтернатива - добавить эквивалентный код к декорированному объекту.

Таким образом, возможно, что выполнение функции decorate занимает в два раза больше времени, но это потому, что декоратор выполняет некоторую важную работу, на развлечение которой уходит примерно столько же времени, что и на функцию без декорирования.

12
ответ дан 30 November 2019 в 13:45
поделиться

Важно знать, что декоратор имеет простой эффект:

@decorator
def f():
    …

- просто синтаксический сахар для

def f():
    …
f = decorator(f)

Таким образом, если декоратор ничего не делает, вы не возникает никаких накладных расходов, когда вызывает декорированную функцию (хотя вызов decorator(f) занимает немного времени), как в

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

. Таким образом, само по себе декорирование функции не добавляет много накладных расходов для того, что вы хотите сделать: единственные очевидные накладные расходы то, что вы могли бы в принципе удалить, означало бы не вызывать func() в декорированной функции, а вместо этого копировать его полный код, но при этом пострадала бы читаемость кода (удобочитаемость и гибкость - вот некоторые причины, по которым декораторы существуют в первую очередь) .

5
ответ дан 30 November 2019 в 13:45
поделиться

Добавляют ли декораторы значительные накладные расходы в систему? Я не могу найти ничего, что могло бы подтвердить это.

Они почти не добавляют измеримых накладных расходов. Нуль.

Важно отметить, что декоратор запускается один раз для создания декорированной функции. Один раз.

Декорированная функция состоит из двух частей.

  1. какое бы украшение ни было добавлено. Это не накладные расходы.

  2. плюс исходная функция. Это не накладные расходы.

Нет никаких реальных накладных расходов. Вы могли бы - с некоторой осторожностью - измерить накладные расходы на один дополнительный вызов и возврат функции как часть декорированной функции, но это почти неизмеримо мало. И это, вероятно, гораздо меньше, чем альтернативный дизайн, в котором не используются украшения.

3
ответ дан 30 November 2019 в 13:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: