仅实例化类

时间:2017-08-04 16:53:49

标签: oop memory-leaks python-3.5 instantiation metaclass

我正在尝试创建一个只在实例化过程中传入的参数是唯一组合时才创建实例的类。如果先前已传入参数组合,则返回先前已创建的实例。 我希望这个类可以被其他类继承,所以它们继承了相同的行为。这是我第一次尝试解决方案,

要继承的基类/父类:

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

这就是它在儿童班中的使用方式:

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()时都会创建一个新的dict,因此内存正在爆炸......即使程序返回之前已经存在的实例实例化。

有没有解决这个问题? 感谢!!!

1 个答案:

答案 0 :(得分:1)

您的代码似乎是正确的 - 上面唯一不正确的是,在实例化新类时将始终调用您的__init__方法,而不管__new__是否返回先前的实例。

所以,如果你在__init__方法中创建额外的对象,这可能是你的内存泄漏的原因 - 但是,如果你将这些新对象绑定到instane(self),他们只需覆盖以前的在同一个地方创建了对象 - 它们将被释放。 。在这里发布的代码中,self.name会发生这种情况 - 可能是您的真实__init__执行了更多操作,并将新对象关联到除实例之外的其他位置(例如,将它们添加到列表中)。如果您的__init__方法如图所示,则您提供的代码中内存增长的原因并不明显。

作为一个额外的建议,但与你所涉及的问题无关,我补充一点,你根本不需要一个元类。

只需检查cls.instantiated_objects方法本身是否存在__new__ dict。不写不需要的元类将简化您的代码库,避免在类层次结构发展时出现元类冲突,如果您的元类上有比您在此处显示的代码更多的代码,甚至可能会解决您的问题。

基类__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

并且不再需要自定义元类。