簡體   English   中英

類中的裝飾器:無法在裝飾函數內部使用self

[英]Decorator in class: cannot use self inside the decorated function

我試圖用裝飾器實現一個自定義記錄器,該裝飾器將以以下方式收集異常(以后將它們保存到數據庫):

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 is not defined我也嘗試了各種組合以將self.logger作為函數的參數傳遞,但是我有點困惑,並且它們失敗了……任何人都可以解決我的問題?

您的代碼有幾個問題。 看評論。

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

正如您可能故意做到的那樣,將類中的函數設為staticmethod會使它“靜態”,從而使其無法訪問實例的“自身”屬性。 另外,該類的__init__永遠不會運行,因為您從未創建該類的實例。

您也可以通過在Child名稱范圍中創建Parent實例來執行以下操作:

注意:此方法不涉及繼承,如果您認為有必要,請嘗試@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

您可以按照以下代碼所示進行操作,這與您的方法有所不同,主要有兩種。 它將logging更改為(嵌套的)類,並將其實現為單例,因此將僅創建其一個實例。

這樣做意味着你必須調用與裝飾@Parent.logging()而不是僅僅@Parent.logging 這樣可以確保創建一個Log實例並將其分配給self.logger ,其中selflogging類的單例實例。 請注意__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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM