我找不到一个明确的答案。据我所知,在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

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


当前回答

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

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


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

其他回答

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

人们肯定更喜欢已经发布的解决方案,但由于还没有人提到这个解决方案,我认为为了完整性,值得一提。

@classmethod方法可以修改为提供一个不调用默认构造函数(__init__)的替代构造函数。相反,使用__new__创建实例。

如果不能根据构造函数参数的类型选择初始化类型,并且构造函数不共享代码,则可以使用此方法。

例子:

class MyClass(set):

    def __init__(self, filename):
        self._value = load_from_file(filename)

    @classmethod
    def from_somewhere(cls, somename):
        obj = cls.__new__(cls)  # Does not call __init__
        super(MyClass, obj).__init__()  # Don't forget to call any polymorphic base class initializers
        obj._value = load_from_somewhere(somename)
        return obj

为什么你认为你的解决方案“笨拙”?就我个人而言,在你这样的情况下,我更喜欢一个具有默认值的构造函数,而不是多个重载构造函数(Python不支持方法重载):

def __init__(self, num_holes=None):
    if num_holes is None:
        # Construct a gouda
    else:
        # custom cheese
    # common initialization

对于有很多不同构造函数的非常复杂的情况,使用不同的工厂函数可能会更干净:

@classmethod
def create_gouda(cls):
    c = Cheese()
    # ...
    return c

@classmethod
def create_cheddar(cls):
    # ...

在你的奶酪的例子中,你可能想要使用奶酪的一个Gouda子类…

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

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


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

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

使用__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)