Специализация конструктора в Python - PullRequest
4 голосов
/ 30 июля 2009

Иерархии классов и конструкторы связаны между собой. Параметры из дочернего класса должны быть переданы их родителю.

Итак, в Python мы получаем что-то вроде этого:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        # do something with a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, a, b, c, d, e, f, ka=None, kb=None, kc=None, kd=None, ke=None, kf=None):
        super(Child, self).__init__(a, b, c, ka=ka, kb=kb, kc=kc)
        # do something with d, e, f, kd, ke, kf

Вообразите это с дюжиной дочерних классов и множеством параметров. Добавление новых параметров становится очень утомительным.

Конечно, можно полностью отказаться от именованных параметров и использовать * args и ** kwargs, но это делает объявления методов неоднозначными.

Есть ли шаблон для элегантной работы с этим в Python (2.6)?

Под "элегантно" я подразумеваю, что хотел бы уменьшить количество раз, когда появляются параметры. a, b, c, ka, kb, kc появляются 3 раза: в конструкторе Child, в вызове super () для Parent и в конструкторе Parent.

В идеале я бы хотел указать параметры для init Родителя один раз, а для init только для ребенка указать только дополнительные параметры.

Я бы хотел сделать что-то вроде этого:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        print 'Parent: ', a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, d, e, f, kd='d', ke='e', kf='f', *args, **kwargs):
        super(Child, self).__init__(*args, **kwargs)
        print 'Child: ', d, e, f, kd, ke, kf

x = Child(1, 2, 3, 4, 5, 6, ka='a', kb='b', kc='c', kd='d', ke='e', kf='f')

Это, к сожалению, не работает, так как 4, 5, 6 в конечном итоге назначаются на kd, ke, kf.

Есть ли какой-нибудь элегантный шаблон python для выполнения вышесказанного?

Ответы [ 3 ]

7 голосов
/ 30 июля 2009

«дюжина дочерних классов и множество параметров» звучит как проблема, независимо от именования параметров.

Я подозреваю, что небольшой рефакторинг может очистить некоторые Стратегии объекты, которые упростили бы эту иерархию и заставили бы сверхсложные конструкторы уйти.

2 голосов
/ 30 июля 2009

Ну, единственное решение, которое я мог видеть, это использовать смесь перечисленных переменных, а также * args и ** kwargs, как таковые:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        pass

class Child(Parent):
    def __init__(self, d, e, f, *args, kd=None, ke=None, kf=None, **kwargs):
        Parent.__init__(self, *args, **kwargs)
        pass

Таким образом, вы можете видеть, какие параметры требуются для каждого из классов, но без необходимости их повторного ввода.

Стоит отметить, что вы теряете желаемый порядок (a, b, c, d, e, f), когда он становится (d, e, f, a, b, c). Я не уверен, есть ли способ получить * args перед другими неназванными параметрами.

1 голос
/ 30 июля 2009

Я пытаюсь сгруппировать параметры в свои собственные объекты, например, вместо передачи sourceDirectory, targetDirectory, временныйDirectory, serverName, serverPort, я бы Объекты DirectoryContext и ServerContext.

Если объекты контекста начинают иметь больше Поведение или логика могут привести к объектам стратегии, упомянутым в здесь .

...