在Jython中使用getattr时出现stackoverflower错误

2024-10-08 18:22:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用Jython编写一个文本编辑器。这个文本编辑器有一个工具栏,它用ToolbarView类显示,并由ToolbarController类处理。有些操作不能由ToolbarController单独处理,因此这些操作被委托给MainController类。在

为了避免重复代码,因为有很多操作从ToolbarController委托给主控制器,我使用了getattr,正如我在上一个问题here中建议的那样。我还意识到我可以在ToolbarView代码中使用相同的机制来执行按钮的操作,但我无法使其工作,最终得到一个无限循环和一个Java StackOverflowError。在

以下是相关代码的摘录:

工具栏视图类:

from javax.swing import JToolBar, ImageIcon, JButton

class ToolbarView(JToolBar):

    def __init__(self, controller):

        #Give reference to controller to delegate action response
        self.controller = controller

        options= ['NewFile', 'OpenFile', 'SaveFile', 'CloseFile']
        for option in options:
            methods[option] = "on" + option + "Click"
            print methods[option]

        for name, method in methods.items():
            button = JButton(name, actionPerformed=getattr(self, method))
            self.add(button)

    def __getattr__(self, name):
        return getattr(self.controller, name)

工具栏控制器类:

^{pr2}$

main控制器类:

^{3}$

所以我期望的是,当我单击按钮时,MainController.onNewFileClick将被执行并在控制台中打印出该消息。如果我想从ToolbarView委托给ToolbarController,它可以工作,但是当我把这个委托从ToolbarController传递给主控制器时,它就不起作用了。它似乎在一个无限的循环中自我调用。我得到的错误是:

Traceback (most recent call last):
  File "main.py", line 3, in <module>
    MainController()
  File "/home/training/Jython/controller/MainController", line 8, in __init__
    self.toolbarController = ToolbarController(self)
  File "/home/Jython/controller/ToolbarController.py", line 8, in __init__
    self.view = ToolbarView(self)
  File "/home/Jython/controller/ToolbarView.py", line 44, in __init__
    button = JButton(name, actionPerformed=getattr(self, method))
  File "/home/Jython/controller/ToolbarView.py", line 54, in __getattr__
    return getattr(self.controller, name)
  File "/home/Jython/controller/ToolbarController.py", line 15, in __getattr__
    return getattr(self.mainController, name)
  File "/home/Jython/controller/ToolbarController.py", line 15, in __getattr__
    return getattr(self.mainController, name)

[...]

  File "/home/Jython/controller/ToolbarController.py", line 15, in __getattr__
    return getattr(self.mainController, name)
RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)

我做错什么了?我在python中尝试过类似的方法(从一个类委托给另一个类),如果在getattr后面加一个put ()就可以了,但是这里我感到困惑,因为JButton中的actionPerformed。我试过了,但结果是一样的。在


Tags: nameinpyselfhomereturnlinejython
2条回答

你好像在用Jython,我真的不知道。无论如何,在python中,您重写了__getattr__,那么您应该期望getattr使用被重写的钩子。所以我觉得你的意思是:

class ToolbarView(JToolBar):

    def __init__(self, controller):

        #Give reference to controller to delegate action response
        self.controller = controller

        options= ['NewFile', 'OpenFile', 'SaveFile', 'CloseFile']
        for option in options:
            methods[option] = "on" + option + "Click"
            print methods[option]

        for name, method in methods.items():
            button = JButton(name, actionPerformed=super(ToolbarView, self).__getattr__(method))
            self.add(button)

    def __getattr__(self, name):
        return getattr(self.controller, name)

观察按钮是如何创建的。在

至于为什么会有这样的问题,那是因为getattr是如何处理的。如果重写__getattr__,则只有在尝试引用未定义的字段时才会调用此钩子:

^{pr2}$

希望现在钩子是怎么工作的。在

所以so实际上是因为您引用了不属于MainController的内容。在

在您的MainController中,只定义了onNewFileClick,但您定义了3个其他选项:

options= ['NewFile', 'OpenFile', 'SaveFile', 'CloseFile']

所以,这将发生在第二轮迭代中。由于MainController没有onOpenFileClick,一个AttributeError将被引发,但被ToolbarController捕获,因此被重写的{}将被调用并打开。这就是你的调用堆栈爆炸的原因。在

我把这归咎于getattr,因为我还没有那么自信地使用它,但事实证明它是相当基本的东西。在

我在创建ToolbarView之后将ToolbarController分配给ToolbarController,后者调用ToolbarView.__getatrr__,后者试图访问尚不存在的self.mainController!在

这是我需要在ToolbarController类中进行的更改。在

之前

from .ToolbarView import ToolbarView
class ToolbarController(object):

    def __init__(self, mainController):

        #Create view with a reference to its controller to handle events
        self.view = ToolbarView(self)

        #Will also need delegating to parent presenter
        self.mainController = mainController

    def __getattr__(self, name):
        return getattr(self.mainController, name)

之后:

^{pr2}$

非常感谢@hustmphrr和@ArtOfWarfare的帮助。在

相关问题 更多 >

    热门问题