Почему у меня не может быть конструктора varargs и другого конструктора с фиксированными аргументами? - PullRequest
1 голос
/ 29 января 2011

Вот что у меня есть:

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 ]

4 голосов
/ 29 января 2011

Как вы заметили в своем вопросе, вызывается конструктор varargs.Это связано с тем, что второе определение Dice.__init__ переопределяет, а не перегружает первое.

Python не поддерживает перегрузку методов , поэтому у вас есть как минимум два варианта под рукой.

  • Определить только конструктор varargs.Проверьте длину списка аргументов и типы первых нескольких элементов, чтобы определить, какую логику запустить.По сути, вы должны объединить два конструктора в один.
  • Преобразовать один из конструкторов в метод статической фабрики.Например, вы можете удалить первый конструктор, оставить varargs и затем определить новый фабричный метод.

Я предпочитаю второй метод, который позволяет вам четко отделить вашу логику.Вы также можете выбрать более описательное имя для вашего фабричного метода;from_n_sided_dice более информативен, чем просто Dice:

@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, и использование отдельных методов с более точными именами все еще часто является лучшим решением.

1 голос
/ 29 января 2011

То, что вы хотите иметь, это один __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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...