【问题标题】:Calling a method from an existing instance从现有实例调用方法
【发布时间】:2014-06-02 12:09:33
【问题描述】:

我对面向对象编程的理解有点不稳定,所以如果你有任何链接可以帮助解释这些概念,我会很高兴看到它们!

我已经稍微缩短了代码。基本原则是我有一个以主 Controller 类的实例开始的游戏。当游戏打开时,Popup 类被打开。事件发生如下:

  1. 点击弹出窗口上的开始按钮
  2. start_click() 方法运行
  3. 在Controller实例中调用start_game()方法
  4. 这又将原始控制器实例中的游戏状态更改为“真”

我的问题在于第 3 步。我收到的错误消息是:

TypeError: unbound method start_game() must be called with Controller 
instance as first argument (got nothing instead)

我想 StartPopUp 类中需要对 Controller 类进行一些引用。但我不太明白如何创建该参考?

import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.properties import BooleanProperty, NumericProperty, ObjectProperty
from kivy.uix.popup import Popup
from kivy.lang import Builder

Builder.load_string('''
<StartPopUp>            
    size_hint: .2, .2
    auto_dismiss: False
    title: 'Welcome'
    Button:
        text: 'Play'
        on_press: root.start_click()
        on_press: root.dismiss()

''')

class StartPopUp(Popup):

    def __init__(self, **kw):
        super(StartPopUp, self).__init__(**kw)

    def start_click(self):
        Controller.start_game()                    

class Controller(Widget):
    playing_label = BooleanProperty(False)          #Intitial phase of game is off

    def __init__(self, **kw):
        super(Controller, self).__init__(**kw)        

    def start_popup(self, dt):    
        sp = StartPopUp()
        sp.open()

    def start_game(self):
        self.playing_label = True
        print self.playing_label   

class MoleHuntApp(App):

    def build(self):
        game = Controller()
        Clock.schedule_once(game.start_popup, 1)
        return game

if __name__ == '__main__':
    MoleHuntApp().run() 

提前致谢!

【问题讨论】:

    标签: android python python-2.7 kivy


    【解决方案1】:

    你可以这样传递实例

    class StartPopUp(Popup):
    
        def __init__(self, controller, **kw):
            super(StartPopUp, self).__init__(**kw)
            self.controller = controller
    
        def start_click(self):
            self.controller.start_game()
    

    在控制器中

    def start_popup(self, dt):    
        sp = StartPopUp(self)
        sp.open()
    

    【讨论】:

      【解决方案2】:

      您需要在 Controller 类的实例上调用 start_game()。例如,

      def start_click(self):
          controller = Controller()
          controller.start_game()
      

      这样,startgame()self 参数将指向controller 对象。但是您需要跟踪创建的Controller 实例,以便以后能够再次修改它。在这种情况下,没有理由将 playing_label 作为静态变量。

      您可能想要的是一个静态方法,无需拥有Controller 类的实例即可调用。为此,您可以使用staticmethod decoratorstart_game() 设为静态方法,如下所示:

      @staticmethod
      def start_game():
          Controller.playing_label = True
          print Controller.playing_label
      

      然后,您可以继续使用Controller.start_game()

      【讨论】:

      • 我尝试了你方法中的 staticdecorator 部分,效果很好!但我不太明白。假设您有两个控制器实例,如果您调用静态方法,该方法是否正在运行,并且正在更新两个控制器实例中的播放标签?
      • 是的,静态方法和静态变量不是每个实例。因此,“playing_label 在两个控制器实例中都被更新”在技术上是不正确的。由于您在哪里定义了playing_label,所以对于创建的controller 的所有实例,它只有一个值。
      【解决方案3】:

      从错误消息中可以明显看出,必须为控制器类的特定实例调用方法start_game()。您可以为控制器类添加一个getInstance() 方法,该方法返回控制器的当前活动实例。在调用start_game() 之前,从start_click() 方法内部调用它。假设它返回instanceC。然后你可以从start_click()调用start_game()方法为instanceC.start_game()

      【讨论】:

      • 我觉得这个方法有点过头了,我尝试过但无法让它发挥作用,希望一旦我了解了更多关于 OOP 的知识,我会回到它!
      【解决方案4】:

      尝试在创建 StartPopUp 对象的那一刻传递游戏对象,并让 StartPopUp 保留对它的引用,以便以后可以将此实例用于 start_click() 方法,如下所示:

      class StartPopUp(Popup):
      
          def __init__(self, game_ctrl, **kw):
              super(StartPopUp, self).__init__(**kw)
              self.game_ctrl = game_ctrl
      
          def start_click(self):
              self.game_ctrl.start_game()                    
      
      class Controller(Widget):
          playing_label = BooleanProperty(False)          #Intitial phase of game is off
      
          def __init__(self, **kw):
              super(Controller, self).__init__(**kw)        
      
          def start_popup(self, dt):    
              sp = StartPopUp(self)
              sp.open()
      
          def start_game(self):
              self.playing_label = True
              print self.playing_label
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-30
        • 1970-01-01
        • 2011-02-01
        • 1970-01-01
        相关资源
        最近更新 更多