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

时间:2011-01-29 20:21:25

标签: python constructor

这是我到目前为止所做的:

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构造函数。我可以做些什么来完成这项工作,还是有另一种选择?

2 个答案:

答案 0 :(得分:4)

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

Python doesn't support method overloading,所以您至少有两个选择。

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

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

@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)]

编辑:您可以使用函数装饰器emulate method overloading(通过动态调度,而不是您可能习惯的静态调度,但Python中不存在静态类型)。您可能需要设计自己的解决方案以支持*args**kwargs,并且使用具有更精确名称的单独方法通常仍然是更好的解决方案。

答案 1 :(得分:1)

您希望拥有的是单个__init__方法,该方法按以下方式定义:

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)
相关问题