【问题标题】:I can't get private class decorator to work我无法让私人班级装饰员工作
【发布时间】:2020-10-20 17:00:16
【问题描述】:

我正在尝试获取一个私有类装饰器,或者至少是一个与类工作相关的装饰器。我一直在尝试使用内联类,但目前在运行它时遇到以下问题:

click_ImportToDB() missing 1 required positional argument: 'self'

如果您可以查看以下内容,我已经删减了很多内容并让我知道我做错了什么,那就太好了:

class frmApplication(tk.Frame):

    # THIS IS THE PRIVATE INLINE CLASS DECORATOR THAT I AM TRYING TO BUILD.
    class _form_validation():
        def __init__(self, func):
            self.func = func
        
        def __call__(self):
            # Wrap the function up in error trapping and form validation
            try:
                # Ensure the strDBPath and config file have the same value for the database
                # Ensure the database actually exists
                # Now call the function
                self.func()
            except Exception as Ex:
                strReport=Ex.args[0]
                messagebox.showerror("Error",strReport)


    #BACK TO THE frmApplication CLASS
    def __init__(self,FormParent=tk.NONE):
        .....

    def __populateDatabaseFrame(self):
        ....

    def __populateButtonFrame(self):
        #First, add a frame
        self.__objButtonFrame=ttk.Frame(self.master,border=2,relief=tk.SUNKEN)
        self.__objButtonFrame.grid(row=1,column=0,columnspan=1,sticky=tk.N+tk.S+tk.E+tk.W,padx=10,pady=10)
        F=self.__objButtonFrame
        #Configure the columns of the frame
        F.grid_columnconfigure(0,weight=1)
        #Now add an upload to database button into the frame

        # THERE IS A CALL TO click_ImportToDB HERE !!!!!
        F.__btnImportToDB=ttk.Button(F,text="Upload to Database",command=self.click_ImportToDB)
        F.__btnImportToDB.grid(row=0,column=0,sticky=tk.E+tk.W,padx=10,pady=10)



        #Now add a button to show the data
        .....

    def __createDatabase(self):
        ...

    def __selectDatabase(self):
        ...
    
    #Public Functions.
    def click_SelectDB(self):
        ...

    def click_NewDB(self):
        ....

    @_form_validation
    def click_ImportToDB(self):
        frmTop=tk.Toplevel(self.master)
        frmTop.transient(frmTop.master)
        frmTop.focus_set()
        frmTop.grab_set()
        objFrm=vID.frmImportToDB(frmTop)
        frmTop.wait_window()
        del objFrm

非常感谢

标记

【问题讨论】:

  • 你能分享你的包装代码吗?
  • 您好 Nivardo,代码非常庞大且复杂。如果这很复杂,请不要担心。我认为向一个类添加一个装饰器会很简单,但我似乎无法让“自我”部分正确传播。我在网上没有找到任何示例,所以可能无法完成。

标签: python-3.x class python-decorators


【解决方案1】:

我不确定你是否将参数从装饰器传递给函数。

class Test():
    class _decorator(object):

        def __init__(self, arg):
            self._arg = arg
            print(self._arg)
        def __call__(self):
            print("DOING SOMETHING HERE BEFORE THE FUNC EXEC")
            retval = self._arg(self)
            print("DOING SOMETHING HERE AFTER THE FUNC EXEC")

            return retval


    @_decorator
    def test_method(self):
        print("EXECUTING FUNC")
        return "RETURN FROM TEST_METHOD"

if __name__ == '__main__':
    test = Test()
    print(test.test_method())

我试图创建此代码来复制您的疑问。

尝试,将self 传递给您的函数。

如果这不起作用。您不能尝试使用 noraml 装饰器代替类装饰器,这里是相同的示例。

from functools import wraps


class Test():

    def _decorator(f):
        @wraps(f)
        def wrapped(inst, *args, **kwargs):
            print("EXECUTING BEFORE FUNC")

            return_val = f(inst, *args, **kwargs)
            print("EXECUTING AFTER FUNC")
            return return_val
        return wrapped


    @_decorator
    def test_method(self):
        print("EXECUTING FUNC")
        return "RETURN FROM TEST_METHOD"

if __name__ == '__main__':
    test = Test()
    print(test.test_method())

希望对你有帮助。

【讨论】:

    【解决方案2】:

    感谢您的帮助。第一个建议并没有真正奏效。我已经编辑了代码以帮助解释问题所在:

    class Test():
    
        def __init__(self):
            self.name = 'test class'
    
        class _decorator(object):
    
            def __init__(self, arg):
                self.name = '_decorator class'
                self._arg = arg
                
    
            def __call__(self):
                print("\n---- BEFORE FUNCTION EXECUTION ----\n")
                print('self points to: "' + self.name + '"')
                print('However I really need it to point to the test class to perform validation etc.')
                self._arg(self)
                print("\n---- AFTER FUNCTION EXECUTION ----\n")
    
    
        @_decorator
        def test_method(self):
            print('self points to: "' + self.name + '"')
            print("**** Executing test_method ****")
            
    
    if __name__ == '__main__':
        test = Test()
        test.test_method()
    

    输出如下:

    ---- BEFORE FUNCTION EXECUTION ----
    
    self points to: "_decorator class"
    However I really need it to point to the test class to perform validation etc.
    self points to: "_decorator class"
    **** Executing test_method ****
    
    ---- AFTER FUNCTION EXECUTION ----
    

    我确实尝试将第二个选项调整如下:

    from functools import wraps
    
    class Test():
    
        def __init__(self):
            self.name = 'Test Class'
    
        def _decorator(f):
            @wraps(f)
            def wrapped(inst, *args, **kwargs):
    
                print('inst points to: '+inst.name)
    
                print("EXECUTING BEFORE FUNC")
                return_val = f(inst, *args, **kwargs)
                print("EXECUTING AFTER FUNC")
    
                return return_val
    
            return wrapped
    
    
        @_decorator
        def test_method(self):
            print("EXECUTING FUNC")
            return "RETURN FROM TEST_METHOD"
    
    if __name__ == '__main__':
        test = Test()
        print(test.test_method())
    

    输出如下:

    inst points to: Test Class
    EXECUTING BEFORE FUNC
    EXECUTING FUNC
    EXECUTING AFTER FUNC
    RETURN FROM TEST_METHOD
    

    这看起来更像我所追求的。唯一的缺点是 linter 现在报告以下问题,但它并没有阻止它工作:

    Method '_decorator' should have 'self' as first argument.Python(no-self-argument)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      相关资源
      最近更新 更多