跨多个类实例(但不是所有实例)的共享属性

时间:2018-12-16 21:12:45

标签: python python-3.x class

我有一个课程,例如Cat,目前我的定义如下。

class Cat:
    def __init__(self, clone_population=0, **kwargs):
        self.clone_population = clone_population

    def clone(self):
       props = vars(self)
       props['clone_population'] += 1
       return Cat(**props)

可以通过直接实例化它们(出生的猫)来生猫,也可以从其他猫中克隆它们。

现在,我不知道的是,如何跟踪给定产猫的克隆种群,以使出生者本身及其所有克隆都可以访问种群数

基于当前代码的示例(我在这里)

cat_mandu = Cat()  # A new cat is born 
cat_mandu.clone_population
# 0

按预期,我们还没有克隆。如果我进行克隆:

cat_mandu_v2 = cat_mandu.clone()  # catmandu is cloned
cat_mandu.clone_population, cat_mandu_v2.clone_population
# 1, 1

现在,对于出生猫和克隆猫来说,我正确地得到了1,因为var字典是跨克隆馈送的。但是,如果我克隆克隆:

cat_mandu_v3 = cat_mandu_v2.clone()  # clone the clone
cat_mandu.clone_population, cat_mandu_v2.clone_population, cat_mandu_v3.clone_population
# 1, 2, 2

我没有更新出生猫的种群。我希望我的行为具有一个属性,该属性可以跟踪给定出生猫的克隆数量,并且该出生者及其所有克隆都跟踪与当前克隆种群相同的数目。因此正确答案应该是2 2 2,而不是1 2 2

请注意,如果新出生的猫meawsome = Cat()出生了,我们应该只看到0个克隆种群(meawsome.clone_population = 0),因为它尚未被克隆。

我非常感谢您提供帮助或提示可以采取这种行为的适当技术。

3 个答案:

答案 0 :(得分:1)

您遇到的问题是,当您使用**props将其传递给新实例的__init__方法时,您正在将计算克隆数量的整数复制。从那时起,就没有联系维持世代之间的计数。每个克隆父级及其克隆子级都将从相同的计数开始,但是谱系中的其他克隆数将分别计数。

要解决此问题,您需要将 all 实例从同一原始猫派生到与计数所处的单一来源相关联。我认为第一只未克隆的猫(血统的“祖先”)是它生活的最自然的地方,但是您可以这样做(例如,可以创建一个单独的Lineage类)。这是我的处理方式:

class Cat:
    def __init__(self, progenitor=None):
        if progenitor is None:
            self._clone_count = 0
            self.progenitor = self
        else:
            self.progenitor = progenitor

    def clone(self):
        self.progenitor._clone_count += 1
        return Cat(self.progenitor)

    @property
    def clone_count(self):
        return self.progenitor._clone_count

通过这种设计,每个谱系只有一个 real 克隆计数,存储在祖猫实例的_clone_count属性中。克隆世系中的所有猫都将能够访问该计数,并且clone_count属性将其暴露给外部(无需其他代码就无需了解所有实现细节)。

答案 1 :(得分:1)

我建议您不要传递所有变量,而只是传递对列表的引用。因此,我们建立了两个规则:

1)任何不是通过克隆创建的猫都会创建自己的列表,并将其引用向下传递给任何克隆

2)任何通过克隆创建的猫都会从其父级获取引用,并将其传递给其他克隆。

最终结果是,来自同一只猫的所有猫都将对同一列表具有相同的引用。

这里是一个示例:

class Cat:

    def __init__(self, parent=None):
        if parent is None:
            self.parent = [0]
        else:
            self.parent = parent
            parent[0] += 1

    def clone(self):
        return Cat(self.parent)

    @property
    def clone_population(self):
        return self.parent[0]

一些测试示例:

c = Cat()
print(c.clone_population)
>>>0
b = c.clone()
print(c.clone_population)
>>>1
d = b.clone()
print(c.clone_population, b.clone_population)
>>>2 2

答案 2 :(得分:1)

另一种方法可能是考虑使用某种类型的 <div class="topSlider"> <div class="slide"></div> <div class="slide"></div> <div class="slide"></div> <div class="slide"></div> </div>元类。

这可能具有以下优势:能够定义CloneTrackers,根据所克隆的对象,该克隆提供不同的行为!

CloneTracker

例如:

class CloneTrackerSingleton(type):
    def __init__(cls, name, bases, attrs, **kwargs):
        super().__init__(name, bases, attrs)
        cls._instance = None
    def __call__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

class SimpleCloneTracker(metaclass=CloneTrackerSingleton):
    def __init__(self):
        self.total = 0
    def inc(self):
        self.total += 1
    def get_total(self):
        return self.total

class Cat:
    def __init__(self):
        self.tracker = SimpleCloneTracker()

    @property
    def clone_pop(self):
        return self.tracker.get_total()

    def clone(self):
        SimpleCloneTracker().inc()
        return Cat()