为什么 namedtuple._make 检查 return 值的长度?
Why does namedtuple._make check the return value's length?
覆盖 Python 中 namedtuple
对象的 length 方法比您预期的要乏味得多。天真的方法,
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
不起作用。如果您检查 class 的实际源代码(可作为 _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
有趣的是,它会检查以确保 return 值的长度为 2。这使得重写元组上的 __len__
方法变得更加困难,因为 _make
将如果它 return 是一个长度不是 2 的值,就会抱怨。
可以通过将始终 returns 2 传递给 _make
:
的“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
是否安全?
_make
检查 return 值的长度,因为命名元组是固定长度的,并且 _make
必须强制执行。如果没有,你可以做
Point = namedtuple('Point', ['x', 'y'])
p1 = Point._make([1, 2, 3])
p2 = Point._make([1])
并得到一个没有 y
的点和一个结尾有额外条目的点。
_make
无法检查参数的长度,因为参数可以是不支持 len
的任意可迭代对象,所以 return 值的长度是最方便的要检查的东西。
不要覆盖 _make
以绕过此检查。您的对象与 namedtuple 的概念相去甚远——哎呀,与元组的概念相去甚远——您根本不应该使用 namedtuple 或任何元组 subclass。就写个正则的class.
覆盖 Python 中 namedtuple
对象的 length 方法比您预期的要乏味得多。天真的方法,
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
不起作用。如果您检查 class 的实际源代码(可作为 _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
有趣的是,它会检查以确保 return 值的长度为 2。这使得重写元组上的 __len__
方法变得更加困难,因为 _make
将如果它 return 是一个长度不是 2 的值,就会抱怨。
可以通过将始终 returns 2 传递给 _make
:
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
是否安全?
_make
检查 return 值的长度,因为命名元组是固定长度的,并且 _make
必须强制执行。如果没有,你可以做
Point = namedtuple('Point', ['x', 'y'])
p1 = Point._make([1, 2, 3])
p2 = Point._make([1])
并得到一个没有 y
的点和一个结尾有额外条目的点。
_make
无法检查参数的长度,因为参数可以是不支持 len
的任意可迭代对象,所以 return 值的长度是最方便的要检查的东西。
不要覆盖 _make
以绕过此检查。您的对象与 namedtuple 的概念相去甚远——哎呀,与元组的概念相去甚远——您根本不应该使用 namedtuple 或任何元组 subclass。就写个正则的class.