【问题标题】:python3 self variable from class to decoratorpython self 变量从类到装饰器
【发布时间】:2017-06-04 14:03:24
【问题描述】:

我正在尝试构建我的第一个装饰器并在一个类中实现它。

# decorator class
class Cache(object):
  def __init__(self,filename,**kwargs):
    self.time_ago = datetime.now() - timedelta(**kwargs)
    self.filename = filename

  def __call__(self,fn):
    if not os.path.isfile(self.filename):
      return self.cache(fn(self))

    time_ago = self.time_ago
    filename = self.filename
    c_age = datetime.fromtimestamp(os.path.getctime(filename))
    m_age = datetime.fromtimestamp(os.path.getmtime(filename))
    print (c_age)
    print (m_age)
    print (time_ago)
    if c_age < time_ago or m_age < time_ago:
      return self.cache(fn(self))
    else:
      return self.read()

  def cache(self,data):
      with open(self.filename,'r+') as ef:
        ef.write(data)
        return ef.read()

  def read(self):
    f = open(self.filename,'r')
    data = f.read()
    f.close()
    return data

我正在尝试在下面的类中调用装饰器:

class Zabb(object):

  @Cache('nodes.json',minutes=1)
  def getNodes(self):
    return "Get Nodes"

我这样称呼它:

z = Zabb()
nodes = z.getNodes()

我收到以下错误:

Traceback (most recent call last):
File "./deco.py", line 52, in <module>
nodes = z.getNodes()
TypeError: 'str' object is not callable

我即将完成这项工作。我做错了什么?

【问题讨论】:

  • __call__ 需要返回一个高阶函数(包装)

标签: python python-3.x python-3.5


【解决方案1】:

您需要从__call__ 方法返回一个高阶函数(wrapped)。添加一个内部方法并返回它。

def __call__(self, fn):
    def wrapper(*args, **kwargs): # <-- Add this wrapper
        if not os.path.isfile(self.filename):
            return self.cache(fn(*args, **kwargs))

        time_ago = self.time_ago
        filename = self.filename
        c_age = datetime.fromtimestamp(os.path.getctime(filename))
        m_age = datetime.fromtimestamp(os.path.getmtime(filename))
        print (c_age)
        print (m_age)
        print (time_ago)
        if c_age < time_ago or m_age < time_ago:
            return self.cache(fn(*args, **kwargs))
        else:
            return self.read()
    return wrapper # <-- Return the wrapper

【讨论】:

    【解决方案2】:

    如果您忘记了 @deco 语法糖和推理它真正做什么,装饰器会更容易理解。在你的例子中,

    @Cache('nodes.json',minutes=1)
    def getNodes(self):
        return "Get Nodes"
    

    真正的意思:

    def getNodes(self):
        return "Get Nodes"
    
    getNodes = Cache('nodes.json',minutes=1)(getNodes)
    

    实际上将 Zabb.getNodes 重新绑定到 Cache('nodes.json',minutes=1).__call__(getNodes) 的结果 - 这是一个字符串,而不是一个函数。

    您想要的是让Cache.__call__ 返回一个函数,该函数将包装对装饰函数的调用,即:

      def __call__(self,fn):
        def wrapper(*args, **kw):
          if not os.path.isfile(self.filename):
            return self.cache(fn(self))
    
          time_ago = self.time_ago
          filename = self.filename
          c_age = datetime.fromtimestamp(os.path.getctime(filename))
          m_age = datetime.fromtimestamp(os.path.getmtime(filename))
          print (c_age)
          print (m_age)
          print (time_ago)
          if c_age < time_ago or m_age < time_ago:
            return self.cache(fn(self))
          else:
            return self.read()
        return wrapper
    

    【讨论】:

      猜你喜欢
      • 2011-07-17
      • 2012-08-14
      • 1970-01-01
      • 2021-12-23
      • 2012-11-24
      • 2020-10-09
      • 2023-03-23
      • 1970-01-01
      相关资源
      最近更新 更多