Python 函数的属性 def fib(n): 如果n>>fib=计数(fib) >>>fib(5) 5. >>>小谎,呼叫计数 15 >>>计数 命名错误
据我所知,Python 函数的属性 def fib(n): 如果n>>fib=计数(fib) >>>fib(5) 5. >>>小谎,呼叫计数 15 >>>计数 命名错误,python,python-3.x,function,attributes,decorator,Python,Python 3.x,Function,Attributes,Decorator,据我所知,fib现在实际上是计数的。然而,我不明白为什么,当我想调用counted.call\u count时,我必须调用fib.call\u count 我认为counted是类函数的一个实例。但是什么是计数。呼叫计数的确切含义是什么 更具体地说,我不理解在代码类****:之外定义的属性。在这种情况下,定义属性就像self.call\u count更清晰,因为我可以理解self来引用实例。在我的例子中,似乎counted.call\u count中的counted就像self.call\u c
fib
现在实际上是计数的
。然而,我不明白为什么,当我想调用counted.call\u count
时,我必须调用fib.call\u count
我认为
counted
是类函数的一个实例。但是什么是计数。呼叫计数的确切含义是什么
更具体地说,我不理解在代码类****:
之外定义的属性。在这种情况下,定义属性就像self.call\u count
更清晰,因为我可以理解self
来引用实例。在我的例子中,似乎counted.call\u count
中的counted
就像self.call\u count
中的self
一样,但是它是吗?这里的问题是在主程序代码中没有调用counted
函数,它被称为fib
。(count
返回counted
,通过赋值绑定到fib
),因此您应该使用这个名称
您对修饰函数名的依赖有点脆弱。你会发现你依赖这个名字。如果您将调用代码更改为
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
您将看到它只计算外部调用
你实际上是在写一个装饰师,尽管你可能不知道。写这篇文章的更传统的方法可能是
fibfun = count(fib)
fibfun(5)
fibfun.call_count
问题是,您只能调用此修饰函数一次,除非您考虑到随着进一步调用,计数会继续累积:
>>> fib(5)
5
>>> fib.call_count
15
这是可以接受的。否则,可能需要进一步的复杂性。这里的问题是,counted
函数在主程序代码中没有调用counted
,它被称为fib
。(count
返回counted
,通过赋值绑定到fib
),因此您应该使用这个名称
您对修饰函数名的依赖有点脆弱。你会发现你依赖这个名字。如果您将调用代码更改为
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
您将看到它只计算外部调用
你实际上是在写一个装饰师,尽管你可能不知道。写这篇文章的更传统的方法可能是
fibfun = count(fib)
fibfun(5)
fibfun.call_count
问题是,您只能调用此修饰函数一次,除非您考虑到随着进一步调用,计数会继续累积:
>>> fib(5)
5
>>> fib.call_count
15
这是可以接受的。否则,可能需要进一步的复杂性。思考python解释器在幕后是如何工作的,这可能有助于您理解这里发生了什么。当源代码通过lexer并转换为字节码时,我们可以看到对“load”和“store”命令的引用,这表明解释器主要作为基于堆栈的机器工作:
>>> fib(5)
5
>>> fib.call_count
30
>dis.dis(计数)
2 0负载\u闭合0(计数)
2负载关闭1(f)
4构建元组2
6加载常数1(<0x00000193D034C8A0处计数的代码对象,文件“ipython-input-2-a31b910d61de”,第2行>)
8负载常数2('count..counted')
10制作功能8
12门店编号0(已计算)
5 14荷载常数3(0)
16加载顺序为0(计数)
18存储属性0(呼叫计数)
6 20加载顺序0(计数)
22返回值
我们还可以看到,call\u count
属性绑定到创建的新代码对象,但是名称:counted
被显式取消引用,因为它不再在作用域中,只返回code对象。思考python解释器如何在后台工作可能有助于您理解这里发生的事情。当源代码通过lexer并转换为字节码时,我们可以看到对“load”和“store”命令的引用,这表明解释器主要作为基于堆栈的机器工作:
>>> fib(5)
5
>>> fib.call_count
30
>dis.dis(计数)
2 0负载\u闭合0(计数)
2负载关闭1(f)
4构建元组2
6加载常数1(<0x00000193D034C8A0处计数的代码对象,文件“ipython-input-2-a31b910d61de”,第2行>)
8负载常数2('count..counted')
10制作功能8
12门店编号0(已计算)
5 14荷载常数3(0)
16加载顺序为0(计数)
18存储属性0(呼叫计数)
6 20加载顺序0(计数)
22返回值
我们还可以看到,call\u count
属性绑定到创建的新代码对象,但是名称:counted
被显式取消引用,因为它不再在范围内,只返回代码对象。counted。call\u count
不会只显示“Error”。它将显示NameError,告诉您当前范围中未定义计数的。@DanielRoseman:好的,谢谢!但我认为这不是重点。。。我想知道的是,为什么我要叫“fib.call\u count”,正如我刚才所说的那样。无论如何,谢谢<代码>计数。调用\u计数
不会只显示“错误”。它将显示NameError,告诉您当前范围中未定义计数的。@DanielRoseman:好的,谢谢!但我认为这不是重点。。。我想知道的是,为什么我要叫“fib.call\u count”,正如我刚才所说的那样。无论如何,谢谢!