Python 避免在多态性获胜的情况下使用type()比较';行不通
我在()中遇到了以下情况: 我对type(element)==type([])的使用感到震惊。这不仅是一种糟糕的做法,而且这个函数对任何其他序列类型都不起作用。多态性是避免类型比较的典型方法,但不能在这里使用。在这种情况下,如何避免类型比较?我认为:Python 避免在多态性获胜的情况下使用type()比较';行不通,python,types,Python,Types,我在()中遇到了以下情况: 我对type(element)==type([])的使用感到震惊。这不仅是一种糟糕的做法,而且这个函数对任何其他序列类型都不起作用。多态性是避免类型比较的典型方法,但不能在这里使用。在这种情况下,如何避免类型比较?我认为: def recursive_sum(nested_sum_list): sum = 0 for element in nested_num_list: try: sum += element
def recursive_sum(nested_sum_list):
sum = 0
for element in nested_num_list:
try:
sum += element
except TypeError:
sum += recursive_sum(element)
return sum
这使得该函数适用于其他序列,但仍然有点粗糙。谢谢 对于任意嵌套列表的展平,您总是需要某种检查来测试元素本身是iterable还是leaf节点。我不会将展平与计算一个函数中的和结合起来,而是定义一个只进行展平的生成器函数:
def flatten(x):
try:
it = iter(x)
except TypeError:
yield x
else:
for i in it:
for j in flatten(i):
yield j
这样,您将在单个函数中包含所有丑陋的位。对于嵌套序列x
,现在可以执行以下操作
sum(flatten(x))
获取递归和。在我所知的任何语言中,您在这里看到的都不是多态性<代码>+=对于列表意味着一件事,对于数字意味着另一件事。您希望列表具有不同寻常的含义(汇总所有元素并返回总和),但这仅对您的特定示例有意义。对于列表的其他(我想说是大多数)用法,
+=
的原始含义要方便得多
要使其真正具有多态性,您可以从列表中派生出+=
,并使+=
表示您想要的意思-这样您就不需要这些黑客
顺便说一句:
应改写为:
if isinstance(element, list):
您正在检查元素是否可以添加到int,这不是您想要的
不过,try
还不错:试着把它当作一个iterable使用——如果它起作用,那么它就是一个iterable:
def recursive_sum(nested_sum_list):
sum = 0
# this raises TypeError if element is not a sequence
for element in nested_num_list:
try:
sum += recursive_sum(element)
except TypeError:
sum += element
return sum
对于iterables,还有一个解决方案:
import collections
print isinstance(element, collections.Iterable)
它基本上只是搜索一个\uuuuuuuuuuuuuuuuuu
方法。“sum”函数接受一个iterable,所以我会使用“hasattr”内置函数检查元素是否实现了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
像这样:
def recursive_sum(nested_num_list):
sum = 0
for element in nested_num_list:
if hasattr(element, '__iter__'):
sum = sum + recursive_sum(element)
else:
sum = sum + element
return sum
您可以使用isinstance(element,collections.sequence)检查元素是否是序列
此函数的目的不是为了普遍适用于添加嵌套结构,它只是为了演示递归而创建的
添加更复杂的序列类型检查、try和except,或者添加数字以外的内容,都会降低该函数作为递归学习工具的实用性
也就是说,isinstance(element,(list,tuple))
在这里可能更合适,并且不会增加任何复杂性。列表的真实情况:
>>> import collections
>>> hasattr(element, '__getitem__')
True
>>> not hasattr(element, 'keys')
True
>>> isinstance(element, collections.Sequence)
True
>>> hasattr(element, '__iter__')
True
字符串的真实情况:
>>> string = '1234'
>>> hasattr(string, '__getitem__')
True
>>> not hasattr(string, 'keys')
True
>>> isinstance(string, collections.Sequence)
True
>>> hasattr(string, '__iter__')
False
很好,但效率极低-大多数子元素可能是数字,而不是列表,因此会抛出大量异常。这实际上是我想到的第一件事,但后来我意识到,“检查元素是否可以添加到int”在绝大多数情况下在功能上是等效的,计算上是优越的,而且(可以说)语义上更准确。它确实反转了原始函数的逻辑,但这很好。不管怎样,谢谢你提出这个备选方案。@Bryan Head:是的,这个函数可能更有意义,但你问了一个不同的问题:如何识别iterables,我试着回答这个问题:-)注意,有些iterables没有\uuuUr\uUr
属性。要测试对象是否可编辑,请使用try:iter(x);除了TypeError:…
或isinstance(x,collections.Iterable)
。iter(x)将为string返回True,如果您的实际用途列表喜欢集合展平,您希望避免这种情况isinstance(x,collections.Sequence)
是一个更好的方法choice@Imram:在递归求和的情况下,嵌套序列中的任何位置都不应出现字符串,但最好有一个包含生成器的列表,如[重复(3,10),重复(1,5)]
。这就是为什么我更愿意在这里测试Iterable
。Sven-任何Iterable示例都没有\uuuuuuuuuuuuuuuu
?如果需要的话,我可以为这个问题单独发帖。@布赖恩:这之前已经讨论过了。不幸的是,我现在记得的唯一一个例子是字符串,不知何故,我在这篇文章中的第一条评论就没有了意义……在静态类型语言中,您可以使用具有不同类型签名的函数重载函数。字符串是序列。如果你不想这样对待他们,你必须为他们破例。
>>> import collections
>>> hasattr(element, '__getitem__')
True
>>> not hasattr(element, 'keys')
True
>>> isinstance(element, collections.Sequence)
True
>>> hasattr(element, '__iter__')
True
>>> string = '1234'
>>> hasattr(string, '__getitem__')
True
>>> not hasattr(string, 'keys')
True
>>> isinstance(string, collections.Sequence)
True
>>> hasattr(string, '__iter__')
False