Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Python: задекорируем-ка декораторы. Вновь

Anna | 16.06.2014 | нет комментариев
В прошлом году на Прогре теснее была дюже развёрнутая статья в 2-х частях о декораторах. Цель этой новой статьи — cut to the chase и сразу заняться увлекательными, осмысленными примерами, Дабы поспеть после этого разобраться в примерах ещё больше мудрёных, чем в предыдущих статьях.
Целевая аудитория — программисты, теснее знакомые (скажем по C#) с функциями высшего порядка и с замыканиями, но привыкшие, что аннотации у функций — это «метаинформация», проявляющаяся только при рефлексии. Специфика Питона, сразу же кидающаяся в глаза таким программистам — то, что наличие декоратора перед объявлением функции разрешает изменить поведение этой функции:

Как это работает? Ничего хитроумного: декоратор — это легко функция, принимающая доводом декорируемую функцию, и возвращающая «поправленную»:

def timed(fn):
    def decorated(*x):
        start = time()
        result = fn(*x)
        print "Executing %s took %d ms" % (fn.__name__, (time()-start)*1000)
        return result
    return decorated

@timed
def cpuload():
    load = psutil.cpu_percent()
    print "cpuload() returns %d" % load
    return load

print "cpuload.__name__=="   cpuload.__name__
print "CPU load is %d%%" % cpuload()

(Исходник целиком)

cpuload.__name__==decorated
cpuload() returns 16
Executing cpuload took 105 ms
CPU load is 16%

Объявление @timed def cpuload(): ... разворачивается в def cpuload(): ...; cpuload=timed(cpuload), так что в итоге глобальное имя cpuload связывается с функцией decorated внутри timed, замкнутой на начальную функцию cpuload через переменную fn. В итоге мы и видим cpuload.__name__==decorated

В качестве декоратора может применяться всякое выражение, значение которого — функция, принимающая функцию и возвращающая функцию. Таким образом допустимо создавать «декораторы с параметрами» (реально, фабрики декораторов):

def repeat(times):
    """ повторить вызов times раз, и воротить среднее значение """
    def decorator(fn):
        def decorated2(*x):
            total = 0
            for i in range(times):
                total  = fn(*x)
            return total / times
        return decorated2
    return decorator

@repeat(5)
def cpuload():
    """ внутри функции cpuload ничего не изменилось """

print "cpuload.__name__=="   cpuload.__name__
print "CPU load is %d%%" % cpuload()

(Исходник целиком)

cpuload.__name__==decorated2
cpuload() returns 7
cpuload() returns 16
cpuload() returns 0
cpuload() returns 0
cpuload() returns 33
CPU load is 11%

Значение выражения repeat(5) — функция decorator, замкнутая на times=5. Это значение и применяется в качестве декоратора; реально имеем def cpuload(): ...; cpuload=repeat(5)(cpuload)

Дозволено сочетать несколько декораторов на одной функции, тогда они используются в натуральном порядке — справа налево. Если два предыдущих примера объединить в @timed @repeat(5) def cpuload(): — то на выходе получим

cpuload.__name__==decorated
cpuload() returns 28
cpuload() returns 16
cpuload() returns 0
cpuload() returns 0
cpuload() returns 0
Executing decorated2 took 503 ms
CPU load is 9%

А если поменять порядок декораторов — @repeat(5) @timed def cpuload(): — то получим

cpuload.__name__==decorated2
cpuload() returns 16
Executing cpuload took 100 ms
cpuload() returns 14
Executing cpuload took 109 ms
cpuload() returns 0
Executing cpuload took 101 ms
cpuload() returns 0
Executing cpuload took 100 ms
cpuload() returns 0
Executing cpuload took 99 ms
CPU load is 6%

В первом случае объявление развернулось в cpuload=timed(repeat(5)(cpuload)), во втором случае — вcpuload=repeat(5)(timed(cpuload)). Обратите вниманpre>

CPU load is 6%
cpuload() returns 0
cpuload() returns 0
cpuload() returns 7
cpuload() returns 0
cpuload() returns 0
CPU load is 1%

Это одна из очаровательнейших вероятностей Питона — к функциям дозволено добавлять не только признаки, но и произвольные функции-способы. Функции на функциях сидят и функциями погоняют.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB