【问题标题】:Defining a "property"-like decorator in Python 2.7在 Python 2.7 中定义类似“属性”的装饰器
【发布时间】:2012-06-02 23:58:30
【问题描述】:

我正在尝试编写一个类似于@property 的装饰器,但遇到了一些问题。

class Dec(object):
  def __init__(self, fn):
    self._fn = fn
    self._before = None
  @property
  def before(self)
    return self._before
  @before.setter
  def before(self, fn):
    self._before = fn
  def __call__(self, *args, **kwargs):
    self._before(*args, **kwargs)
    self._fn(*args, **kwargs)

def withbefore(fn):
  return Dec(fn)

它是一个简单的链式装饰器。 @property/@.setter 语法正是我想要克隆的。

这行得通:

@withbefore
def foo():
   ...
@foo.before
def beforefoo():
  ...

但在课堂上却没有:

class Weee(object):
    @withbefore
    def do_stuff(self):
      pass
    @do_stuff.before
    def before_do_stuff(self):
      pass

它会引发导入错误。

TypeError: 'NoneType' object is not callable

如何正确模拟@property/.{setter,getter,deleter}?

【问题讨论】:

  • 为什么before实际上是一个属性?

标签: python decorator


【解决方案1】:

真诚地,我认为你最好:

from functools import wraps

def withbefore(fn):
    def dec(bef):
        fn._before_fn = bef
        return bef

    @wraps(fn)
    def _wrapper(*args, **kwargs):
        fn._before_fn(*args, **kwargs)
        return fn(*args, **kwargs)

    _wrapper.before = dec
    return _wrapper

它更紧凑,更 Pythonic,应该适用于所有情况。

【讨论】:

    【解决方案2】:

    实际上,它引发了一个 TypeError。

    无论如何,我在使用函数运行装饰器时也遇到了同样的错误。发生这种情况是因为,当您使用 @foo.before 装饰函数时,它将以装饰函数作为参数调用 self._before 函数。由于self._beforeNone,所以会报错。

    有多种解决方案。我最喜欢的是将不同的默认值设置为 self._before - 一个将设置 self._before 值的函数:

    class Dec(object):
      def __init__(self, fn):
        self._fn = fn
        def setbefore(b):
            self._before = b
        self._before = self.default_before = setbefore
    

    当然,这个函数不应该在调用Dec对象的时候调用所以我们改一下__call__方法:

      def __call__(self, *args, **kwargs):
          if self._before != self.default_before:
             self._before(*args, **kwargs)
          self._fn(*args, **kwargs)
    

    【讨论】:

    • 啊,我知道了。我认为整个@property 部分相当愚蠢,没有它会更干净。此外,一旦到位,我仍然需要做this 以确保 self 是正确的。谢谢!
    • @teeler 哇,第二个问题的链接答案太棒了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2018-10-25
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    相关资源
    最近更新 更多