a.py
import d
d.funcme('blah')
d.py
import sys
import Errors
def argcheck(in_=(), out=(type(None),)):
def _argcheck(function):
# do something here
def __argcheck(*args, **kw):
print '+++++++++ checking types before calling the func'
# do something here
res = function(*args, **kw)
return res
return __argcheck
return _argcheck
@argcheck((str)) <-----
def funcme(name):
try:
f = sys._getframe(1)
except ValueError, err:
raise Errors.UserError(err) # stack too deep
filename, lineno = f.f_globals['__name__'], f.f_lineno
print filename, lineno
没有argcheck装饰器的OUTPUT(注释掉@argcheck((str))
):
$ python a.py
__main__ 3
使用argcheck
装饰器输出:
$ python a.py
+++++++++ checking types before calling the func
defines 9
问题:
装饰师做了什么,以便改变_getframe
的值?
如何保存信息以便捕获原始信息,即__main__
3而不是定义9?
答案 0 :(得分:2)
问题是你的funcme()
函数假设它是直接调用而不是通过其他东西间接调用 - 比如装饰器。这可以通过更改其调用顺序并添加一个带有默认值的附加depth
关键字参数来修复,该默认值将传递给_sys._getframe()
。有了这个脚手架,装饰器就可以覆盖默认值。无论是否已应用装饰器,以下内容都将打印相同的内容:
1 import sys
2 import Errors
3 def argcheck(in_=(), out=(type(None),)):
4 def _argcheck(function):
5 # do something here
6 def __argcheck(*args, **kw):
7 print '+++++++++ checking types before calling the func'
8 # do something here
9 res = function(*args, depth=2, **kw) # override default depth
10 return res
11 return __argcheck
12 return _argcheck
13
14 @argcheck((str))
15 def funcme(name, depth=1): # added keyword arg with default value
16 try:
17 f = sys._getframe(depth) # explicitly pass stack depth wanted
18 except ValueError, err:
19 raise Errors.UserError(err) # stack too deep
20
21 filename, lineno = f.f_globals['__name__'], f.f_lineno
22 print filename, lineno
答案 1 :(得分:1)
装饰者基本上是语法糖。这样:
@argcheck((str))
def funcme(name):
与此相同:
funcme = argcheck(str)(funcme)
现在您可以看到装饰器更改调用堆栈的原因。
我不确定如何在任意情况下解决这个问题,但如果您事先知道装饰器的某些内容,您可以补偿代码。您也可以查看functools.wraps,也许这会提供一些可能有帮助的线索。