LINUX.ORG.RU

[python] Прокси класс.

 


0

0

Есть задача - в цикле пройтись по всем уровням наследования класса, выполняя определенную манипуляцию с его полями. Список предков класса доспупен по self.__class__.__mro__ и я могу получить доступ к полям предка каждого класса из списка вызовом super(). Получился код примерно следующего содержания:

class BaseClass(object):

    def __init__(self, *args, **kwds):
        classes = []
        for cls in reversed(self.__class__.__mro__):
            if cls is object or cls is ControlBase:
                continue #super() от object и super() от ControlBase мне не нужны, т.к. там фактически поля object'а
            classes.append(super(cls, self))
        classes.append(self) #грязный хак для включения самого верхнего уровня

        for cls in classes:
            self.do_something(cls)

    def do_something(self, cls):
        if hasattr(cls, '__thisclass__'): #и тут грязный хак для различия между чистым self и списком прокси-классов, возвращенных super()
            names = cls.__thisclass__.__dict__
        else:
            names = cls.__class__.__dict__

        for name, val in names.iteritems():
            pass #Здесь мои манипуляции

В общем, слишком много некрасивых костылей. Вопрос в том, как сделать прокси класс аналогичный возвращаемому super(), то есть связать текущий self с методами определенного класса из числа предков, но так, чтобы прокси класс давал доступ к полям самого класса, а не его предка.

★★★

class A(object):
a=1
def foo(self):
print self.b

class B(A):
b=2
def foo(self):
A.foo(self)

A ты можешь указать не явно а точно так же получить из self.__class__.__mro__, self.__class__.__bases__ и т.п.

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

То есть фокус здесь в том, чтобы явно отправлять методу свой self в качестве первого параметра?

YogSagot ★★★
() автор топика

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

ntp
()

да, как-то непонятно что хочется получить

pawnhearts ★★★★★
()

Я строю аппликуху на активном использовании системы ивентов, взятых отсюда: http://www.valuedlessons.com/2008/04/events-in-python.html

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

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

YogSagot ★★★
() автор топика

Хм, кажется нашел.

http://stackoverflow.com/questions/1015307/python-bind-an-unbound-method

import types

def f(self): print self

class C(object): pass

meth = types.MethodType(f, C(), C) # Bind f to an instance of C print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>>

По идее именно то, что мне нужно. Приду домой - проверю.

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

Я не понимаю зачем вам нужно усложнять и привлекать магию.

Чем это не устраивает?

event = Event()

class A(object):
    def __init__(self):
        event.handle(self.handler_a)

    def handler_a(self):
        print 'a'

class B(A):
    def __init__(self):
        super(B, self).__init__()
        event.handle(self.handler_b)

    def handler_b(self):
        print 'b'

b = B()
event.fire()
$ python events.py
a
b
ntp
()
Ответ на: комментарий от ntp

>Я не понимаю зачем вам нужно усложнять и привлекать магию.

Усложню тут - облегчю себе работу в будущем. Ивентов будет очень много. И я считаю, что лучше просто объявить в классе метод обработчика с именем, оформленным в определенной нотации, и пусть его конструктор цепляет автоматом.

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

> метод должен быть явно связан с экземпляром чтобы не пришлось явно передавать self в метод.

ну так свяжи, например self.foo=lambda: somefunc(self)
или
from functools import partial
self.foo=partial(somefunc,self)

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

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

Я все равно не понимаю зачем вы ищете себе сложности с прокси-классом. Чем это не устраивает?

import inspect

event = Event()

class A(object):
    def __init__(self):
        for name, value in inspect.getmembers(self):
            if name.startswith('handler_'):
                event.handle(value)

    def handler_a(self):
        print 'a'

class B(A):
    def handler_b(self):
        print 'b'

b = B()
event.fire()
ntp
()
Ответ на: комментарий от ntp

>Чем это не устраивает?

Постоянными замороками с вопросом "А какой у меня там в данный момент уровень вложенности, чтобы знать, каким именем мне называть нужный мне обработчик на данном уровне".

На всех уровнях у метода обработчика одно и то же имя. Фактически все что мне требуется для объявления события на этапе собственно разработки приложения, это сперва в конструкторе объявить переменную self.OnLoadEvent = Event() и в теле класса просто объявить метод def OnLoad(self): и все, все корректно подцепиться само собой и мне будет совершенно неважно, что где-то там парой уровней выше уже был объявлен обработчик OnLoad(self), прозрачным для меня образом подцепятся они оба и оба будут вызываться по очереди.

И, да. Фокус с types.MethodType() оказался более чем успешным, вчера дома потестил, все работает ровно так, как мне надо. Всем спасибо, вопрос решен. =)

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