2015-06-12 67 views
1

在C++中一個被允許返回到一個值的基準,然後寫至是,例如:分配給一個函數調用類似於C++ 11

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

這工作,但不請,因爲它很好地指出,我不得轉讓好玩ction要求:

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)] 

,我想對於任何一個valueothervalue以前的值替換每個None,就像這樣:

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我比猜想更多,也更適合這個用例)。

有沒有人有一個很好的建議如何做到這一點?

+0

元組是不可變的,所以你簡單的例子就沒有意義了。 –

+0

區別在於C++允許函數返回可分配給*的東西* - Python不會,所以它根本沒有意義。 – jonrsharpe

+0

>>> A [2] = 5 回溯(最近通話最後一個): 文件 「」,1號線,在 類型錯誤: '元組' 對象不支持項目分配 – Markon

回答

2

有兩個問題在這裏:

  • 的Python語法不允許直接分配給一個函數調用的返回值 - can't assign to function call。就那麼簡單。

  • 元組是不可變的,所以你不能替換一個項目,只能改變它的值。這顯然是在例如Symplified公司的一個問題 - 你不能改變一個數字的值。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(例如:設置屬性)的東西。

+0

嗯,這裏鍵返回列表,你可以追加和你可以改變的東西,但是你不能用其他東西來覆蓋整個東西。這隻適用於,我認爲,如果鍵返回類似指針的類型,如列表,但不是該列表的元素。 – Herbert

+0

即:data = [1,2,3,4]; key = lambda x:x [1]; v =密鑰(數據); V = 5;打印(數據)結果在[1,2,3,4] – Herbert

+0

它適用於任何可變的,只要你不做*賦值*。你的例子有點混亂(元組vs列表),給我一些時間... –

0

我覺得這是你可以得到無重大兩輪牛車最接近:

class Data(object): 

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

    def __getitem__(self, key): 
     return getattr(self, key) 

    def __setitem__(self, key, value): 
     setattr(self, key, value) 


d = Data('blabla', None, 543) 
print d.value      # None 
d['value'] = 321 
print d.value      # 321 
+0

這將是很多樣板代碼,此外,我可能希望在某一時刻使用一種數據類型的訪問方式,而另一種情況下則使用另一種類型的訪問方式。如果你想分開getter和setter,最好傳遞一個get-lambda和一個set-lambda,而不是你的OO實現,因爲獲取和設置實現應該是每個調用而不是每個類型定義的。 – Herbert

+0

@Herbert我不希望將他們分開,只是沒有辦法解決這個問題,正如其他人指出的那樣。你可以編寫一個通用的包裝類,該類使用get-lambda和set-lambda(或任何其他類型的邏輯)實例化,並提供相應的'__getitem__'和'__setitem__'。 –