仅实例化 class 的唯一 objects

Instantiate only unique objects of a class

我正在尝试创建一个 class,它仅在实例化期间传入的参数是唯一组合时才创建一个实例。如果先前已传入参数组合,则 return 先前已创建的实例。 我希望此 class 被其他 class 继承,以便它们继承相同的行为。这是我第一次尝试解决方案,

要继承的base/parentclass:

class RegistryType(type):
    def __init__(cls, name, bases, namespace, *args):
        cls.instantiated_objects = {}


class AdwordsObject(object, metaclass=RegistryType):
    api = AdWordsAPI()

    def __new__(cls, *args):
        object_name = '-'.join(args)
        if object_name in cls.instantiated_objects:
            return cls.instantiated_objects[object_name]
        else:
            obj = super(AdwordsObject, cls).__new__(cls)
            cls.instantiated_objects[object_name] = obj
            # cls.newt_connection.commit()
            return obj

这就是它在 child class 中的使用方式:

class ProductAdGroup(AdwordsObject):
    # init method only called if object being instantiated hasn't already been instantiated
    def __init__(self, product_name, keyword_group):
        self.name = '-'.join([product_name, keyword_group])

    @classmethod
    def from_string(cls, name: str):
        arguments = name.split('-')
        assert len(arguments) == 2, 'Incorrect ad group name convention. ' \
                                    'Use: Product-KeywordGroup'
        ad_group = cls(*arguments)
        return ad_group

我已经 运行 使用此设置的程序,但似乎每次创建 ProductAdGroup() 时都会创建一个新的字典,因此内存正在爆炸......即使程序 returns 之前已经实例化的实例。

有办法解决这个问题吗? 谢谢!!!

你的代码似乎是正确的 - 上面唯一不正确的地方是你的 __init__ 方法在实例化一个新的 class 时总是被调用,而不管 __new__ 与否。

因此,如果您在 __init__ 方法中创建了额外的对象,这可能是内存泄漏的原因 - 但是,如果您将这些新对象绑定到实例 (self),它们应该只是覆盖先前在同一位置创建的对象 - 它们将被释放。 .在此处发布的代码中,self.name 会发生这种情况 - 可能是您真正的 __init__ 做了更多的事情,并将新对象关联到实例以外的其他地方(例如,将它们附加到列表中)。如果您的 __init__ 方法与所示的一样,那么您提供的代码中内存增长的原因并不明显。

作为额外的建议,但与您所涉及的问题无关,我补充说您根本不需要元class。

只需检查 __new__ 方法本身是否存在 cls.instantiated_objects 字典。不编写不需要的 metaclass 将简化您的代码库,如果您的 class 层次结构发生变化,则可以避免 metaclass 冲突,如果您的 meta[ 上有更多代码,甚至可以消除您的问题=32=] 比你在这里展示的要多。

基础class __new__ 方法可以改写成这样:

class AdwordsObject(object):
    def __new__(cls, *args):
        if not cls.__dict__.get("instantiated_objects"):
            cls.instantiated_objects = {}
        name = '-'.join(args)
        if name in cls.instantiated_objects:
            return cls.instantiated_objects[name]
        instance = super().__new__(cls)
        cls.instantiated_objects[name] = instance
        return instance

并且不再需要自定义元数据class。