首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将Python @属性作为具有特定条件的列表的更简洁的方法是什么?

将Python @属性作为具有特定条件的列表的更简洁的方法是什么?
EN

Stack Overflow用户
提问于 2017-02-16 17:49:29
回答 3查看 260关注 0票数 1

现在我有了上面的源代码:

代码语言:javascript
运行
复制
class Stats(object):

    def __init__(self):
        self._pending = []
        self._done = []

    @property
    def pending(self):
        return self._pending

这些清单的填写方式对我的问题并不重要。

情况是这样,我得到了这些列表的子列表:

代码语言:javascript
运行
复制
stats = Stats()
// code to fill the lists
stats.pending[2:10]

这里的问题是,我希望得到的元素和我检索的一样多。在上面的例子中,我期望一个包含8个元素(10-2)的子列表。

当然,如果列表较短,实际上我将得到少于8个元素。

所以,我需要的是:

  • 当列表有足够的项时,它将返回相应的子列表。
  • 当列表较短时,它返回一个具有预期长度的子列表,其中填充了原始列表的最后一个元素和额外项的默认值(例如,无)。

这样,如果我这么做的话:

代码语言:javascript
运行
复制
pending_tasks = stats.pending[44:46]

挂起的列表只包含30个元素,它应该返回一个包含两个默认元素的列表,例如: None,None;而不是一个空list ([]),它是列表的默认行为。

我想我已经知道如何在一个正常的方法/函数中完成它了,但是我想以最干净的方式来完成它,如果可能的话,尝试遵循@property方法。

非常感谢!

EN

回答 3

Stack Overflow用户

发布于 2017-02-16 18:17:40

这不是一件容易的事情,因为切片操作是您想要修改的,这是在property返回原始列表之后发生的。不过,这并不是不可能的,您只需要用另一个对象包装常规列表,该对象负责为您填充切片。这将有多容易或有多难,这可能取决于您需要包装器实现的列表接口的多少。如果您只需要索引和切片,那么非常简单:

代码语言:javascript
运行
复制
class PadSlice(object):
    def __init__(self, lst, default_value=None):
        self.lst = lst
        self.default_value

    def __getitem__(self, index):
        item = getitem(self.lst, index)
        if isinstance(index, slice):
            expected_length = (index.stop - index.start) // (index.step or 1)
            if len(item) != expected_length:
                item.extend([default_value] * (expected_length - len(item)))
        return item

对于负步骤切片,或者不指定一个端点的片,这段代码可能无法正常工作(它有检测省略步骤的逻辑,因为这很常见)。如果这对你来说很重要的话,你也许可以把这些角落的箱子修好。

票数 1
EN

Stack Overflow用户

发布于 2017-02-16 18:17:51

这可不容易。您返回的对象(列表)如何知道它以后将如何被切片?但是,您可以子类list,并重写__getitem____getslice__ (仅限Python2):

代码语言:javascript
运行
复制
class L(list):
    def __getitem__(self, key):
        if isinstance(key, slice):
            return [list(self)[i] if 0 <= i < len(self) else None for i in xrange(key.start, key.stop, key.step or 1)]
        return list(self)[key]
    def __getslice__(self, i, j):
        return self.__getitem__(slice(i, j))

这将衬垫所有的切片与None,完全兼容负索引和步骤!= 1。在您的属性中,返回实际列表的L版本:

代码语言:javascript
运行
复制
@property
def pending(self):
    return L(self._pending)
票数 0
EN

Stack Overflow用户

发布于 2017-02-16 18:44:01

您可以构造一个新类,它是list的一个子类。然后,您可以将__getitem__魔术方法重载到将[]操作符重载到适当的行为。假设list的这个子类称为MyList

代码语言:javascript
运行
复制
class MyList(list):
    def __getitem__(self, index):
        """Modify index [] operator"""

        result = super(MyList, self).__getitem__(index)

        if isinstance(index, slice):
            # Get sublist length.
            if index.step: # Check for zero to avoid divide by zero error
                sublist_len = (index.stop - index.start) // index.step
            else:
                sublist_len = (index.stop - index.start)

            # If sublist length is greater (or list is shorter), then extend
            # the list to length requested with default value of None
            if sublist_len > len(self) or index.start > len(self):
                result.extend([None for _ in range(sublist_len - len(result))])

        return result

然后,只需更改pending方法以返回MyList类型,而不是list

代码语言:javascript
运行
复制
class Stats(object):
    @property
    def pending(self):
        return MyList(self._pending)

希望这能帮上忙。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42281234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档