Форум сайта python.su
Есть стремление не приписывать декоратор к каждому методу класса, а просто сказать, что все функции этого класса должны перед вызовом сделать то-то и то-то. Например, напечатать, “сейчас работает функция f(a=1,b=2,c=3)”
Представляю себе код примерно так:
import types
class ClassWithLoggedFunctions(type):
def __call__(self, *args, **kargs):
self.instance = super(ClassWithLoggedFunctions, self).__call__(*args,**kargs)
def __call__(self, *args, **kargs):
print 'execution %s(%s, %s)' % (func, args, kargs)
func.__call__(self, *args, **kargs)
for i in dir(self.instance):
func = getattr(self.instance, i)
if isinstance(func, types.MethodType):
pass # magic here!
return self.instance
class C():
__metaclass__ = ClassWithLoggedFunctions
def f(self, a, b, c):
return (a,b,c)
C().f(1,2,3)
Офлайн
Может лучше воспользоваться правильным логированием и писать сообщения для дебага приложения в самих методах класса?
import logging
logger = logging.getLogger(__name__)
class C(object):
def f(self, a, b, c):
logger.debug('f called with %r, %r, %r' % (a, b, c))
# ... process
logger.debug('f done')
Офлайн
Я бы подошёл так:
class MetaProperty(type):
def __init__(cls, name, base, cls_dict):
for attr, value in cls_dict.items():
if callable(value):
setattr(cls, attr, property(value))
class StrangeObject(object):
__metaclass__ = MetaProperty
def a(self):
return 'a'
so = StarangeObject()
assert so.a == 'a'
Офлайн
А просто в __getattribute__ заврапить то, что является callable не пойдет?
Офлайн
Перемудрил я! Спасибо ZZZ!
Сделал так:
import types
def decorator(f):
def func(*args, **kargs):
print 'executing %s...' % f.__name__
return f(*args, **kargs)
return func
class LoggedClass(type):
def __call__(cls, *args, **kargs):
def func(f):
print f.__name__
return f
for attr in dir(cls):
value = getattr(cls, attr)
if isinstance(value, types.MethodType):
setattr(cls, attr, decorator(value))
return type.__call__(cls, *args, **kargs)
class CustomClass(object):
__metaclass__ = LoggedClass
def some_function(self):
return 'a'
c = CustomClass()
print c.some_function()
Офлайн
спасибо за классный рабочий пример!
только вот функция func, которая внутри __call__ похоже никогда не вызывается.
как и для чего подразумевается ее использовать?
собственно у меня похожая задача, только я хочу использовать декораторы не только для логирования,
но и для обработки ошибок, а так же возможно, для разных уровней логирования.
для двух последних задач, кмк, нужны декораторы, меняющие свое поведение,
в зависимости от внешних условий (например параметры программы).
задача и ее решение на словах:
- есть много классов и их методов, возвращающих True/False.
- хочется не меняя их (или меняя минимально ~1-2 строки на класс) писать новый клиентский код,
который не будет проверять True/False после каждого вызова
- пишем декоратор для обработки ошибок, в котором, в зависимости от какого-то класса конфигурации,
решаем, что на каждый False надо еще бросить Exception (хочется завершать программу по любой ошибке),
тогда клиентский код становится компактнее
можно сделать лучше?
код пока еще не написан…
далее буду эксперементировать с тем сохраняется ли при таком подходе более или адекватный стэк,
что важно для анализа ошибок “пользователем” программы.
еще интересный момент в том, что как и с методами, хотелось бы применять к классу сразу несколько декораторов.
но для этого, я так понимаю, их прийдется объединять во что-то типа иерархии наследования,
с обеспечением вызова всех базовых классов.
проще нельзя?
Отредактировано (Апрель 18, 2011 07:45:42)
Офлайн
функция func, которая внутри __call__ похоже никогда не вызывается.Осталось от дебага, видимо
можно сделать лучше?Пользовался дополнительными флагами при объявлении класса. И обрабатывал их в метаклассе.
class CustomClass(object):
__metaclass__ = LoggedClass
_throw_exc_on_False = True
еще интересный момент в том, что как и с методами, хотелось бы применять к классу сразу несколько декораторов.Можно, только осторожно) У меня это сделать нормально не получилось. В результате, нарисовал иерархию метаклассов, там все и обрабатывал.
но для этого, я так понимаю, их прийдется объединять во что-то типа иерархии наследования,
с обеспечением вызова всех базовых классов.
Офлайн
Ребята, 2011 год на дворе! Начиная с Python 2.6 можно писать декораторы для классов.
Даже не взирая на то, что логировать вызовы всех методов без исключения — бессмысленно.
Логи ведь нужно не только писать, а еще и читать ;)
Офлайн
Андрей Светловну и как это сделать лучше учитывая, что год 2011 и python >= 2.6?
Ребята, 2011 год на дворе! Начиная с Python 2.6 можно писать декораторы для классов.
Андрей Светловналичие смысла определяется разработчиками, а читабельность системой логирования.
Даже не взирая на то, что логировать вызовы всех методов без исключения — бессмысленно.
Логи ведь нужно не только писать, а еще и читать ;)
Офлайн
мда… срочно надо почитать про мета-классы.
задам, наверное, ламерский вопрос.
каким образом, флаг _throw_exc_on_False или любой другой можно передать
из CustomClass в LoggedClass или прочитать внутри него,
тем самым, дополнительно настроив поведение декоратора?
Офлайн