我找不到一个明确的答案。据我所知,在Python类中不能有多个__init__函数。那么如何解决这个问题呢?

假设我有一个名为Cheese的类,它具有number_of_holes属性。我怎么能有两种方法来创建奶酪对象…

其中一个需要像这样的洞的数量:帕玛森=奶酪(num_holes = 15)。 还有一个不带参数,只是随机number_of_holes属性:gouda = Cheese()。

我只能想到一种方法来做到这一点,但这似乎很笨拙:

class Cheese():
    def __init__(self, num_holes = 0):
        if (num_holes == 0):
            # Randomize number_of_holes
        else:
            number_of_holes = num_holes

你说呢?还有别的办法吗?


当前回答

最好的答案是上面关于默认参数的那个,但我很高兴写这个,而且它确实符合“多个构造函数”的要求。使用风险自负。

新方法怎么样?

典型的实现通过使用super(currentclass, cls)调用超类的new()方法来创建类的新实例。使用适当的参数New (cls[,…]),然后在返回它之前根据需要修改新创建的实例。”

因此,您可以让新方法通过附加适当的构造函数方法来修改类定义。

class Cheese(object):
    def __new__(cls, *args, **kwargs):

        obj = super(Cheese, cls).__new__(cls)
        num_holes = kwargs.get('num_holes', random_holes())

        if num_holes == 0:
            cls.__init__ = cls.foomethod
        else:
            cls.__init__ = cls.barmethod

        return obj

    def foomethod(self, *args, **kwargs):
        print "foomethod called as __init__ for Cheese"

    def barmethod(self, *args, **kwargs):
        print "barmethod called as __init__ for Cheese"

if __name__ == "__main__":
    parm = Cheese(num_holes=5)

其他回答

我还没有看到一个直截了当的答案。想法很简单:

使用__init__作为“基本”构造函数,因为python只允许一个__init__方法 使用@classmethod创建任何其他构造函数并调用基本构造函数

这是一个新的尝试。

 class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def fromBirthYear(cls, name, birthYear):
        return cls(name, date.today().year - birthYear)

用法:

p = Person('tim', age=18)
p = Person.fromBirthYear('tim', birthYear=2004)

如果你只需要__init__,使用num_holes=None作为默认值是可以的。

如果你想要多个独立的“构造函数”,你可以把它们作为类方法提供。这些方法通常称为工厂方法。在本例中,num_holes的默认值为0。

class Cheese(object):
    def __init__(self, num_holes=0):
        "defaults to a solid cheese"
        self.number_of_holes = num_holes

    @classmethod
    def random(cls):
        return cls(randint(0, 100))

    @classmethod
    def slightly_holey(cls):
        return cls(randint(0, 33))

    @classmethod
    def very_holey(cls):
        return cls(randint(66, 100))

现在创建一个这样的对象:

gouda = Cheese()
emmentaler = Cheese.random()
leerdammer = Cheese.slightly_holey()

如果你想使用可选参数,所有这些答案都很好,但python的另一种可能性是使用类方法生成工厂风格的伪构造函数:

def __init__(self, num_holes):

  # do stuff with the number

@classmethod
def fromRandom(cls):

  return cls( # some-random-number )
class Cheese:
    def __init__(self, *args, **kwargs):
        """A user-friendly initialiser for the general-purpose constructor.
        """
        ...

    def _init_parmesan(self, *args, **kwargs):
        """A special initialiser for Parmesan cheese.
        """
        ...

    def _init_gauda(self, *args, **kwargs):
        """A special initialiser for Gauda cheese.
        """
        ...

    @classmethod
    def make_parmesan(cls, *args, **kwargs):
        new = cls.__new__(cls)
        new._init_parmesan(*args, **kwargs)
        return new

    @classmethod
    def make_gauda(cls, *args, **kwargs):
        new = cls.__new__(cls)
        new._init_gauda(*args, **kwargs)
        return new

我会用继承。特别是当不同点大于洞的数量时。尤其是如果豪达干酪需要不同的原料那就用帕尔马干酪。

class Gouda(Cheese):
    def __init__(self):
        super(Gouda).__init__(num_holes=10)


class Parmesan(Cheese):
    def __init__(self):
        super(Parmesan).__init__(num_holes=15)