代码之家  ›  专栏  ›  技术社区  ›  jtm

更好的python属性修饰器

  •  3
  • jtm  · 技术社区  · 14 年前

    我继承了一些包含相当神秘的装饰器的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
    

    我得到的错误是因为 SysSt迹 . (也许这是对settrace的滥用?)

    我的问题是:同一个装潢师可以实现吗? 没有 系统设置。如果不是的话,我会做一些重改写。

    2 回复  |  直到 14 年前
        1
  •  8
  •   Thomas Wouters    14 年前

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

    但是,在Python2.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
  •  2
  •   SamB som-snytt    14 年前

    可以 有可能;看来这种滥用 settrace 正被用来捕获修饰函数,在它返回之前,目的是窃取它的局部变量…

    不幸的是,目前我能想到的主要方法包括黑客破解字节码。

    但是,您可以用一个要求每个这样修饰的函数调用另一个特殊函数而不是简单地返回的函数来替换它,或者您可以修改它来调用 sys.gettrace 而不是抛出任何活动的跟踪函数,然后恢复相同的跟踪函数。