我的目标是创建一个带有Log类的简单日志模块,我可以在其他项目中使用它来跟踪事物。特别是,我想创建一个" @ tracemethod"装饰器记录所有方法调用(方法名称和参数)。这是一个非常简化(但功能性)的类:
class Log :
def __init__(self, path) :
self.path = path
# here is a whole path-checking routine.
def log(self, msg):
with open(self.path, mode="a+") as log_file :
log_file.write(msg + "\n")
def tracemethod(self, f):
def wrapped(self2, *args, **kwargs) :
outstring = "{}({},{})".format(f.__name__, str(args), str(kwargs))
self.log(outstring)
return f(self2, *args, **kwargs)
return wrapped
它有效,我可以在另一个模块中调用该类并使用它:
from log import Log
log1 = Log("/Path/to/existing_log_file.txt")
class Foo() :
@log1.tracemethod
def __init__(self, a, b, c) :
self.a = a
self.b = b
self.c = c
@log1.tracemethod
def a_method(self, c, d, e):
return c+d+e
foo = Foo(4,5, c=5 )
foo.a_method(32, 64, e=9)
在existing_log_file.txt中给出了:
__init__((4, 5),{'c': 5})
a_method((32, 64),{'e': 9})
但正如你所看到的," tracemethod" Log类中的方法使用" self2"用于区分Log实例和Foo实例的参数。我听说过重命名" self"是一个很大的禁忌。什么是实现这一目标的正确/ pythonic方式?
答案 0 :(得分:2)
当你真正需要访问被包裹的self
时,这是一个两难的问题 - 你有一个指导方针告诉你不要重命名self
个参数,而是更强的指导方针你不要用另一个self
遮蔽。{/ p>
PEP 8中没有任何内容可以告诉你该怎么做;文档中甚至都没有示例。
但这是有原因的。实际上,您需要访问已包装的self
非常罕见。看看你的代码:你不能对self2
做任何事情:
def tracemethod(self, f):
def wrapped(self2, *args, **kwargs) :
outstring = "{}({},{})".format(f.__name__, str(args), str(kwargs))
self.log(outstring)
return f(self2, *args, **kwargs)
return wrapped
你显然想在输出中跳过它,但你可以通过切片[1:]
来做到这一点。因此,就像文档中的所有示例一样,将其保留在*args
中,而不是将其作为单独的参数拉出来:
def tracemethod(self, f):
def wrapped(*args, **kwargs) :
outstring = "{}({},{})".format(f.__name__, str(args[1:]), str(kwargs))
self.log(outstring)
return f(*args, **kwargs)
return wrapped
所以,在你的情况下,避免了问题。
什么时候你可以逃脱这个?
在这种情况下,似乎并不是一个被广泛接受的标准。真的,任何可以清楚地了解哪个是哪个,并且容易在视觉上区分两者的东西都可以; self2
并没有完全消除它,但是AMADANON的wrappedself
确实如此。
我认为我见过的两个最常见的名字是inner_self
和wrapped_self
(有或没有下划线),但没有进行更科学的调查,我不会过分依赖。
我也看过一个教程(虽然我不记得在哪里),建议将所有内容包装在另一个函数调用中以避免问题出现,但这对我来说似乎很愚蠢。
答案 1 :(得分:1)
我认为最狡猾的方式是跳过内心" self"总之,只需使用* args和** args(args [0]将是" self",如果你需要它):
def tracemethod(self, f):
def wrapped(*args, **kwargs) :
outstring = "{}({},{})".format(f.__name__, str(args), str(kwargs))
self.log(outstring)
return f(*args, **kwargs)
return wrapped
毕竟,self是其中一个参数。这样你的装饰器也可以用于常规(非对象)函数。
或者,更换" self"用"包裹自己" (或类似的东西),那么你可以使用" self"而不是" self2":
def tracemethod(wrappedself, f):
def wrapped(self, *args, **kwargs) :
outstring = "{}({},{})".format(f.__name__, str(args), str(kwargs))
wrappedself.log(outstring)
return f(self, *args, **kwargs)
return wrapped