python:获取构造函数以返回现有对象而不是新对象

时间:2010-09-01 06:38:20

标签: python constructor

我有一个知道现有实例的类。有时我希望类构造函数返回现有对象而不是创建新对象。

class X:
    def __new__(cls, arg):
        i = f(arg)
        if i:
            return X._registry[i]
        else:
            return object.__new__(cls)
    # more stuff here (such as __init_, _registry, etc.)

当然,如果执行第一个分支,我不需要__init__,但无论如何都会调用它。什么是告诉__init__什么都不做的好方法?

我可以添加一些属性来跟踪__init__是否已经运行,但也许还有更好的方法?

2 个答案:

答案 0 :(得分:3)

在支持私有构造函数(C#,Dart,Scala等)的语言中,工厂方法为此问题提供了可靠的解决方案。

但是,在Python中,类构造函数始终是可访问的,因此类的用户可能很容易忘记工厂方法并直接调用构造函数,从而生成应该是唯一的对象的重复副本。

使用元类可以实现针对此问题的万无一失的解决方案。下面的示例假定第0个构造函数参数可用于唯一标识每个实例:

class Unique(type):

    def __call__(cls, *args, **kwargs):
        if args[0] not in cls._cache:
            self = cls.__new__(cls, *args, **kwargs)
            cls.__init__(self, *args, **kwargs)
            cls._cache[args[0]] = self
        return cls._cache[args[0]]

    def __init__(cls, name, bases, attributes):
        super().__init__(name, bases, attributes)
        cls._cache = {}

可以按如下方式使用:

class Country(metaclass=Unique):
    def __init__(self, name: str, population: float, nationalDish: str):
        self.name = name
        self.population = population
        self.nationalDish = nationalDish

placeA = Country("Netherlands", 16.8e6, "Stamppot")
placeB = Country("Yemen", 24.41e6, "Saltah")
placeC = Country("Netherlands", 11, "Children's tears")

print(placeA is placeB)    # -> False
print(placeA is placeC)    # -> True
print(placeC.nationalDish) # -> Stamppot

总之,如果要在运行时生成一组唯一对象(可能使用可重复输入的数据),此方法很有用。

答案 1 :(得分:1)

使用工厂,即

_x_singleton = None

def XFactory():
    global _x_singleton

    if _x_singleton is None:
        _x_singleton = X()
    return _x_singleton

或在您的班级中使用“创建”类方法,其行为方式符合您的要求,

class X(object):
    instance = None
    def __init__(self):
        # ...
    @classmethod
    def create(cls):
        if cls.instance is None:
            cls.instance = cls()
        return cls.instance

如果不满足某些条件,你甚至可以考虑让__init__引发异常(即self.instance不是None)