[英]Creating an instance in OWLready2 creates a completely new class instead of asigning it to the existing class
[英]Return class instance instead of creating a new one if already existing
我為我正在進行的一些實驗室實驗的結果定義了一個名為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__
塊中這是不可能的)
嘗試以這種方式進行操作(非常簡化的示例):
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
如果要自定義創建,而不僅僅是在新創建的對象中進行初始化,則可以使用__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
經過四年的提問,我來到這里,Serge Ballesta 的回答幫助了我。 我用更簡單的語法創建了這個例子。
如果base
是None
,它將始終返回創建的第一個對象。
class MyClass:
instances = []
def __new__(cls, base=None):
if len(MyClass.instances) == 0:
self = object.__new__(cls)
MyClass.instances.append(self)
if base is None:
return MyClass.instances[0]
else:
self = object.__new__(cls)
MyClass.instances.append(self)
# self.__init__(base)
return self
def __init__(self, base=None):
print("Received base = %s " % str(base))
print("Number of instances = %d" % len(self.instances))
self.base = base
R1 = MyClass("apple")
R2 = MyClass()
R3 = MyClass("banana")
R4 = MyClass()
R5 = MyClass("apple")
print(id(R1), R1.base)
print(id(R2), R2.base)
print(id(R3), R3.base)
print(id(R4), R4.base)
print(id(R5), R5.base)
print("R2 == R4 ? %s" % (R2 == R4))
print("R1 == R5 ? %s" % (R1 == R5))
它給了我們結果
Received base = apple
Number of instances = 2
Received base = None
Number of instances = 2
Received base = banana
Number of instances = 3
Received base = None
Number of instances = 3
Received base = apple
Number of instances = 4
2167043940208 apple
2167043940256 None
2167043939968 banana
2167043940256 None
2167043939872 apple
R2 == R4 ? True
R1 == R5 ? False
很高興知道__init__
將始終在__new__
return
之前被調用,即使您沒有調用它(在注釋部分)或者您返回一個已經存在的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.