Найти - Пользователи
Полная версия: autosuper
Начало » Python для экспертов » autosuper
1
gkraser
Хотелось бы вызывать super без указания класса (в python 2.6).
Вот нашел решение:

class AutoSuper(type):
def __init__(cls, name, bases, dict):
super(AutoSuper, cls).__init__(name, bases, dict)
setattr(cls, "_%s__super" % name, super(cls))

class Base(object):
__metaclass__ = AutoSuper
Теперь пример из http://python.su/forum/viewtopic.php?id=7772 работает:

class A(Base):
def f(self):
print 'A.f'
return None

class B(A):
def f(self):
print 'B.f'
return self.__super.f()

class C(B):
def f(self):
print 'C.f'
return self.__super.f()
В чем могут быть проблемы/недостатки?
bw
Из-за этих пунктов смахивает на хак:
1. Метаклассы здесь не нужны (как наследование от заранее подготовленного класса).
2. Я бы не стал приватить (пусть атрибут называется __super__).

Я бы привёл вывод супера к такому виду:
...
def foo(self):
return my.utils.super()
Где my.utils некий твой модуль.
А вообще, всё это гон, зачем?

..bw
gkraser
bw
А вообще, всё это гон, зачем?
Хочется в python 2.6 иметь super без указания классов (как в python 3)….

Вообщем эта методика не работает: идет привязка к именам классов, из-за которой вылезут перекрытия имен _x_super при совпадении имен унаследованных классов…

А все таки: есть ли возможность иметь super без указания классов как в python 3)?
Андрей Светлов
Чепуха. Несколько лет назад пытался использовать что-то вроде http://code.activestate.com/recipes/286195-selfsuper/
Честно сказать, никакого выигрыша не ощутил. Не стоит эта возня потраченных усилий.
gkraser
Выгрыш - в читабельности, в унификации кода для перекрытых методов.

Этот autosuper.py я сейчас и пробую. Вроде - работает…
Андрей Светлов
О какой унификации вы говорите? Если все равно руками вбивать - то можно и имя класса при этом поменять.
Печатать меньше на пару идентификаторов. Нужно делать на один импорт больше.
Код работает немного медленней. Читать stacktrace в случае ошибки менее приятно.

Дело, конечно, господское. Я пробовал - не прижилось.
ilya1
__super__ явно не подойдет, так как будет для всей иерархии один, а вот __super как раз то, что нужно (для каждого класса свой родитель). Описанное решение написал Guido, так что должно работать,- я пользуюсь, нравится (после C++ не могу отказаться от этого удобства).

Но и это решение критикуют, http://www.artima.com/weblogs/viewpost.jsp?thread=236278 .
Андрей Светлов
Проясните пожалуйста, как вы использовали super в С++? Насколько я помню, такой конструкции там нет
ilya1
Андрей Светлов
Проясните пожалуйста, как вы использовали super в С++? Насколько я помню, такой конструкции там нет
Конечно же в такой реализации там нет, но важна та сама идея/удобство:
class A
{
A(int) {}
};

class B: public A
{
typedef A MyParent;
public:
B(int i): MyParent(i) {}
};

class C: public B
{
typedef B MyParent;
public:
C(int i): MyParent(i) {}
};
Замечания:
- основное применение не в конструкторах, а в виртуальных методах;
- MyParent закрыт ото всех, в первую очередь от классов-наследователей, потому вызвать метод неправильного родителя невозможно.
- вообще, фишка данного приема - не надо помнить какому классу метод принадлежит, и кто его родитель; при копи-пасте сильно помогает.
ilya1
Кстати, вышеуказанный autosuper работает только для нового типа классов (порожденных от object), для классических не пройдет. А у меня, как назло, код завязан на несколько “классических” классов (пример: cmd.Cmd). Потому (из упрямства) попытался решить проблему, вышло вот так:

# Для старых классов (не порожденных от object) пользуемся так:
# make_super_for_classic_class(MyOld, Old)
# , установить после (!) описания класса MyOld

class Super(object):
''' По примеру http://www.python.org/download/releases/2.2/descrintro/#superexample '''
def __init__(self, typ, obj):
self.typ = typ
self.obj = obj
def __getattr__(self, attr):
dct = self.typ.__dict__
if attr in dct:
x = dct[attr]
if hasattr(x, "__get__"):
# привязка метода x к объекту self.obj
x = x.__get__(self.obj)
return x
raise AttributeError, attr

def make_super_for_classic_class(cls, parent_cls):
def get_super_attr(obj):
return Super(parent_cls, obj)
# добавляем атрибут __super через setattr из-за скрытности первого
# вне класса cls
setattr(cls, "_%s__super" % cls.__name__, property(get_super_attr))
Покритикуйте, пож. . Тестовый пример:
class AClassic:
def func(self):
return "A"

class BClassic(AClassic):
def func(self):
return self.__super.func() + "B"
make_super_for_classic_class(BClassic, AClassic)

class CClassic(BClassic):
def func(self):
return self.__super.func() + "C"
make_super_for_classic_class(CClassic, BClassic)

eq_('ABC', CClassic().func())
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB