LINUX.ORG.RU

[Python] Множественное наследование

 


0

2

Здравствуй ЛОР,

class A(object):
    def pr(self):
        print "A"

class B(object):
    def pr(self):
        print "B"

class C(A, B):
    def pr(self):
        super(C, self).pr()

if __name__ == '__main__':
    c = C()
    c.pr()

Как вызвать все функции pr у классов родителей? И почему вышеприведённый код этого не делает?

Потому что в случае с множественным наследованием и одинаковыми названиями методов в суперклассе надо чётко указывать, метод какого суперкласса ты хочешь вызывать.

По крайней мере, так оно в С++.

anonymous
()

попробуй по старому:

class A(object):
    def pr(self):
        print "A"

class B(object):
    def pr(self):
        print "B"

class C(A, B):
    def pr(self):
        A.pr(self)
        B.pr(self)

Zubchick
()
Ответ на: комментарий от ConnorMcLaud

множественное наследование - зло, тем более с одинаковыми элементами класса. Без него никак не обойтись?

lazyklimm ★★★★★
()
Ответ на: комментарий от lazyklimm

>множественное наследование - зло, тем более с одинаковыми элементами класса. Без него никак не обойтись?

Устоявшаяся архитектура фрэймворка юнит тестов. Класс теста наследуется от нескольких классов родителей, в которых реализуется setupEnvironment.

Не скажу, что без этого нельзя обойтись, но «здесь так принято» (с)

ConnorMcLaud
() автор топика
Ответ на: комментарий от KRoN73

Может быть вы просто разучились его готовить? Годы, седина... А тогда, 3 года назад, и дефки были моложе и множественное наследование было круто...

anonymous
()
Ответ на: комментарий от anonymous

Нет, просто перестал смешивать внутри одного объекта несколько :)

KRoN73 ★★★★★
()

никогда не понимал функциональную значимость super. нахера ее вообще придумали? просто вызвать метод у парента можно и без этого. кто-нибудь, может вменяемую аргументацию привести в пользу использования super?

Deleted
()
Ответ на: комментарий от Zubchick

Вообще, я за множественное наследоваение яйца бы отрывал. Посему вся эта ебатория выглядит как костыль алгоритмическим неасиляторам.

Deleted
()
Ответ на: комментарий от true_admin

>чтобы не хардкодить имена классов

с таким ходом мышления можно любое приложение назвать хардкодом. назвать именование классов хардкодом - это пиздец (простите за мой французский, но иначе это не называть)

Deleted
()
Ответ на: комментарий от Deleted

>никогда не понимал функциональную значимость super. нахера ее вообще придумали?

Меня в PHP сейчас бесит, что постоянно приходится юзать «function title() { ... parent::title(); .. }» вместо «function title() { ... parent(); .. }»

KRoN73 ★★★★★
()
Ответ на: комментарий от Deleted

имена классов меняются, чтобы в куче мест не писать придумали super() который вроде как нормально работает в py3k.

Короче, см. что Крон выше моего поста написал.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

>А в чём состоит зло множественного наследования?

При аккуратном программировании - нормально. Но при неаккуратном позволяет смешивать в одном объекте разные сущности. Вот это - зло :) Как в моём примере трёхлетней давности, когда я смешивал в одном объекте сущности бэкенда, внутренней логики объекта и его рендерера. Как только вынес рендерер в отдельную сущность, потребность в множественном наследовании отпала. И больше никогда не возвращалась и в будущем, с более сложными объектами. Как-то сразу стал заранее производить как можно большую декомпозицию.

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Вот такой случай считается нормальным? :) Единственное место где мне хочется прикрутить множественно наследование это сделать класс Log чтобы ко всем объектам легко логгирование прикручивать. Можно юзать последовательное наследование, но, имхо, тут это не нужно совсем.

class Log:
    def __init__(self):
        self.verbose = True

    def debug(self, msg):
        if self.verbose:
            print("DEBUG: [%s] %s" % (self.__class__.__name__, msg))


class Child(Parent, Log):
    def __init__(self):
        Log.__init__(self)
        self.debug("test test test")

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

У меня у базового класса всех моих объектов есть метод debug_title(), возвращающий что-то типа «class_name(id)», использующий его метод __toString() и есть множество разных способов использовать их (и подобных) в зависимости от задач, но ни разу даже в голову не приходило, что было бы неплохо подмешать к классу логгер :)

Т.е., в зависимости от ситуации, у меня вместо

    def __init__(self): 
        Log.__init__(self) 
        self.debug("test test test") 

будет или

    function __construct()
    {
        bors_log::debug($this, "test test test");
    }
или
    function __construct()
    {
        bors_hidden_log('debug', "test test test in {$this}");
    }

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

>Меня в PHP сейчас бесит, что постоянно приходится юзать «function title() { ... parent::title(); .. }» вместо «function title() { ... parent(); .. }»

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

Deleted
()
Ответ на: комментарий от KRoN73

вот мне приходится наследовать чужие классы, там такого нет :)

true_admin ★★★★★
()
Ответ на: комментарий от Deleted

вот зачем думать если можно тупо воткнуть super()? (я про py3k). Не нравится не используй, но говорить что это для лохов глупо. Зачем нужен питон если есть C.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

сделать класс Log чтобы ко всем объектам легко логгирование прикручивать

Для этого придумали типажи (traits).

dave ★★★★★
()
Ответ на: комментарий от true_admin

Это в Скале:

trait Logged {

  def debug(msg: String) {
    println(msg)
  }
}

Потом просто при создании класса (или объекта-синглтона) делаем «extends Logged» или «with Logged». Короче говоря, это похоже на интерфейс, который может реализовывать методы и иметь поля. Получается что-то среднее между одиночным и множественным наследованием. Особенность в том, что у типажа не может быть конструкторов (но это обходится). Еще все методы типажей линеаризуются. И нет известной «бриллиантовой» проблемы наследования как в Си++.

dave ★★★★★
()
Ответ на: комментарий от true_admin

Имхо, не считаю это нормальным. В данном случае имеет смысл применить не наследование, а композицию, т.е. не отношение типа «is-a», а «has-a».

Вопрос не в тему: чем logging-то не устраивает?

shylent
()
Ответ на: комментарий от shylent

в смысле композицию? Покажи пример.

Я и делаю на основе logging, но более высокоуровневый, с фильтрацией событий.

true_admin ★★★★★
()
Ответ на: комментарий от dave

ничего не находится по поиску python+типажи. У меня сейчас нет проблем с наследованием, значит ли это что мне типажи не нужны?

true_admin ★★★★★
()
Ответ на: комментарий от yoghurt

>Ну ну. Т.е. в конструктор базового класса в из конструктора наследника вы никогда не вызываете? :)

Хотя, это не совсем метод

сам спросил, сам ответил ;)

Deleted
()
Ответ на: комментарий от true_admin

>вот зачем думать если можно тупо воткнуть super()?

Не нравится не используй, но говорить что это для лохов глупо.

ты не находишь, что ты сам сейчас подтвердил все то, что я говорил? ;) только я делал упор на то, что всякие super являются костылями для тех, кто до сих пор юзает мультинаследование.

Deleted
()
Ответ на: комментарий от true_admin

Композиция B и A - это когда объект B становится атрибутом объекта A, т.е. «A has B», в отличие от наследования, когда B наследует от A, то можно сказать, что «B is A», так?

В данном случае можно объект 'log' делать атрибутом всех объектов иерархии, назначая его, скажем в __init__ базового класса.

Пардон за длинный пост, да еще и не совсем по теме, но я все-таки закончу.

Я считаю, что в этом конкретном случае (с логированием) вообще не нужно сводить вместе объекты типа Log и все остальное. Никто не мешает, по аналогии с logging, сделать на уровне модуля, допустим, 'log = logging.getLogger(...)', а потом спокойно вызывать log.debug(), log.critical() и т.п. Зачем нужна првязка к «текущему объекту» (self)? Чтобы, грубо говоря, сериализовать все атрибуты в строку, чтобы потом эту строку написать в лог, ведь так? Но тогда достаточно просто для класса адекватно определить __repr__ (ну, или __str__), который эти атрибуты отформатирует, как вам хочется, и все будет работать само и без лишних сущностей.

Надеюсь, что мысль донести удалось.

shylent
()
Ответ на: комментарий от Deleted

я юзаю super и я не юзаю наследование. Запись с super() короче, вот и всё.

true_admin ★★★★★
()
Ответ на: комментарий от shylent

Я правильно понимаю что ты предлагаешь делать так?

import logging
log = logging.getLogger()
class MyClass():
    def function:
        ...
        log.debug("[%s] debug message" % self)
true_admin ★★★★★
()
Ответ на: комментарий от true_admin

Я правильно понимаю что ты предлагаешь делать так?

Да.

Логгер можно по-разному инициализировать, - в одном месте, в каждом модуле по-отдельности, но это, в принципе, и не очень-то важно.

Делать же его атрибутом объектов всех классов - незачем. Главное, чтобы __str__ или __repr__ этих объектов отдавали осмысленную информацию.

shylent
()
Ответ на: комментарий от shylent

Это текущий вариант. Скажу чем он мне не нравится: каждый раз надо задавать форматирование и передавать имя класса итп параметры, это неправильно.

Плюс я не могу задавать, например, такие опции:

Log.rules = {
    MyClass1 : log.DEBUG,
    MyClass2 : log.CRITICAL,
    MyClass3 : None,
    'default': log.INFO,
}

Т.е. свою фильтрацию сообщений для различных классов,(можно даже в динамике этим управлять). Если же мы сделаем наследование(не важно множественно или обычное) то это всё элегантно решается. Оверхеда это особо не создаст.

true_admin ★★★★★
()

Какой только хренью люди не маятся, когда в их недоязыках комбинаций методов нет.

Love5an
()
Ответ на: комментарий от true_admin

В смысле декоратором класса? Или в другом месте? У мну щас после работы мозг отказывается работать...

Просто декоратор к __init__ или к любому другому методу, который нужно «проследить»:

class MyClass(blabla):
    @logme
    def __init__(self):
        ....

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

mikki
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.