如何从python中的类属性中分配方法装饰器?

时间:2013-04-07 05:26:40

标签: python

所以,我知道我可以毫无问题地做到这一点:

button = widget.libray.Button()

class X():
  @button.on_click
  def click(self, event):
    ...

没有问题。

......但这很令人生气,因为现在'按钮'超出了课堂范围;我希望这是一个阶级财产。如何为类成员使用@blah修饰语法?

我当然不能使用装饰器,如下所示:

class UiDemo(cocos.cocosnode.CocosNode):

  def on_enter(self):
    self.b = Button(text='Hello World')
    self.bt = b.event(self.bt) # <--- !!! Instead of decorator!
    vbox = VBox(elements=[self.b])
    self.dialog = Dialog(title='My Dialog', x=100, y=100, content=vbox, width=200, height=100)
    cocos.director.director.window.push_handlers(self.dialog)

  # @self.b.event doesn't work here, obviously.
  def bt(self, button):
     print('Button pressed: %s' % button)

  def on_exit(self):
    cocos.director.director.window.remove_handlers(self.dialog)

  def draw(self):
    self.dialog.on_draw()

class Client:
  def run(self):
    cocos.director.director.init()
    test = UiDemo()
    main_scene = cocos.scene.Scene(test)
    cocos.director.director.run (main_scene)

我的意思是,我看到了问题;这个方法是在类定义时定义的(我猜),所以即使你在 init ()步骤中创建了widget,它也不存在于类定义的位置被解析,因此当时它不能用作装饰器。

我想知道的是,有什么方法可以解决这个问题吗?

肯定有很多情况你希望你的decorator属性引用附加到类的东西的实例?

(正如你从我上面的例子中看到的,这个不是只是一个“假设”情况;这是本周第二次我最终使用了详细的self.func = self.instance.dec(self.func)表单来执行此操作)

有什么建议吗?

(......显然,除了使用不这样做的库,因为它是愚蠢的;这不是真正的解决方案。:P)

2 个答案:

答案 0 :(得分:3)

您可以将按钮设为类属性:

class X():
  button = widget.libray.Button()

  @button.on_click
  def click(self, event):
    # blah

如果您尝试连接多个X实例(因为它们将共享相同的按钮),这当然会导致问题,但如果您已全局定义button,则这已成为问题。

您已准确诊断出问题:装饰发生在类定义时,但您希望方法与实例关联。最终,试图用这些技巧强迫它可能会让人感到困惑。您正在创建的按钮实例在概念上与X的实例相关联,而不是类本身。你可以合理地创建一个你打算多次实例化的GUI类(对于某些特定样式的小部件,或者其他什么),在这种情况下你必须放弃这些技巧,因为你真的需要在你希望绑定事件的时间。

如果你真的想,你可以设计一个更精细的方案来处理这个问题。例如,您可以使用@onclick('button')之类的装饰器将名称button存储为方法对象的属性。然后,您可以在__init__中使用代码来迭代对象的方法,并将它们绑定到GUI小部件上具有相应名称的事件。 (也就是说,您创建一个按钮并将其存储为self.button,然后__init__将此属性的名称与传递给装饰器的名称相关联,并绑定事件。)

然而,做一件显而易见的事情可能更简单:不要尝试使用装饰器来处理类级别的特定于实例的行为。只需绑定方法代码中的事件,如第二个示例所示。

答案 1 :(得分:1)

在我看来,由于你想要装饰而没有必要,所以出现了混乱。你真正需要做的是注册一个回调。除了注册之外,还没有一点装饰回调。

将按钮作为成员,就像您已经拥有的那样,并将回调注册到它。

def on_enter(self):
    self.b = Button(text='Hello World')
    b.event(self.bt) # register, don't decorate

此外,您无法使用装饰器(除非创建全局Button),因为装饰是在定义类时完成的,Button member只在创建一个对象时被实例化,因此你不能在那时注册一个回调。