鸭子打字麻烦。 “i-am-like-a-list”的鸭子打字测试

时间:2015-05-20 00:01:34

标签: python list

最后添加的使用上下文

我经常想要操作像列表这样的抽象对象。 e.g。

def list_ish(thing):
    for i in xrange(0,len(thing)):
        print thing[i]

现在这是合适的,如果是一个列表,但如果事物是​​一个字典,那将会失败。什么是pythonic为什么要问“你表现得像一个列表?”

注:

hasattr('__getitem__') and not hasattr('keys')

这适用于我能想到的所有情况,但我不喜欢负面定义鸭子类型,因为我预计可能存在它无法捕获的情况。

我真正想要的是问    “嘿,你按照我希望列表的方式对整数指标进行操作吗?” e.g。

  thing[i],  thing[4:7] = [...],   etc.

注意:我不想简单地在大型try / except中执行我的操作,因为它们具有破坏性。在这里尝试失败并不酷......

使用上下文 - “点列表”是一个类似列表的东西,它包含类似字母的东西作为其元素。 - “矩阵”是类似列表的东西,包含类似列表的东西

- 我有一个函数库,可以在点列表上运行,也可以在类似矩阵的事物上运行。

- 例如,从用户的角度来看,像“电子表格式”操作“列切片”这样的破坏性操作可以同时对矩阵对象和点列表对象进行操作 - 结果事情就像原始的一样,但只有指定的列。

- 由于这个特殊的操作是破坏性的,所以进行就好像一个物体是一个矩阵,只是为了通过操作找到部分方式,它实际上是一个点列表或者没有 - 上方。

- 我希望我的'is_matrix'和'is_point_list'测试具有高效性,因为它们有时会出现在内部循环中。因此,我会对仅测试元素零的测试感到满意。

- 我更喜欢不涉及构造临时对象的测试,只是为了确定一个对象的类型,但也许这不是python方式。

总的来说,我发现整个鸭子打字的东西有点混乱,充满了虫子和缓慢,但也许我还没想到真正的Pythonista

很高兴喝更多的kool-aid ......

3 个答案:

答案 0 :(得分:3)

你可以做的一件事,就是应该在正常的list上快速工作而在正常dict上失败,就是从正面采取零长度切片:

try:
    thing[:0]
except TypeError:
    # probably not list-like
else:
    # probably list-like

切片在dict上失败,因为切片不可清除。

但是,strunicode也通过了此测试,并且您提到您正在进行破坏性编辑。这意味着您可能还想检查__delitem____setitem__

def supports_slices_and_editing(thing):
    if hasattr(thing, '__setitem__') and hasattr(thing, '__delitem__'):
        try:
            thing[:0]
            return True
        except TypeError:
            pass
    return False

我建议您根据问题中的要求,明确地为您的输入组织您的要求,以及您希望功能处理的可能输入范围。如果您真的只想处理listdict,那么您是否正在使用isinstance,对吗?也许您的方法所做的只能删除项目,或者只替换项目,因此您不需要检查其他功能。记录这些要求以供将来参考。

答案 1 :(得分:1)

处理内置类型时,您可以使用Abstract Base Classes。在您的情况下,您可能希望针对collections.Sequencecollections.MutableSequence进行测试:

if isinstance(your_thing, collections.Sequence):
    # access your_thing as a list

在2.6(包括)2.6之后的所有Python版本中都支持此功能。

如果您使用自己的类来构建your_thing,我建议您也从这些抽象基类继承(直接或间接)。这样,您可以确保正确实现序列接口,并避免所有打字混乱。

对于第三方库,如果第三方类没有从内置类型继承,则没有简单的方法来检查序列接口或抽象类。在这种情况下,您必须检查您将要使用的每个界面,并且您使用的界面。例如,您的list_ish函数使用了__len____getitem__,因此只检查这两种方法是否存在。 __getitem__(例如dict)的错误行为应该引发异常。

答案 2 :(得分:1)

也许他们在这里不是理想的pythonic答案,所以我提出了一个' hack'解决方案,但是不太了解python的类结构,知道我是否正确:

def is_list_like(thing):
    return hasattr(thing, '__setslice__')

def is_dict_like(thing):
    return hasattr(thing, 'keys')

我在这里的目标是简单地进行高性能测试:

  • (1)从不调用dict-thing,也不调用类似于字符串的列表项目
  • (2)返回python类型的正确答案
  • (3)如果有人实施" full" list / dict的核心方法集
  • (4)速度快(理想情况下在测试期间不分配对象)

编辑:来自@DanGetz

的想法