在一个装饰的装饰之外创建访问函数属性 [英] Accessing function attribute created in a decorator outside that decorator

查看:136
本文介绍了在一个装饰的装饰之外创建访问函数属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要计算时代给定函数被调用的次数。

I want to count the number of times a given function has been called.

所以,我做了一个 countcalls 装饰给我的功能,这得到每次通话递增 __ callcount 属性。够简单了。

So, I made a countcalls decorator to give my functions a __callcount attribute which gets incremented on each call. Simple enough.

我的问题是获得 __ callcount 值回出来以后。

My issue is getting the __callcount value back out later.

下面是我的code:

import functools

def countcalls(f):
    f.__callcount = 0

    @functools.wraps(f)
    def _countcalls(*args, **kwds):
        f.__callcount += 1
        print('  Called {0} time(s).'.format(f.__callcount))
        return f(*args, **kwds)
    return _countcalls

@countcalls
def fib(n):
    if n < 0:
        raise ValueError('n must be > 0')
    if n == 0 or n == 1:
        return 1

    return fib(n-1) + fib(n-2)

if __name__ == '__main__':
    print('Calling fib(3)...')
    x = fib(3)
    print('fib(3) = {0}'.format(x))

    print('Calling fib(3) again...')
    x = fib(3)
    print('fib(3) = {0}'.format(x))

    print('fib was called a total of {0} time(s).'.format(fib.__callcount)) 

产生以下输出(Python的3​​.3.0):

Which generates the following output (Python v3.3.0):

Calling fib(3)...
  Called 1 time(s).
  Called 2 time(s).
  Called 3 time(s).
  Called 4 time(s).
  Called 5 time(s).
fib(3) = 3
Calling fib(3) again...
  Called 6 time(s).
  Called 7 time(s).
  Called 8 time(s).
  Called 9 time(s).
  Called 10 time(s).
fib(3) = 3
fib was called a total of 0 time(s).

为什么 FIB .__ callcount 在最后一行等于 0 ?由于输出显示, __ callcount 被递增, FIB

Why does fib.__callcount equal 0 on the last line? As the output shows, __callcount gets incremented, and persists between calls of fib.

我是什么失踪?

推荐答案

那么,这里的原因,一点帮助后。谢谢你们!

Well, here's the reason, after a bit of help. Thanks guys!

问题是功能是不可变的。例如。

The issue is that functions are immutable. e.g.

>>> def f(func):
...     return func()
...
>>> def g():
...     return 'sunflower seeds'
...
>>> id(g)
139636515497336
>>> g = f(g)
>>> id(g)
139636515515112

因此​​,要获得功能˚F我们的定义分配 __ callcount 属性的唯一办法 countcalls 是返回从 callcount 。但是,我们已经返回内部函数 _countcalls 。我们可以同时返回˚F _countcalls 但搅乱 @countcalls 修饰语法。

So, the only way to get the function f we assigned the __callcount attribute to in the definition of countcalls is to return that function from callcount. But we're already returning the inner function _countcalls. We can return both f and _countcalls but that messes up the @countcalls decorator syntax.

您仍然可以这样来做,它只是并不像pretty。

You can still do it this way, it's just not as pretty.

import functools

def countcalls(f):
    f.__callcount = 0

    @functools.wraps(f)
    def _countcalls(*args, **kwds):
        f.__callcount += 1
        print('  Called {0} time(s).'.format(f.__callcount))
        return f(*args, **kwds)
    return f, _countcalls

def fib(n):
    if n < 0:
        raise ValueError('n must be > 0')
    if n == 0 or n == 1:
        return 1

    return fib(n-1) + fib(n-2)

if __name__ == '__main__':
    counter, fib = countcalls(fib)

    print('Calling fib(3)...')
    x = fib(3)
    print('fib(3) = {0}'.format(x))

    print('Calling fib(3) again...')
    x = fib(3)
    print('fib(3) = {0}'.format(x))

    print('fib was called a total of {0} time(s).'.format(counter.__callcount))

长话短说,只需使用类从Python的装饰图书馆。 :D

这篇关于在一个装饰的装饰之外创建访问函数属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆