python 模式装饰器中的奇怪 class 行为

strange class behavior in the python pattern decorator

我想对英雄施加狂暴效果。 Abstract classes:AbstractEffect和AbstractPositive(class继承人),可以接受base参数。接下来,还将创建 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}

我的错误是什么?

你被路过引用虐了。

在您的代码中,您有 self.stats = self.base.stats。这不会制作副本。因此,self.stats对于brs1brs2指的是一样dict。当您实例化 brs2 时,您更改它,并且该更改反映在 brs1.

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

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

因为以下代码

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())