[英]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.