Python 在Jython中使用getattr时出现堆栈溢出错误
我在Jython写一个文本编辑器。此文本编辑器有一个工具栏,其中显示有Python 在Jython中使用getattr时出现堆栈溢出错误,python,model-view-controller,jbutton,jython,getattr,Python,Model View Controller,Jbutton,Jython,Getattr,我在Jython写一个文本编辑器。此文本编辑器有一个工具栏,其中显示有ToolbarView类,并由ToolbarController类处理。有些操作不能由ToolbarController单独处理,因此这些操作被委托给MainController类 为了避免重复代码,因为有许多操作是从ToolbarController委托给MainController的,我使用了getattr,正如我在前面的问题中所建议的那样。我也意识到我可以在工具栏视图中使用相同的机制来操作按钮,但是我无法让它工作,结果我
ToolbarView
类,并由ToolbarController
类处理。有些操作不能由ToolbarController
单独处理,因此这些操作被委托给MainController
类
为了避免重复代码,因为有许多操作是从ToolbarController
委托给MainController的,我使用了getattr,正如我在前面的问题中所建议的那样。我也意识到我可以在工具栏视图中使用相同的机制来操作按钮,但是我无法让它工作,结果我得到了一个无限循环和一个Java StackOverflowerError
这是相关代码的摘录:
工具栏视图类:
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)
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)
from .ToolbarController import ToolbarController
class MainController(object):
def __init__(self):
self.toolbarController = ToolbarController(self)
def onNewFileClick(self, event):
print("MainController: Creating new file...")
def onEditFileClick(self, event):
print("MainController: Editting new file...")
def onSaveFileClick(self, event):
print("MainController: Saving new file...")
def onCloseFileClick(self, event):
print("MainController: Closing new file...")
工具栏控制器类:
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)
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)
from .ToolbarController import ToolbarController
class MainController(object):
def __init__(self):
self.toolbarController = ToolbarController(self)
def onNewFileClick(self, event):
print("MainController: Creating new file...")
def onEditFileClick(self, event):
print("MainController: Editting new file...")
def onSaveFileClick(self, event):
print("MainController: Saving new file...")
def onCloseFileClick(self, event):
print("MainController: Closing new file...")
主控制器等级:
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)
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)
from .ToolbarController import ToolbarController
class MainController(object):
def __init__(self):
self.toolbarController = ToolbarController(self)
def onNewFileClick(self, event):
print("MainController: Creating new file...")
def onEditFileClick(self, event):
print("MainController: Editting new file...")
def onSaveFileClick(self, event):
print("MainController: Saving new file...")
def onCloseFileClick(self, event):
print("MainController: Closing new file...")
所以我期望的是,当我单击按钮时,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)
回溯(最近一次呼叫最后一次):
文件“main.py”,第3行,在
主控制器()
文件“/home/training/Jython/controller/MainController”,第8行,在__
self.toolbarController=工具栏控制器(self)
文件“/home/Jython/controller/ToolbarController.py”,第8行,在__
self.view=工具栏视图(self)
文件“/home/Jython/controller/ToolbarView.py”,第44行,在__
button=JButton(名称,actionPerformed=getattr(self,method))
文件“/home/Jython/controller/ToolbarView.py”,第54行,在__
返回getattr(self.controller,name)
文件“/home/Jython/controller/ToolbarController.py”,第15行,在__
返回getattr(self.mainController,名称)
文件“/home/Jython/controller/ToolbarController.py”,第15行,在__
返回getattr(self.mainController,名称)
[...]
文件“/home/Jython/controller/ToolbarController.py”,第15行,在__
返回getattr(self.mainController,名称)
运行时错误:超过最大递归深度(Java StackOverflowerError)
我做错了什么?我在python中也尝试过类似的方法(从一个类到另一个类的委托),如果在getattr之后放置一个put()
,它就会起作用,但是在这里我会感到困惑,因为JButton中执行了操作。我试过了,但结果都一样 你似乎在使用Jython,我真的不知道。无论如何,在python中,您重写了\uuu getattr\uuu
,然后您应该期望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
是如何处理的。如果覆盖\uuuu getattr\uuuu
,则只有在尝试引用未定义的字段时,才会调用此钩子:
>>> class A(object):
defined = True
def __getattr__(self, name):
print "referenced :" + name
>>> a = A()
>>> a.defined
True
>>> a.undefined
referenced :undefined
希望现在能弄清楚钩子是怎么工作的
因此,so实际上是由于您引用了不属于MainController
的内容造成的
在您的MainController
中,仅定义了onNewFileClick
,但您定义了3个其他选项:
options= ['NewFile', 'OpenFile', 'SaveFile', 'CloseFile']
因此,这将发生在第二轮迭代中。由于main控制器
没有打开文件单击
,将引发一个属性错误
,但被ToolbarController
捕获,因此被覆盖的\uu getattr\uuuu
将被调用并继续。这就是你的调用堆栈爆炸的原因。我把这归咎于getattr
,因为我还没有信心使用它,但事实证明它是相当基本的东西
在创建工具栏视图之后,我将main控制器分配给ToolbarController
,该视图随后调用ToolbarView.\uuuu getatrr\uuuuuuuu
,该视图调用ToolbarController.\uu getattr\uuuuuuuuuu
,试图访问尚不存在的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)
之后:
from .ToolbarView import ToolbarView
class ToolbarController(object):
def __init__(self, mainController):
#Needs to delegate to main presenter.
#Note self.mainController needs to exist before creating the ToolbarView
#since it needs delegating actions to it!
self.mainController = mainController
#Create view with a reference to its controller to handle events
self.view = ToolbarView(self)
def __getattr__(self, name):
return getattr(self.mainController, name)
非常感谢@hustmphrr和@ArtOfWarfare的帮助。这与您的主控制器无关。我想看看actionPerformed=getattr(self,method)
,什么是self.method
?例如,为什么需要使用getattr
而不是
运算符?我想知道两件事#1-为什么您没有为MainController
和ToolbarController
指定基类?我在Jython中根本没有做过OOP,只做过函数式编程,但我的理解是Jython一直停留在版本2,这意味着您的对象应该继承自object
,而不是什么都不继承,如果您想依赖新样式的类行为(我认为getattr
是其中的一部分)#2-你的课程真的和你想象的一样吗?调试-在ToolbarController.\uuu getattr\uuu
中,打印出self.mainController
的类。我猜这是一个ToolbarController
实例。谢谢你的提示,@ArtOfWarfare#1 Jython仍在版本2.X中。我现在更改了我的类,它们从对象继承。我也会用这个来编辑我的问题#2.很有趣。我在尝试访问self.mainController.\uuuuu class\uuuuuu.\uuuuuuu name\uuuuuuuuu
时遇到堆栈溢出错误,因此引起问题的不是getattr,似乎是对mainController的引用:OI'm Study!创建后,我将mainController
分配给ToolbarController