为复杂和重复的函数调用创建类似propertylike的解决方案

2024-05-15 04:31:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在扩展一个现有的PlayerClassFromGameEngine类,以允许自定义效果只在特定时间内生效。你知道吗

示例: 使用原来的类,我会说player.move_type = MoveTypes.Freeze冻结一个玩家,然后说player.move_type = MoveTypes.Normal解冻他。 现在我想扩展这个类,这样就可以使用函数调用:player.freeze(5),将播放器冻结5秒钟。你知道吗

我显然需要两个函数,效果函数和撤销函数,即freeze()unfreeze()。 这是我目前的课程,效果不错:

class MyPlayer(PlayerClassFromGameEngine):
    def __init__(self, index):
        super().__init__(index)  # Let the original game engine handle this
        self.effects = defaultdict(set)

    def freeze(self, duration):
        self.move_type = MoveType.FREEZE  # Move type comes from the super class
        thread = threading.Thread(target=self._unfreeze)
        thread.args = (duration, thread)
        self.effects['freeze'].add(thread)
        thread.start()

    def _unfreeze(self, duration, thread):
        time.sleep(duration)
        self.effects['freeze'].remove(thread)
        if not self.effects['freeze']:  # No more freeze effects
            self.move_type = MoveType.NORMAL

如您所见,只有一个效果需要10行以上的代码,有20行代码会很糟糕,因为它们的工作方式完全相同,只是使用不同的键('freeze'burn,等等),有些调用函数而不是访问move_type属性。你知道吗

我基本上不知道从哪里开始,也许是描述符和装饰者,但是有人能给我一些建议,或者更好的解决方案吗?你知道吗


编辑: 这是我在Martijn的建议之后想到的,但是它不起作用,因为我无法访问Effect类中的播放器

from collections import defaultdict
from threading import Thread
from time import sleep

class Effect(object):
    def __init__(self, f, undo_f=None):
        self.f = f
        self.undo_f = undo_f
        self._thread = None

    def __call__(self, duration):
        self._thread = Thread(target=self._execute, args=(duration, ))
        self._thread.start()

    def _execute(self, duration):
        self.f()
        sleep(duration)
        self.undo_f()

    def undo(self, undo_f):
        return type(self)(self.f, undo_f)

class Player:
    def __init__(self, index):
        self.index = index
        self._effects = defaultdict(set)

    @Effect
    def freeze(self):
        print('FROZEN')

    @freeze.undo
    def freeze(self):
        print('UNFROZEN')

p = Player(1)
p.freeze(3)

我想我需要的是以某种方式访问Effect类中的播放器,因为我不能在Effect._execute方法中调用self.f(player)self.undo_f(player),也不能访问播放器的effects字典。 我想我在任何地方都不需要key参数,因为我可以为每个效果生成一个随机数(c的唯一一个),因为它不会以任何方式显示给任何人。你知道吗


Tags: selfindexmovedeftype播放器threadclass
1条回答
网友
1楼 · 发布于 2024-05-15 04:31:19

这将是一种方式:

from functools import partial
import time
import threading


class aftereffect(object):
    def __init__(self, func):
        self._func = func
        self._aftereffect = lambda instance: None


    def aftereffect(self, func):
        self._aftereffect = func
        return self


    def __get__(self, instance, cls):
        # this is the descriptor protocol, and
        # instance is the actual object

        def delayed_effect(timeout):
            time.sleep(timeout)
            self._aftereffect(instance)

        def caller(*args, **kwargs):
            timeout = kwargs.pop("_timeout", 1.)
            t = threading.Thread(target=partial(delayed_effect, timeout=timeout))
            t.start()
            return self._func(*args, **kwargs)

        return caller.__get__(instance, cls)


class Thing(object):
    @aftereffect
    def something(self):
        print "something", self

    @something.aftereffect
    def something(self):
        print "after_something", self


t = Thing()
t.something()
t.something(_timeout=5)

相关问题 更多 >

    热门问题