2017-05-02 32 views
0

在Python中重寫namedtuple對象的長度方法比您預期的要枯燥乏味。天真的做法,爲什麼namedtuple._make檢查返回值的長度?

from collections import namedtuple 

class Rule(namedtuple('Rule', ['lhs', 'rhs'])): 
    def __len__(self): 
     return len(self.rhs) 

r = Rule('S', ['NP', 'Infl', 'VP']) 
new_r = r._replace(lhs='CP') # raises a TypeError 

不起作用。如果你檢查類(可作爲_source屬性)的實際的源代碼,你可以看到,_make(其中_replace電話和引發錯誤)是這樣實現的:

@classmethod 
def _make(cls, iterable, new=tuple.__new__, len=len): 
    'Make a new Rule object from a sequence or iterable' 
    result = new(cls, iterable) 
    if len(result) != 2: 
     raise TypeError('Expected 2 arguments, got %d' % len(result)) 
    return result 

有趣的是,檢查以確保返回值的長度爲2。這使得它更難以覆蓋的元組的__len__方法,因爲如果它返回比2

其他長度的值這是可能的_make會抱怨通過傳遞總是返回2到01的「len」函數來防止此行爲:

from collections import namedtuple 

class Rule(namedtuple('Rule', ['lhs', 'rhs'])): 
    def _make(self, *args, len=lambda _: 2, **kwargs): 
     return super()._make(*args, len=len, **kwargs) 

    def __len__(self): 
     return len(self.rhs) 

r = Rule('S', ['NP', 'Infl', 'VP']) 
new_r = r._replace(lhs='CP') # fine 

我的問題是,爲什麼是這個長度檢查不一定是第一名,而且是安全的替代_make所以它不這樣做呢?

+4

「在Python中重寫namedtuple對象的長度方法比您期望的要冗長乏味 - 」您爲什麼要這麼做?這似乎是一個可怕的想法,會導致各種錯誤,即使除了這個錯誤。 – user2357112

回答

6

_make檢查返回值的長度,因爲namedtuples是固定長度的,並且_make必須執行該操作。如果沒有,你可以做

Point = namedtuple('Point', ['x', 'y']) 
p1 = Point._make([1, 2, 3]) 
p2 = Point._make([1]) 

,並獲得無y一個點和一個額外的入口懸掛斷點結束。

_make無法檢查參數的長度,因爲參數可能是不支持len的任意迭代,所以返回值的長度是最方便的檢查。

請勿忽略_make以繞過此檢查。你的對象與namedtuple的概念相去甚遠 - 從元組的概念來看,它足夠遠 - 你不應該使用namedtuple或任何元組子類。只要寫一個普通班。