【问题标题】:strange class behavior in the python pattern decoratorpython模式装饰器中的奇怪类行为
【发布时间】:2019-10-14 19:06:58
【问题描述】:

我想对英雄施加狂暴效果。 抽象类:AbstractEffect 和 AbstractPositive(类继承),可以接受基参数。接下来,还将创建 AbstractNegative。我不确定继承方案是否正确(Hero ---> AbstractEffect)。

from abc import ABC, abstractmethod 
class Hero:
    def __init__(self):
        self.stats = {"HP": 128}
    def get_stats(self):
        return self.stats.copy()

class AbstractEffect(ABC):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats()

class AbstractPositive(AbstractEffect):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats()

class Berserk(AbstractPositive):
    def __init__(self, base):
        self.base = base
        self.stats= self.base.stats
        self.stats["HP"] += 7
    def get_stats(self):
        return self.stats


hero = Hero() 
brs1 = Berserk(hero) 
print('brs1', brs1.get_stats()) 
brs2 = Berserk(brs1) 
print('brs2', brs2.get_stats()) 
print('brs1', brs1.get_stats())

我想收到

brs1 {'HP': 135}
brs2 {'HP': 142}
brs1 {'HP': 135}

但我明白了

brs1 {'HP': 135}
brs2 {'HP': 142}
brs1 {'HP': 142}

我的错误是什么?

【问题讨论】:

  • 很难知道你真正想要什么,但效果是两个Berserk 包装器都只是引用了原始Herostats 属性。每个Berserk 都会增加相同的"HP" 条目,因此您应该会发现所有三个实例都具有:stats["HP"] == 142

标签: python oop abstract-class decorator


【解决方案1】:

由于以下代码

self.stats = {"HP": 128}

{"HP": 128} 是一个容器
并且,

self.stats = self.base.stats

因此,
当你使用Berserk(heroxxx)增强英雄时,self.stats["HP"] += 7实际上是在修改原始数据。所以你需要把它改成self.stats = self.base.get_stats(),然后你就可以得到你想要的了。可以使用以下代码进行测试。

from abc import ABC, abstractmethod
class Hero:
    def __init__(self):
        self.stats = {"HP": 128}
    def get_stats(self):
        return self.stats.copy()

class AbstractEffect(ABC):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats

class AbstractPositive(AbstractEffect):
    def __init__(self, base):
        self.base = base
    @abstractmethod
    def get_stats(self):
        return self.base.stats

class Berserk(AbstractPositive):
    def __init__(self, base):
        self.base = base
        self.stats = self.base.get_stats()
        self.stats["HP"] += 7

    def get_stats(self):
        return self.stats.copy()


hero = Hero()
brs1 = Berserk(hero)
print('brs1', brs1.get_stats())
brs2 = Berserk(brs1)
print('brs2', brs2.get_stats())
print('brs1', brs1.get_stats())

【讨论】:

    【解决方案2】:

    你被通过引用残忍地攻击了。

    在您的代码中,您有self.stats = self.base.stats。这不会复制。因此,self.stats for brs1brs2 指的是 相同 dict。当您实例化brs2 时,您会对其进行更改,并且该更改会反映在brs1 中。

    self.stats = self.base.stats.copy() 将是一个好的开始,如果您不希望这种情况发生。

    也就是说,我觉得你想用这种方式编码状态效果很奇怪......如果是我,我会让每个状态效果只包含一个修饰符,这取决于角色类依次处理解析这些修饰符。

    【讨论】:

    • @hyper 显示什么?
    • ...如果是我,我会让每个状态效果只包含一个修饰符,然后由角色类来依次处理这些修饰符...
    猜你喜欢
    • 2021-07-11
    • 2014-07-12
    • 2017-05-30
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-31
    • 2021-01-26
    • 1970-01-01
    相关资源
    最近更新 更多