Лучший декоратор свойств Python - PullRequest
3 голосов
/ 10 апреля 2010

Я унаследовал некоторый код Python, который содержит довольно загадочный декоратор. Этот декоратор устанавливает свойства в классах по всему проекту. Проблема в том, что это я отследил мои проблемы отладки с этим декоратором. Кажется, это «обнюхивает» все отладчики, которые я пробовал и пытаюсь ускорить код с помощью psyco-брейков. (Кажется, псих и этот декоратор не играет хорошо). Я думаю, что было бы лучше изменить это.

def Property(function):
    """Allow readable properties"""
    keys = 'fget', 'fset', 'fdel'
    func_locals = {'doc':function.__doc__}
    def probeFunc(frame, event, arg):
        if event == 'return':
            locals = frame.f_locals
            func_locals.update(dict((k,locals.get(k)) for k in keys))
            sys.settrace(None)
        return probeFunc
    sys.settrace(probeFunc)
    function()
    return property(**func_locals)

Используется так:

class A(object):
    @Property
    def prop():
        def fget(self):
            return self.__prop
        def fset(self, value):
            self.__prop = value
    ... ect

Ошибки, которые я получаю, говорят о проблемах из-за sys.settrace . (Возможно, это злоупотребление settrace?)

Мой вопрос: возможен ли тот же декоратор без sys.settrace. Если нет, то меня ждут тяжелые переписки.

Ответы [ 2 ]

8 голосов
/ 10 апреля 2010

Тоже самое? Нет. Вы не можете делать то, что делает этот декоратор без магии, как sys.settrace. (Технически это не обязательно должен быть sys.settrace, но использование чего-то другого - например, переписывание байт-кода - не будет улучшением.) Вы можете сделать это намного проще, например, сделав:

def Property(f):  
    fget, fset, fdel = f()
    fdoc = f.__doc__
    return property(fget, fset, fdel, fdoc)

class Foo(object):
    @Property
    def myprop():
        "Property docstring"
        def fget(self):  
            return 'fget' 
        def fset(self, x):
            pass
        def fdel(self):
            pass
        return fget, fset, fdel

В Python 2.6 и более поздних версиях вы можете использовать немного другой декоратор, однако:

def Property(cls):
    fget = cls.__dict__.get('fget')
    fset = cls.__dict__.get('fset')
    fdel = cls.__dict__.get('fdel')
    fdoc = cls.__doc__
    return property(fget, fset, fdel, fdoc)

И вы бы использовали это так:

class Foo(object):
    @Property
    class myprop(object):
        "Property docstring"
        def fget(self):
            return 'fget'
        def fset(self, x):
            pass
        def fdel(self):
            pass

Однако, более идиоматический способ сделать это в Python 2.6 и более поздних версиях выглядит так:

class Foo(object):
    @property
    def myprop(self):
        "Property docstring"
        return 'fget'
    @myprop.setter
    def myprop(self, x):
            pass
    @myprop.deleter
    def myprop(self):
            pass
2 голосов
/ 10 апреля 2010

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

К сожалению, основные подходы, которые я могу себе представить, включают взлом байт-кода: - (.

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

...