我试图了解在从上到下阅读源代码时是否始终按照遇到的顺序调用装饰器?这是我写的一些示例代码:
def log(func):
print(func)
return func
class A:
@log
def __init__(self):
print('__init__')
@log
def foo(self):
print('foo')
@log
def bar(self):
print('bar')
@log
def baz(self):
print('baz')
@log
def qux(self):
print('qux')
这是输出:
<function A.__init__ at 0x0000000002342840>
<function A.foo at 0x00000000023428C8>
<function A.bar at 0x0000000002342950>
<function A.baz at 0x00000000023429D8>
<function A.qux at 0x0000000002342A60>
上面的输出似乎表明装饰器是按照从上到下读取源代码时遇到的顺序调用的?
答案 0 :(得分:2)
在您的情况下,他们正在阅读&#34;按顺序&#34;但每个方法只有一个装饰器。说明它们如何被读取的一种好方法是它们被链接,或者不止一个。例如:
@i_get_called_last
@i_get_called_second
@i_get_called_first
def my_decorated_function(a):
print a
return a
在这个例子中,你可以读到它们实际上是从&#34;从下到上阅读&#34;,意思是从最内层到最外面的方法。
答案 1 :(得分:0)
是的,但存在非常规情况:
@log
def a():
@log
def b():
pass
pass
输出:仅
<function a at 0x7fe2dfe24710>
另一个:
def log1(func):
print('1', func)
return func
def log2(func):
print('2', func)
return func
@log1
@log2
def a():
pass
输出:
2 <function a at 0x7fe2dfe24b90>
1 <function a at 0x7fe2dfe24b90>
答案 2 :(得分:-1)
看起来你在Python中有一个更基本的东西要理解:
一旦你理解了这一点,那装饰器只相当于 用装饰器的返回值替换声明的函数,即:
@deco
def myfunc():
pass
# is equivalent to:
def myfunc():
pass
myfunc = deco(myfunc)
你开始明白发生了什么。 因此,当Python 编译器在源代码中找到一个块时,如:
def a(): 通
它在字节码中记录函数体的代码对象(pass
语句),
和从此代码创建函数对象的字节码,以及def语句中包含的元素(本质上是对types.FunctionType的调用)。在运行代码时(在编译传递之后),此调用的返回对象将绑定到找到该函数的命名空间中的名称a
。只有在这一点上,“功能对象”才存在,并且可以被调用。
如果在def
语句之前有装饰器,则从下到上调用它们
顺序,在名称实际绑定之前 - 函数名称刚刚绑定到最后一个装饰器的返回对象。
课堂主体不同的是:
for
或while
循环直接放在类主体中 - 这些循环将在类创建时运行(通常在导入模块时)。 type
工厂来实际创建类:参数是类名,类库和对象的名称
(在类体中找到的函数和属性)作为字典。type
(或更确切地说,类'元类)的此调用的返回对象绑定到“class”语句所在的命名空间中的类名。(这实际上比创建函数更简单,而且你
实际上可以在野外找到更多的代码来创建一个没有的新类
一个类体,相反,调用type
,而不是创建调用FunctionType的新函数的代码
所以 - 回答你的问题:是的 - “装饰者按照他们遇到的顺序被调用” - 但是一旦你发现了Python的运作方式,这是很自然的。
所以,如果上面的解释有点模糊,请检查一下它的作用:
def log(func):
print(func.__name__)
return func
class A(object):
for i in range(5):
@log
def func(self):
pass
locals()["func_%d" % i] = func
并与之比较:
class B(object):
for i in range(5):
def func(self):
pass
func.__name__ = "func_%d" % i
locals()["func_%d" % i] = log(func)