如何在Pyglet中继承Clock?

时间:2013-04-30 00:37:51

标签: python pyglet

我想继承pyglet.clock模块的Clock类,但是当我使用schedule_interval时遇到了一些麻烦:

以下代码不会打印任何内容,如果没有打勾,则对象c看起来像是:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyglet

class Clock(pyglet.clock.Clock):
    def __init__(self):
        super(Clock, self).__init__()

class Test(object):
    def update(self, dt):
        print dt

w = pyglet.window.Window()
@w.event
def on_draw():
    w.clear()

t = Test()

c = pyglet.clock.Clock()
c.schedule_interval(t.update, 1/60.0)

pyglet.app.run()

但接下来的工作正常。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyglet

class Clock(pyglet.clock.Clock):
    def __init__(self):
        super(Clock, self).__init__()

        pyglet.clock.set_default(self)

class Test(object):
    def update(self, dt):
        print dt

w = pyglet.window.Window()
@w.event
def on_draw():
    w.clear()

t = Test()

c = Clock()
c.schedule_interval(t.update, 1/60.0)

pyglet.app.run()

唯一的区别是Clock的构造函数方法中的pyglet.clock.set_default(self)句子。

我认为这不清楚,或者至少不是将pyglet.clock.Clock子类化为拥有自己派生的Clock类的最佳方法。

问题:

有一些方法可以使用Pyglet自动设置默认时钟吗?

有更优雅或pythonic的解决方案吗?

可以在没有pyglet.clock.set_default(self)行的情况下执行此操作吗?

1 个答案:

答案 0 :(得分:1)

我没有使用pyglet,但这是我的猜测:

你快到了。你的第一次实现可能不起作用的原因是因为这些行:

c = pyglet.clock.Clock()
c.schedule_interval(t.update, 1/60.0)

在这里,您正在创建一个新的Clock实例,并在其上安排回调。但是,您实际上并没有将该时钟实例与pyglet相关联。所以,当你跑...

pyglet.app.run()

...你从未真正告诉pyglet有关新的时钟实例c。相反,pyglet将使用它自己创建的实例。看看这个source code for pyglet from the clock module ...:

# Default clock.
_default = Clock()

def set_default(default):
    '''Set the default clock to use for all module-level functions.

    By default an instance of `Clock` is used.

    :Parameters:
        `default` : `Clock`
            The default clock to use.
    '''
    global _default
    _default = default

def get_default():
    '''Return the `Clock` instance that is used by all module-level
    clock functions.

    :rtype: `Clock`
    :return: The default clock.

当pyglet启动时,它会创建自己的时钟实例(称为_default)。如果您想使用自己的,则需要使用set_default()来替换它。因此,要修复第一段代码,您可能需要执行以下操作之一:

c = pyglet.clock.get_default()
c.schedule_interval(t.update, 1/60.0)

...或...

c = pyglet.clock.Clock()
pyglet.clock.set_default(c)
c.schedule_interval(t.update, 1/60.0)

上面的第二个例子是没有意义的:pyglet已经为你提供了一个Clock的实例,所以你真的只是复制了pyglet已经为你做过的事情。无论哪种方式,你最终都会在pyglet使用的时钟上安排回调。

所以,现在应该有意义的是,你确实需要致电set_default()。这就是你告诉pyglet使用你的对象而不是默认使用它的方法。现在,您可以可以想象将此set_default()调用放在您当前拥有它的位置(在构造函数中)。但是,这样做可能更有意义......

class Clock(pyglet.clock.Clock):
    def __init__(self):
        super(Clock, self).__init__()

...

c = Clock()
pyglet.clock.set_default(c)

修改

回答你为什么要在构造函数之外执行此操作的问题:

首先,作为一般经验法则,构造函数只应用于构造对象。通过添加set_default,您不仅可以构建对象,还可以更改其他实体(pyglet.clock模块)的状态。这可能会引起混淆,我将在下面展示。假设我编写的代码看起来像这样......

c = MyClock()
c2 = UnpausedClock()

在此示例中,我之前已实现了两种不同的时钟类型:NewClockUnpausedClock。游戏取消暂停时,UnpausedClock只会考虑时间过去。如果我将set_default()放在这两个新类的构造函数中,那么UnpausedClock将成为新的默认时钟(我不想要)。不要将set_default()放在构造函数中,而是执行以下操作:

c = MyClock()
c2 = UnpausedClock()
pyglet.clock.set_default(c)

我的代码更明确,更少混淆。

当然,代码将以任何一种方式工作,但我觉得使用set_default OUTSIDE构造函数可以让您在以后需要时更灵活地使用该类。