Python:回调问题

标签 python oop inheritance callback static-members

所以我正在制作一款游戏,所有对象都派生自一个 GameObject 类,看起来像这样;

class GameObject(pygame.sprite.DirtySprite):
    actions = dict()

    def __init__(self):
        pygame.sprite.DirtySprite.__init__(self)
        self.rect  = None
        self.state = None

    def update(self):
        if callable(self.__class__.actions[self.state]):
        #If this key has a function for its element...
            self.__class__.actions[self.state](self)

现在,我遇到了另一个与继承有关的问题。观察下面的类,以及从它派生的两个类;

class Bullet(gameobject.GameObject):
    FRAME  = pygame.Rect(23, 5, 5, 5)
    STATES = config.Enum('IDLE', 'FIRED', 'MOVING', 'RESET')

    def __init__(self):
        gameobject.GameObject.__init__(self)
        self.image = config.SPRITES.subsurface(self.__class__.FRAME)
        self.rect  = self.__class__.START_POS.copy()
        self.state = self.__class__.STATES.IDLE

    actions = {
               STATES.IDLE   : None        ,
               STATES.FIRED  : start_moving,
               STATES.MOVING : move        ,
               STATES.RESET  : reset       ,
              }

class ShipBullet(bullet.Bullet):
    SPEED     = -8
    START_POS = pygame.Rect('something')

    def __init__(self):
        super(self.__class__, self).__init__()
        self.add(ingame.PLAYER)

class EnemyBullet(bullet.Bullet):
    SPEED     = 2
    START_POS = pygame.Rect('something else')

    def __init__(self):
        super(self.__class__, self).__init__()
        self.add(ingame.ENEMIES)

除了 None 之外,Bullet.actions 的每个元素(请注意,是静态成员)都是 Bullet 中的一个函数。 Bullet 并不是要自己创建;如果这是 C++,它将是一个抽象类。所以发生的事情是,Bullet 的子类在每一帧搜索 Bullet.actions 以决定下一步做什么,这取决于它们的状态(它们是否移动,它们是否刚刚射击, ETC。)。然而,由于 Bullet.actions 的元素是 Bulletown 方法,它的子类正在执行这些方法而不是它们自己的扩展版本(它调用父方法)。由于内存使用原因,我不想复制这个回调指令。所以,我问这个; 我怎样才能让子类的实例查看充满回调方法的父类字典,如果存在则执行它们自己的版本,如果不存在则执行它们父类的版本?

最佳答案

一个可能的解决方案是存储函数的名称而不是直接引用并使用 getattr检索正确的引用:

actions = {
           STATES.IDLE   : None          ,
           STATES.FIRED  : 'start_moving',
           STATES.MOVING : 'move'        ,
           STATES.RESET  : 'reset'       ,
          }

[...]

def update(self):
    method_name = self.__class__.actions[self.state]
    if method_name and callable(getattr(self, method_name)):
        getattr(self, method_name)(self)

为了加速,您可以在初始化对象时预先计算此表:

class Bullet(gameobject.GameObject):

    FRAME  = pygame.Rect(23, 5, 5, 5)
    STATES = config.Enum('IDLE', 'FIRED', 'MOVING', 'RESET')

    action_names = {
                     STATES.IDLE   : None          ,
                     STATES.FIRED  : 'start_moving',
                     STATES.MOVING : 'move'        ,
                     STATES.RESET  : 'reset'       ,
                    }

    def __init__(self):
        gameobject.GameObject.__init__(self)
        self.image = config.SPRITES.subsurface(self.__class__.FRAME)
        self.rect  = self.__class__.START_POS.copy()
        self.state = self.__class__.STATES.IDLE

        # Update actions table using getattr, so we get the correct
        # method for subclasses.
        self.actions = {}
        for state, method_name in self.action_names.items():
            if method_name and callable(getattr(self, method_name)):
                self.actions[state] = getattr(self, method_name)
            else:
                self.actions[state] = lambda self: None


    def update(self):
        self.actions[self.state]()

请注意,由于 __init__ 中的代码使用了 getattr ,它可以放在 Bullet.__init__ 中并且仅由其他类扩展。由于您已经调用了 super 构造函数,因此无需更改扩展类甚至注释它们。

关于Python:回调问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13505649/

相关文章:

python 3 : TypeError: 'int' object is not callable

javascript - 将私有(private)类的作用域放在单独的文件中

c++ - 如何使用派生类实例调用基类重载的 func,

python - 在 python 中解析 POSTed Excel 文件

php - PDO 类的通用插入方法

python - 通过 Gmail API 发送 Excel 文件但附件已损坏

c++ - 段错误c++导致程序崩溃

c# - 在基抽象类中使用派生类型

Python 子进程模块和 Awk

python - 从与 python 模块相同的目录读取文件