valerium
@valerium
Изобретая велосипед

Как правильно переопределить конструктор класса?

Приветствую.

Да, вопрос похож на нубство, но я как-то совсем запутался.

Есть класс, унаследованный от datetime.date. К этому классу нужно добавить пару атрибутов и пару свойств. Для этого я в своём классе прописывают функцию __init__, в которой делаю обычную рутину: проверяю параметры, создаю новые атрибуты, после чего вызываю конструктор класса-родителя.

Когда я пытаюсь создать экземпляр класса, используя только те атрибуты, которые принимает родительский класс, всё отлично. Когда же я пытаюсь добавить ещё атрибутов, вылетает TypeError. ЧЯДНТ?

Немного кода. Так выглядит мой класс.
class MyClass(date):
    def __init__(self, m_year: int, m_month: int, m_day: int,
                 expiry: date=None, *args, **kwargs):
        if expiry:
            self._expiry = expiry
        else:
            self._expiry = date(m_year, m_month, m_day)
        super(Maturity, self).__init__(*args, **kwargs)

    @property
    def expiry(self):
        return {'year': self._expiry.year,
                'month': self._expiry.month,
                'day': self._expiry.day}


Создаём экземпляр класса. Так всё хорошо, работают как методы родительского класса, так и моего.
>>> q = MyClass(2015, 5, 5)
>>> q
MyClass(2015, 5, 5)
>>> q.strftime('%Y')
'2015'
>>> q.expiry
{'day': 5, 'month': 5, 'year': 2015}


Но стоит мне захотеть болшего, как выпадает вот такое исключение.
>>> q = MyClass(2015, 5, 5, expiry=date(2015, 5, 1))
TypeError: function takes at most 3 arguments (4 given)


Помимо прочего, смущает то, что код одинаково работает как с 8-й строкой (вызов super), так и без неё.
  • Вопрос задан
  • 512 просмотров
Решения вопроса 2
@adv-tsk
Full Stack Web Developer
Это происходит потому, что конструктор класса date принимает всего три аргумента: year, month, day, а Вы пытаетесь передать ему дополнительные аргументы. Вот как Вы должны были поступить в Вашем случае:

class MyClass(date):

    __slots__ = '_expiry',

    def __new__(cls, m_year, m_month, m_day, expiry=None, *args, **kwargs):
        return super(MyClass, cls).__new__(cls, m_year, m_month, m_day)

    def __init__(self, m_year, m_month, m_day, expiry=None, *args, **kwargs):
        if expiry:
            self._expiry = expiry
        else:
            self._expiry = date(m_year, m_month, m_day)

    @property
    def expiry(self):
        return {'year': self._expiry.year,
                'month': self._expiry.month,
                'day': self._expiry.day}

>>> q = MyClass(2015, 5, 5, expiry=date(2015, 5, 1))
>>> print(q.expiry)
>>> {'year': 2015, 'day': 1, 'month': 5}

UPD: То что Вы называете конструктором класса, является инициализатором класса, т.е. тот самый метод __init__(). Конструктором класса является метод __new__().
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы