Python 类中的装饰器:不能在装饰函数内使用self
我正试图实现一个带有装饰器的自定义记录器,该装饰器将以以下方式收集异常(稍后保存到db):Python 类中的装饰器:不能在装饰函数内使用self,python,decorator,Python,Decorator,我正试图实现一个带有装饰器的自定义记录器,该装饰器将以以下方式收集异常(稍后保存到db): import functools class Log: def __init__(self): self.mssg = "" self.err = "" class Parent: def __init__(self): self.logger = Log() def logging(fun): @functoo
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未定义
我还尝试了各种组合以将self.logger
作为函数的参数传递,但我有点困惑,它们失败了。。。有人有办法解决我的问题吗?正如您可能故意做的那样,在类astaticmethod
中创建函数会使其成为“静态”的,从而使其无法访问实例的“self”属性。另外,类的\uuuuu init\uuuu
从未运行过,因为您从未创建过该类的实例
您也可以通过在子命名空间中创建父实例来执行类似操作:
注意:此方法不涉及继承,如果您认为这是必要的,请尝试@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
正如您可能有意做的那样,在类a
staticmethod
中创建函数会使其成为“静态”函数,从而使其无法访问实例的“self”属性。另外,类的\uuuuu init\uuuu
从未运行过,因为您从未创建过该类的实例
您也可以通过在子命名空间中创建父实例来执行类似操作:
注意:此方法不涉及继承,如果您认为这是必要的,请尝试@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
你的代码有几个问题。看看评论
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
你的代码有几个问题。看看评论
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
您可以按照下面的代码所示进行操作,这与您的方法有两种主要方式不同。它将
日志记录
更改为一个(嵌套)类,并将其作为一个单例实现,因此只会创建它的一个实例
这样做意味着您必须使用@Parent.logging()
调用装饰程序,而不仅仅是@Parent.logging
。这可以确保创建Log
实例并将其分配给self.logger
,其中self
是logging
类的单例实例。请注意,\uuu call\uu()
不是一个静态方法
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
您可以按照下面的代码所示进行操作,这与您的方法有两种主要方式不同。它将
日志记录
更改为一个(嵌套)类,并将其作为一个单例实现,因此只会创建它的一个实例
这样做意味着您必须使用@Parent.logging()
调用装饰程序,而不仅仅是@Parent.logging
。这可以确保创建Log
实例并将其分配给self.logger
,其中self
是logging
类的单例实例。请注意,\uuu call\uu()
不是一个静态方法
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
猜测一下,日志方法中的
self
没有定义,因为它没有作为参数显式传递给logging
或internal
。您可能需要从(*args
的第一个元素)获取它。猜测一下,日志方法中的self
没有定义,因为它没有作为参数显式传递给logging
或internal
。您可能需要从*args
的(第一个元素)中获取它。您还可以将内部
定义为定义内部(self,*args)
,这样您不仅可以免费获得自我
,而且还可以直接看到decorstor创建了一个方法。@SuperSaiyan Thax这太棒了!有一件事我不明白,那就是那行super(Child,self)。\uuu init\uuu()
。这是干什么的?@SuperSaiyan实际上我现在明白了,但为什么它比调用Parent好。uu init_uu()您还可以将internal
定义为definner(self,*args)
,这样您不仅可以免费获得self
,而且可以直接看到Decorsortor创建了一个方法。@SuperSaiyan Thax这太棒了!有一件事我不明白,那就是那行super(Child,self)。\uuu init\uuu()
。这是干什么的?@SuperSaiyan实际上我现在明白了,但为什么它比调用Parent好呢?\uuu init\uuu()@abccd我在使用继承,就像在我的真实代码中一样,我想将记录器应用到不同的类。。。无需复制粘贴everywhere@abccd我正在使用继承,因为在我的真实代码中,我想将记录器应用到不同的类。。。无需复制粘贴到任何地方