创建唯一实例有效,但如何在再次调用 class 时获取引用?
Creating unique instance works, but how to get the reference when calling the class again?
我正在尝试创建一个 class,它使用 new 和 init[ 将所有创建的实例存储在 class 本身中=29=] 神奇的方法在一起,我想 return 一个现有的 class 如果它是以前创建的。
我当前的代码如下所示:
class Obj():
_list = []
def __new__(cls, id, *args, **kwargs):
print('new')
for o in Obj._list:
if o.id == id:
print('existent')
return # 'return o' DOES NOT WORK!
instance = super(Obj, cls).__new__(cls, *args, **kwargs)
return instance
def __init__(self, id, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
self.id = id
Obj._list.append(self)
Obj(1)
Obj(1)
代码有效,因为它不会在 Obj._list 中产生双精度数(Obj(1) 的第二次调用打印 'existent' 并取消另一个实例的创建)。但是当我将新函数中的 return
行更改为 return o
时,尽管我想要一个指针/现有实例的名称被 returned 而不是创建另一个实例。
是否有机会使用此代码或任何其他解决方案实现此行为?我试图避免 class 中的函数,例如:
def get(id):
for i in Obj._list:
if i.id == id:
return i
Obj.get(1).my_method_call()
感谢任何帮助!非常感谢!
乌尔里希
这是我给 :
的答案的修改版本
def singleton_id(cls):
instances={}
def getinstance(id, *args, **kwargs):
key = "{}__{}".format(cls, id)
if key not in instances:
instances[key] = cls(id, *args, **kwargs)
return instances[key]
return getinstance
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
super().__init__(*args, **kwargs)
self.id = id
print(id(Obj(1)) == id(Obj(1))) # True
print(id(Obj(1)) == id(Obj(2))) # False
从打印语句的输出可以看出,使用相同 ID 创建的对象是相同的。
既然你想访问已经创建的实例,我对答案进行了更多修改。
注意:我已经从密钥中删除了 cls
,所以这将不再作为具有相同密钥的不同 类 的装饰器,但这似乎不是必需的你的情况。
def singleton_id(cls):
def getinstance(id, *args, **kwargs):
if id not in singleton_id.instances:
singleton_id.instances[id] = cls(id, *args, **kwargs)
return singleton_id.instances[id]
return getinstance
singleton_id.instances = {}
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
super().__init__(*args, **kwargs)
self.id = id
print(id(Obj(1)) == id(Obj(1))) # True
print(id(Obj(1)) == id(Obj(2))) # False
print(singleton_id.instances[2].id) # 2
最后,我将 Mike 的解决方案整理成一个完整的代码示例(包括向实例添加方法和删除实例)。所以你在 Python 中有一个完全工作的对象处理程序(例如适合游戏)。您可以在最后一行代码中看到唯一的缺点:如果您删除了一个实例并尝试调用它,则会立即设置一个新的空实例。这是完整的解决方案:
def singleton_id(cls):
singleton_id.instances = {}
def getinstance(id, *args, **kwargs):
if id not in singleton_id.instances:
singleton_id.instances[id] = cls(id, *args, **kwargs)
return singleton_id.instances[id]
return getinstance
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
self._methods = []
self.id = id
def delete(self):
del singleton_id.instances[self.id]
def addMethod(self, method, givenName = ''):
print('add')
if givenName == '':
N = method.__name__
else:
N = givenName
self._methods.append(N)
exec('self.' + N + ' = ' + method.__name__ + '.__get__(self)')
def executeMethod(self, method):
if type(method) != str:
method = method.__name__
if method in self._methods:
exec('self.' + method + '()')
def put(self):
print('I am', self.id)
# testing
Obj(1) # creation
Obj(1) # call
Obj(1).put()
print(Obj(1))
def x(self):
print('hello,', self.id)
Obj(1).addMethod(x)
# can be called in different ways:
Obj(1).x()
Obj(1).executeMethod(x)
Obj(1).executeMethod('x')
Obj(1).delete()
Obj(1).put() # immediately creates new instance!
我正在尝试创建一个 class,它使用 new 和 init[ 将所有创建的实例存储在 class 本身中=29=] 神奇的方法在一起,我想 return 一个现有的 class 如果它是以前创建的。
我当前的代码如下所示:
class Obj():
_list = []
def __new__(cls, id, *args, **kwargs):
print('new')
for o in Obj._list:
if o.id == id:
print('existent')
return # 'return o' DOES NOT WORK!
instance = super(Obj, cls).__new__(cls, *args, **kwargs)
return instance
def __init__(self, id, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
self.id = id
Obj._list.append(self)
Obj(1)
Obj(1)
代码有效,因为它不会在 Obj._list 中产生双精度数(Obj(1) 的第二次调用打印 'existent' 并取消另一个实例的创建)。但是当我将新函数中的 return
行更改为 return o
时,尽管我想要一个指针/现有实例的名称被 returned 而不是创建另一个实例。
是否有机会使用此代码或任何其他解决方案实现此行为?我试图避免 class 中的函数,例如:
def get(id):
for i in Obj._list:
if i.id == id:
return i
Obj.get(1).my_method_call()
感谢任何帮助!非常感谢!
乌尔里希
这是我给
def singleton_id(cls):
instances={}
def getinstance(id, *args, **kwargs):
key = "{}__{}".format(cls, id)
if key not in instances:
instances[key] = cls(id, *args, **kwargs)
return instances[key]
return getinstance
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
super().__init__(*args, **kwargs)
self.id = id
print(id(Obj(1)) == id(Obj(1))) # True
print(id(Obj(1)) == id(Obj(2))) # False
从打印语句的输出可以看出,使用相同 ID 创建的对象是相同的。
既然你想访问已经创建的实例,我对答案进行了更多修改。
注意:我已经从密钥中删除了 cls
,所以这将不再作为具有相同密钥的不同 类 的装饰器,但这似乎不是必需的你的情况。
def singleton_id(cls):
def getinstance(id, *args, **kwargs):
if id not in singleton_id.instances:
singleton_id.instances[id] = cls(id, *args, **kwargs)
return singleton_id.instances[id]
return getinstance
singleton_id.instances = {}
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
super().__init__(*args, **kwargs)
self.id = id
print(id(Obj(1)) == id(Obj(1))) # True
print(id(Obj(1)) == id(Obj(2))) # False
print(singleton_id.instances[2].id) # 2
最后,我将 Mike 的解决方案整理成一个完整的代码示例(包括向实例添加方法和删除实例)。所以你在 Python 中有一个完全工作的对象处理程序(例如适合游戏)。您可以在最后一行代码中看到唯一的缺点:如果您删除了一个实例并尝试调用它,则会立即设置一个新的空实例。这是完整的解决方案:
def singleton_id(cls):
singleton_id.instances = {}
def getinstance(id, *args, **kwargs):
if id not in singleton_id.instances:
singleton_id.instances[id] = cls(id, *args, **kwargs)
return singleton_id.instances[id]
return getinstance
@singleton_id
class Obj():
def __init__(self, id, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
self._methods = []
self.id = id
def delete(self):
del singleton_id.instances[self.id]
def addMethod(self, method, givenName = ''):
print('add')
if givenName == '':
N = method.__name__
else:
N = givenName
self._methods.append(N)
exec('self.' + N + ' = ' + method.__name__ + '.__get__(self)')
def executeMethod(self, method):
if type(method) != str:
method = method.__name__
if method in self._methods:
exec('self.' + method + '()')
def put(self):
print('I am', self.id)
# testing
Obj(1) # creation
Obj(1) # call
Obj(1).put()
print(Obj(1))
def x(self):
print('hello,', self.id)
Obj(1).addMethod(x)
# can be called in different ways:
Obj(1).x()
Obj(1).executeMethod(x)
Obj(1).executeMethod('x')
Obj(1).delete()
Obj(1).put() # immediately creates new instance!