如果已存在,则返回类实例,而不是创建新实例

时间:2017-07-11 11:39:26

标签: python python-3.x class

我为我正在进行的一些实验室实验的结果定义了一个名为Experiment的类。我的想法是创建一种数据库:如果我添加一个实验,这将在退出之前被腌制到数据库并在启动时重新加载(并添加到类注册表中)。

我的班级定义是:

class IterRegistry(type):
    def __iter__(cls):
        return iter(cls._registry)


class Experiment(metaclass=IterRegistry):
    _registry = []
    counter = 0

    def __init__(self, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC):
        hashdat = fn.hashfile(pathresult)
        hashpro = fn.hashfile(pathprotocol)
        chk = fn.checkhash(hashdat)
        if chk:
            raise RuntimeError("The same experiment has already been added")
        self._registry.append(self)
        self.name = name
        [...]

虽然fn.checkhash是一个检查包含结果的文件的哈希值的函数:

def checkhash(hashdat):
    for exp in cl.Experiment:
        if exp.hashdat == hashdat:
            return exp
    return False

因此,如果我添加以前添加的实验,则不会被覆盖。

如果已经存在而不是引发错误,是否有可能以某种方式返回现有实例? (我知道__init__阻止它是不可能的)

2 个答案:

答案 0 :(得分:1)

尝试这样做(非常简化的例子):

class A:
    registry = {}

    def __init__(self, x):
        self.x = x

    @classmethod
    def create_item(cls, x):
        try:
            return cls.registry[x]
        except KeyError:
            new_item = cls(x)
            cls.registry[x] = new_item
            return new_item


A.create_item(1)
A.create_item(2)
A.create_item(2)  # doesn't add new item, but returns already existing one

答案 1 :(得分:1)

如果要自定义创建而不是仅在新创建的对象中初始化,则可以使用__new__

class Experiment(metaclass=IterRegistry):
    _registry = []
    counter = 0

    def __new__(cls, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC):
        hashdat = fn.hashfile(pathresult)
        hashpro = fn.hashfile(pathprotocol)
        chk = fn.checkhash(hashdat)
        if chk:                      # already added, just return previous instance
            return chk
        self = object.__new__(cls)   # create a new uninitialized instance
        self._registry.append(self)  # register and initialize it
        self.name = name
        [...]
        return self                  # return the new registered instance