创建唯一实例有效,但如何在再次调用 class 时获取引用?

Creating unique instance works, but how to get the reference when calling the class again?

我正在尝试创建一个 class,它使用 newinit[ 将所有创建的实例存储在 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!