繁体   English   中英

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

[英]Shared attribute across multiple class instances (but not ALL instances)

我有一门课,比如说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 dict是跨克隆馈送的。 但是,如果我克隆克隆:

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 ),因为尚未克隆它。

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

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

要解决此问题,您需要将源自同一原始猫的所有实例链接到计数所在的单一来源。 我认为第一只未克隆的猫(血统的“祖先”)是它生活的最自然的地方,但是您可以这样做(例如,可以创建一个单独的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

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

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

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

另一种方法可能是考虑使用某种类型的CloneTracker元类。

这可能具有以下优势:能够定义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()

举个例子:

c1 = Cat()
c1.clone_pop  # 0
c2 = c1.clone()
c1.clone_pop, c2.clone_pop  #  (1, 1)
c3 = c2.clone()
c1.clone_pop, c2.clone_pop, c3.clone_pop  # (2, 2, 2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM