0

我想继承 pyglet.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 子类化为拥有自己的派生时钟类的最佳方式。

问题:

有什么方法可以使用 Pyglet 自动设置默认时钟?

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

没有 pyglet.clock.set_default(self) 行可以做到这一点吗?

4

1 回答 1

1

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

您快到了。您的第一个实现可能不起作用的原因是因为以下几行:

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

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

pyglet.app.run()

...您实际上从未告诉 pyglet 新的时钟实例c。相反,pyglet 将使用它自己创建的实例。从时钟模块中查看pyglet 的源代码...:

# 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 可以让您在以后需要时更灵活地使用该类。

于 2013-04-30T02:07:39.137 回答