关于python:为什么我不能有一个varargs构造函数和另一个带有固定参数的构造函数?

Why can't I have a varargs constructor and another constructor with fixed arguments?

以下是迄今为止我所拥有的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Die (object):
    def __init__(self,sides):
        self.sides = sides

    def roll(self):
        return random.randint(1,self.sides)

    def __add__(self,other):
        return Dice(self,other)

    def __unicode__(self):
        return"1d%d" % (self.sides)

    def __str__(self):
        return unicode(self).encode('utf-8')

class Dice (object):
    def __init__(self, num_dice, sides):
        self.die_list = [Die(sides)]*num_dice

    def __init__(self, *dice):
        self.die_list = dice

    def roll(self):
        return reduce(lambda x, y: x.roll() + y.roll(), self.die_list)

但当我尝试做Dice(3,6)并随后调用roll动作时,它说不能,因为'int' object has no attribute 'roll'。这意味着它将首先进入varargs构造函数。我可以在这里做什么来完成这项工作,或者还有其他选择吗?


正如您在问题中观察到的,正在调用varargs构造函数。这是因为Dice.__init__的第二个定义是重写,而不是重载。

Python不支持方法重载,因此您至少有两个选择。

  • 仅定义varargs构造函数。检查参数列表的长度和前几个元素的类型,以确定要运行的逻辑。实际上,您可以将两个构造函数合并为一个。
  • 将其中一个构造函数转换为静态工厂方法。例如,您可以删除第一个构造函数,保留varargs一个,然后定义一个新的工厂方法。

我更喜欢第二种方法,它允许您清晰地分离逻辑。您也可以为工厂方法选择更具描述性的名称;from_n_sided_diceDice更具信息性:

1
2
3
@staticmethod
def from_n_sided_dice(num_dice, sides):
    return Dice([Die(sides)] * num_dice)

旁注:这真的是你想要的吗?[Die(sides)] * num_dice返回一个对同一die对象有多个引用的列表。相反,您可能需要[Die(sides) for _ in range(num_dice)]

编辑:您可以使用函数修饰符模拟方法重载(通过动态调度,而不是使用静态调度,但是静态类型在Python中不存在)。您可能需要设计自己的解决方案来支持*args**kwargs,使用具有更精确名称的单独方法仍然是更好的解决方案。


您想要的是一个单一的__init__方法,它是沿着这些行定义的:

1
2
3
4
5
6
7
8
class Dice (object):
    def __init__(self, *args):
        if not isinstance(args[0], Die):
            self.die_list = [Die(args[0]) for _ in range(args[1])]
        else:
            self.die_list = args
    def roll(self):
        return sum(x.roll() for x in self.die_list)