Что такое чистый, питонский способ иметь несколько конструкторов в Python?

Может быть, он смотрит на Флакс? http://flask.pocoo.org/ Очень простая веб-среда в Python для быстрого создания небольшого веб-сайта.

633
задан smci 21 May 2018 в 06:53
поделиться

6 ответов

На самом деле None намного лучше для "волшебных" значений:

class Cheese():
    def __init__(self, num_holes = None):
        if num_holes is None:
            ...

Теперь, если Вы хотите полную свободу добавления большего количества параметров:

class Cheese():
    def __init__(self, *args, **kwargs):
        #args -- tuple of anonymous arguments
        #kwargs -- dictionary of named arguments
        self.num_holes = kwargs.get('num_holes',random_holes())

Лучше объяснить понятие *args и **kwargs (можно на самом деле изменить эти имена):

def f(*args, **kwargs):
   print 'args: ', args, ' kwargs: ', kwargs

>>> f('a')
args:  ('a',)  kwargs:  {}
>>> f(ar='a')
args:  ()  kwargs:  {'ar': 'a'}
>>> f(1,2,param=3)
args:  (1, 2)  kwargs:  {'param': 3}

http://docs.python.org/reference/expressions.html#calls

779
ответ дан 22 November 2019 в 21:47
поделиться

Используя num_holes=None поскольку значение по умолчанию прекрасно, если Вы собираетесь иметь просто __init__.

Если Вы хотите несколько, независимых "конструкторов", можно обеспечить их как методы класса. Их обычно называют методами фабрики. В этом случае у Вас могло быть значение по умолчанию для 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()
628
ответ дан 22 November 2019 в 21:47
поделиться

Все эти ответы превосходны, если Вы хотите использовать дополнительные параметры, но другая возможность Pythonic состоит в том, чтобы использовать classmethod для генерации псевдоконструктора стиля фабрики:

def __init__(self, num_holes):

  # do stuff with the number

@classmethod
def fromRandom(cls):

  return cls( # some-random-number )
24
ответ дан 22 November 2019 в 21:47
поделиться

Почему Вы думаете, что Ваше решение является "неуклюжим"? Лично я предпочел бы одного конструктора со значениями по умолчанию по нескольким перегруженным конструкторам в ситуациях как Ваши (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 Сыра хотя...

18
ответ дан 22 November 2019 в 21:47
поделиться

Лучший ответ является тем выше о параметрах по умолчанию, но я весело провел время, пишущий это, и он, конечно, отвечает всем требованиям для "нескольких конструкторов". Используйте на Ваш собственный риск.

Что относительно нового метода.

"Типичные реализации создают новый экземпляр класса путем вызова нового суперкласса () метод, использующий супер (currentclass, cls) .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)
10
ответ дан 22 November 2019 в 21:47
поделиться

Использовать num_holes=None как значение по умолчанию, вместо этого. Затем проверьте на ли num_holes is None, и если так, рандомизировать. Это - то, что я обычно вижу, так или иначе.

Более радикально различные способы строительства могут гарантировать classmethod, который возвращает экземпляр cls.

8
ответ дан 22 November 2019 в 21:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: