函数的属性

2024-04-25 23:52:24 发布

您现在位置:Python中文网/ 问答频道 /正文

def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n - 2) + fib(n - 1)

def count(f):
    def counted(*args):
        counted.call_count += 1 
        return f(*args)
    counted.call_count = 0
    return counted

>>> fib = count(fib)
>>> fib(5)
5
>>> fib.call_count
15
>>> counted.call_count
NameError

我知道fib现在实际上是counted。但是,我不明白为什么当我想调用counted.call_count时,我必须调用fib.call_count。你知道吗

我认为counted是类Function的一个实例。但是counted.call_count到底是什么意思?你知道吗

更具体地说,我不理解在代码class ****:之外定义的属性。在这种情况下,定义属性就像self.call_count更清晰,因为我可以理解self来引用实例。在我的例子中,看起来counted.call_count中的countedself.call_count中的self一样,但是是吗?你知道吗


Tags: 实例selfreturnif属性定义defcount
2条回答

思考python解释器是如何工作的,可能会帮助您理解这里发生了什么。当源代码通过lexer并转化为字节码时,我们可以看到“load”和“store”命令的引用,表明解释器主要作为基于堆栈的机器工作:

>>> dis.dis(count)
  2           0 LOAD_CLOSURE             0 (counted)
              2 LOAD_CLOSURE             1 (f)
              4 BUILD_TUPLE              2
              6 LOAD_CONST               1 (<code object counted at 0x00000193D034C8A0, file "<ipython-input-2-a31b910d61de>", line 2>)
              8 LOAD_CONST               2 ('count.<locals>.counted')
             10 MAKE_FUNCTION            8
             12 STORE_DEREF              0 (counted)

  5          14 LOAD_CONST               3 (0)
             16 LOAD_DEREF               0 (counted)
             18 STORE_ATTR               0 (call_count)

  6          20 LOAD_DEREF               0 (counted)
             22 RETURN_VALUE

我们还可以看到,call_count属性被绑定到创建的新代码对象,但是名称:counted被显式取消引用,因为它不再在作用域中,只返回代码对象。你知道吗

这里的问题是counted函数在主程序代码中没有被调用counted,它被称为fib。(count返回counted,通过赋值将其绑定到fib),因此应该使用这个名称。你知道吗

你对修饰函数名的依赖有点脆弱。你会发现你依赖这个名字。如果您将调用代码改为

fibfun = count(fib)
fibfun(5)
fibfun.call_count

您将看到它只计算外部调用。你知道吗

你实际上是在写一个装饰师,尽管你可能不知道。一种更为传统的写作方式可能是

def count(f):
    def counted(*args):
        counted.call_count += 1 
        return f(*args)
    counted.call_count = 0
    return counted

@count
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n - 2) + fib(n - 1)

这样就不需要手动包装函数(decorator语法只是为您进行调用),您只需编写

>>> fib(5)
5
>>> fib.call_count
15

问题是,您只能调用此修饰函数一次,除非您考虑到在进一步调用时计数会继续累积:

>>> fib(5)
5
>>> fib.call_count
30

这是可以接受的。否则,可能需要进一步的复杂性。你知道吗

相关问题 更多 >

    热门问题