python3从类到装饰器的自变量

时间:2017-05-23 14:28:01

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

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

 while ($myrow = mysqli_fetch_array($result)):

    $username   = $myrow["username"];
    $date       = $myrow["date"];
    $returned   = $myrow["returned"];
    $color;

    $formattedDate = date("d-m-Y", strtotime($myrow["date"]));

    $table = '<tr>';

    if ($returned == 'Yes'){ 
            $color = "green";
        } else if ($date < date("Y-m-d")) {
            $color = "red";
        } else{
            $color = "blue";
        }


       $table.= '<td><div style="color: '.$color.';">'.$username.'</div></td>';
       $table.= '<td><div style="color: '.$color.';">'.$formattedDate.'</div></td>'
       $table.= '<td><div style="color: '.$color.';">'.$returned.'</div></td>';


    $table .= '<tr>';

    echo $table;
 endwhile;

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

# 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()

我接近完成这项工作。我做错了什么?

2 个答案:

答案 0 :(得分:1)

您需要从__call__方法返回高阶函数(包装)。添加一个内部方法并将其返回。

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

答案 1 :(得分:1)

如果你忘记@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