我正在尝试使用装饰器实现一个自定义记录器,该装饰器将以下列方式收集异常(以便将它们保存到db):
import functools
class Log:
def __init__(self):
self.mssg = ""
self.err = ""
class Parent:
def __init__(self):
self.logger = Log()
def logging(fun):
@functools.wraps(fun)
def inner(*args):
try:
print(fun.__name__)
self.logger.mssg += fun.__name__ +" :ok, "
return fun(*args)
except Exception as e:
self.logger.err += fun.__name__ +": error: "+str(e.args)
return inner
logging = staticmethod(logging)
class Child(Parent):
def __init__(self, a, b):
self.a = a
self.b = b
@Parent.logging
def sum_(self):
return self.a + self.b
然而,似乎装饰者"打破"方法和实例之间的链接,因为它不能再使用self ...运行时
c = Child(3,6)
c.sum_()
我收到错误消息self is not defined
我也尝试了各种组合来传递self.logger
作为函数的参数,但我有点困惑,他们失败了......任何人都有一个想法可以解决我的问题吗?
答案 0 :(得分:1)
您的代码存在一些问题。看看评论。
import functools
class Log:
def __init__(self):
self.mssg = ""
self.err = ""
class Parent(object):
def __init__(self):
self.logger = Log()
@staticmethod #You can directly use staticmethod decorator!
def logging(fun):
@functools.wraps(fun)
def inner(*args):
self = args[0] #Grab the first arg as self.
try:
print(fun.__name__)
self.logger.mssg += fun.__name__ +" :ok, "
return fun(self, *(args[1:])) # Call the function using
# self that we extracted.
except Exception as e:
self.logger.err += fun.__name__ +": error: "+str(e.args)
return inner
class Child(Parent):
def __init__(self, a, b):
super(Child, self).__init__() #Don't forget call the parent ctor
self.a = a
self.b = b
@Parent.logging
def sum_(self):
return self.a + self.b
c = Child(3,6)
print c.sum_() #Outputs 9
答案 1 :(得分:0)
正如您可能故意这样做的那样,在staticmethod
课程中创建一个函数会使其成为静态",使其无法访问" self"实例的属性。此外,该类的__init__
从未运行,因为您从未创建过该类的实例。
您也可以通过在子名称范围中创建父实例来执行此类操作:
注意:此方法不涉及继承,如果您认为有必要,请尝试@SuperSaiyan的回答
import functools
class Log:
def __init__(self):
self.mssg = ""
self.err = ""
class Parent:
def __init__(self):
self.logger = Log()
def logging(self, fun): # include the "self" argument as it is no longer static
@functools.wraps(fun)
def inner(*args):
try:
print(fun.__name__)
self.logger.mssg += fun.__name__ +" :ok, "
return fun(*args)
except Exception as e:
self.logger.err += fun.__name__ +": error: "+str(e.args)
return inner
class Child: # you do not need to inherit the Parent class if it's only used for the decorator
myparent = Parent() # initiates the logger and create an instance of that class
def __init__(self, a, b):
self.a = a
self.b = b
@myparent.logging # use myparent instead of Parent
def sum_(self):
return self.a + self.b
c = Child(3, 6)
print(c.sum_()) # prints sum_ and 9
答案 2 :(得分:0)
您可以按照以下代码中所示执行此操作,该代码以两种主要方式与您的方法不同。它将logging
更改为(嵌套)类并将其实现为单例,因此只会创建它的一个实例。
这样做意味着您必须使用@Parent.logging()
而不是@Parent.logging
来调用装饰器。这可确保创建Log
实例并将其分配给self.logger
,其中self
是logging
类的单例实例。请注意,__call__()
不是静态方法。
import functools
class Log(object):
def __init__(self):
self.msg = ""
self.err = ""
class Parent(object):
class logging(object): # singleton decorator class
def __init__(self):
self.logger = Log()
def __new__(cls, *args, **kwargs):
if '_inst_' not in vars(cls):
cls._inst = object.__new__(cls)
return cls._inst
def __call__(self, fun):
@functools.wraps(fun)
def inner(*args, **kwargs):
try:
print(fun.__name__)
self.logger.msg += fun.__name__+" :ok, "
return fun(*args, **kwargs)
except Exception as exc:
self.logger.err += fun.__name__+": error: "+str(exc.args)
return inner
class Child(Parent):
def __init__(self, a, b):
super(Child, self).__init__() # initialize Parent
self.a = a
self.b = b
@Parent.logging() # must call and create decorator instance
def sum_(self):
return self.a + self.b
c = Child(3, 6)
print(c.sum_()) # -> 9