一个更好的python属性装饰器

时间:2010-04-09 20:17:49

标签: python debugging properties decorator

我继承了一些包含相当神秘的装饰器的python代码。此装饰器在整个项目的类中设置属性。问题是,我已将此调试问题跟踪到此装饰器。似乎它“fubars”我试过的所有调试器,并试图加速psyco休息的代码。 (似乎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 个答案:

答案 0 :(得分:8)

同样的事情?没有。如果没有像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

答案 1 :(得分:2)

可能可能;似乎这种滥用settrace被用于在它返回之前捕获装饰函数,以便窃取它的局部变量......

不幸的是,我现在想到的主要方法涉及破解字节码: - (。

但是,您可以将其替换为需要每个如此装饰的函数来调用另一个特殊函数而不是简单地返回,或者您可以将其修改为调用sys.gettrace而不是丢弃任何跟踪函数可能是活动的,然后恢复相同的跟踪功能。