【问题标题】:making list index possible for python class list使 python 类列表的列表索引成为可能
【发布时间】:2021-10-21 03:35:36
【问题描述】:

Python 在__getitem()____setitem()____delitem()__ 中没有列表索引参数的功能。由于我长期使用 R 语言,使用列表索引看起来很自然。我知道有pandasnumpy 但是更改类型很麻烦。并且需要导入额外的包!

>>> import numpy as np
>>> lst = [1,2,3,4,5]
>>> np.array(lst)[[0,3,4]]
array([1, 4, 5])

这是我的建议。

class list2(__builtins__.list):
    def __getitem__(self, x):
        if isinstance(x, __builtins__.list):
            #print(x)
            return [__builtins__.list.__getitem__(self, y) for y in x]
        else:
            return __builtins__.list.__getitem__(self,x)
    def __setitem__(self, index, elem):
        if isinstance(index, __builtins__.list):
            if isinstance(elem, __builtins__.list):
                for i,x in zip(index, elem):
                    __builtins__.list.__setitem__(self, i, x)
            else:
                for i in index:
                    __builtins__.list.__setitem__(self, i, elem)
                #self[i] = x
        else:
            __builtins__.list.__setitem__(self, index, elem)
    def __delitem__(self, index):
        if isinstance(index, __builtins__.list):
            for i in sorted(index, reverse = True):
                __builtins__.list.__delitem__(self, i)
                #self[i] = x
        else:
            __builtins__.list.__delitem__(self, index)

好像没问题。

>>> l = list2(['a', 'b', 'c', 'd', 'e'])
>>> l[[2,3]]
['c', 'd']
>>> l[[2,3]]= ['-', '-']
>>> l
['a', 'b', '-', '-', 'e']
>>> del l[[0,3]]
>>> l
['b', '-', 'e']

但是有什么陷阱吗?还是有什么需要改进的地方?

【问题讨论】:

    标签: python r list function methods


    【解决方案1】:

    这样的主要缺陷是它“令人惊讶”,这在 Python 中通常是不受欢迎的——我们希望默认列表的行为类似于默认列表。

    除此之外,您的实现在我看来大多是完整的。可能有几个问题:

    • 如果我们使用__setitem____delitem__ 并多次列出同一个索引会怎样?
    • 如果我们提供长度不匹配的 __setitem__ 列表会怎样?

    我认为有一个关键点值得改变:摆脱索引列表,改用元组。

    如果您将逗号分隔的索引列表传递给__getitem__,这些实际上会被解析为一个元组!

    >>> class Thing:
    ...     def __getitem__(self, indices):
    ...         print(indices)
    ...
    >>> t = Thing()
    >>> t[1, 2, 3]
    (1, 2, 3)
    

    因此,与其使用列表,不如期待元组并放弃双括号。

    在其他改进方面,最好摆脱对__builtins__的引用,并使用super()从默认列表实现中访问函数,添加自定义__repr__是个好主意所以我们不会将其与默认列表混为一谈。

    如果您添加所有这些建议,它会看起来像这样(为清楚起见添加了打字):

    from typing import Any, Tuple, Union
    
    class list2(list):
        def __getitem__(self, index: Union[int, Tuple[int], slice]) -> Any:
            if isinstance(index, (slice, int)):
                return super().__getitem__(index)
    
            return [super(list2, self).__getitem__(x) for x in index]
    
        def __setitem__(self, index: Union[int, Tuple[int], slice], elem: Any):
            if isinstance(index, (slice, int)):
                return super().__setitem__(index, elem)
    
            if len(index) != len(elem):
                raise ValueError("Number of elements in index does not match element.")
    
            for x, element in zip(index, elem):
                self[x] = element
    
        def __delitem__(self, index: Union[int, Tuple[int], slice]):
            if isinstance(index, (slice, int)):
                return super().__delitem__(index)
    
            for x in sorted(set(index), reverse=True):
                super().__delitem__(x)
    
        def __repr__(self) -> str:
            return f"list2({super().__repr__()})"
    
    

    【讨论】:

    • 注意:这仍然适用于例如l[[1, 2, 3]],只是不再需要:l[1, 2, 3] 将产生相同的结果。
    • 很好的答案!我选择__builtins__.list 的一个原因是我将list 的定义更改为def list(*args): if len(args) > 1: return [*args] else: __builtins__.list(args[0])。无论如何,无论用户对环境做了什么,似乎都无法引用本机 list__builtins__.list 可以很容易地分配给其他功能。
    猜你喜欢
    • 2015-04-25
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多