像C ++ 11一样分配给函数调用

时间:2015-06-12 10:28:36

标签: python python-3.x lambda

在C ++中,允许返回对值的引用,然后写入,例如:

#include <iostream>

int main() {
  int data[] = {1,2,3,4};
  std::cout << data[0] << " " << data[1] << " " << data[2] << " " << data[3] << '\n';
  auto key =
    [](int data[]) -> int &
    {
      return data[1];
    };
  key(data) = 6;
  std::cout << data[0] << " " << data[1] << " " << data[2] << " " << data[3] << '\n';
}

这是有效的,C ++ 11代码的输出是:

1 2 3 4
1 6 3 4

同时,在Python 3中:

data = (1,2,3,4)
key = lambda d: d[2]
key(data) = 5
print(data)

这有效,但不讨好,因为它很好地说明我可能不会分配给函数调用:

  File "gett.py", line 4
    key(data) = 5
    ^
SyntaxError: can't assign to function call

那么如何传递一个可用于获取和设置的callable? Python 3的方法是什么?

我的特殊用例是我有这样的东西:

#Data = namedtuple('Data',    ['meta', 'value', 'othervalue'])
# since namedtuples are not muteable

class Data:
  def __init__(self, meta, value, othervalue):
    self.meta = meta; self.value=value; self.othervalue=othervalue;

data = [Data('blabla', None, 543), Data('blabla', 5, 54), Data('blabla', 324, None), Data('blabla', None, 34), Data('blabla', 432, None)]

我希望将每个None替换为valueothervalue的上一个值,如下所示:

def nearest_before_interpolate(self, l, key):
  last = 0
  for i in range(len(l)):
    with getattr(l[i], key) as val:
      if val == None:
        setattr(l[i], key, last)
      else:
        last = val

现在我将密钥作为字符串传递,但如果这是一个通用的lambda,它可以以任何它认为合适的方式提取正确的字段(不是它真的需要这种灵活性,但我是比如lambda我想的更多的字符串,也更适合这个用例。)

有没有人有一个很好的建议怎么做?

2 个答案:

答案 0 :(得分:2)

这里有两个问题:

  • python语法不允许直接赋值函数调用的返回值 - can't assign to function call。就这么简单。

  • 元组是不可变的,因此您无法替换项目,只能更改它的值。这显然是您的简化示例中的问题 - 您无法更改数字的值.5是5。

解决这些问题,这是一个概念证明:

data = ([1],[2],[3],[4])
key = lambda d: d[2]
v = key(data)
v.append(0)
print(data)  # ([1], [2], [3, 0], [4])

更新:抱歉,我有点困惑,因为你使用元组但后来列表。

好吧,你几乎可以做到,只是没有你想要的语法:

class wrapper():
   def __init__(self, d, i):
     self.d = d
     self.i = i
   def set(self, v):
     self.d[self.i] = v

data = [1,2,3,4]
key = lambda d: wrapper(d, 2)
v = key(data)
v.set(5)
print(data)  # [1, 2, 5, 4]

在python中你不能重载赋值,所以你需要一些其他方法来改变值。在这里我选择了一个函数调用,但你可以使用任何可以intercepted的东西(例如:设置一个属性)。

答案 1 :(得分:0)

我认为这是最接近你没有主要hackery的地方:

operator>>