2017-02-16 97 views
1

现在我有上面的源代码:哪种更简洁的方式来获取Python @property作为具有特定条件的列表?

class Stats(object): 

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

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

这些列表中填充的方式是不是我的问题很重要。

的情况是,我得到这些名单的子表是这样的:

stats = Stats() 
// code to fill the lists 
stats.pending[2:10] 

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

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

所以,我需要的是:

  • 当列表中有足够的项目,则返回相应的子集。
  • 当列表较短时,它会返回一个具有预期长度的子列表,其中包含原始列表的最后一个元素和一个默认值(例如None)。

这样一来,如果我这样做:

pending_tasks = stats.pending[44:46] 

而未决列表仅包含30个元素,它应该返回两个默认元素的列表,例如:无,无]而不是空列表([]),这是列表的默认行为。

我想我已经知道如何在普通的方法/函数内部完成它,但我想以最干净的方式来完成,如果可能的话,试图遵循@property方法。

非常感谢!

+0

你知道吗? (我的意思是如何用普通的方法做到这一点?)如何?你怎么能使属性解析机制感觉到,属性解析后会有切片操作?我只能想到使用代理对象,但这可能会变得混乱。我只是出于好奇而问。 –

回答

1

这并不容易,因为切片操作是你想要修改的,而这种情况发生在property返回的原始列表之后。然而,这不是不可能的,你只需要用另一个对象来包装常规列表,这样就可以为你填充切片了。这将是多么容易或困难可能取决于你需要包装器实现多少的列表界面。如果您只需要索引和切片,它真的很容易:

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 

此代码可能不会正确的负步进切片工作,或没有指定端点的一个切片(它确实有逻辑检测省略步骤,因为这很常见)。如果这对你很重要,你可以修复这些角落案例。

0

这并不容易。你将返回的对象(列表)如何知道它将在稍后被切片?你可以继承list,但是,并覆盖(仅Python2)__getitem____getslice__

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版本的实际名单:

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

你可以构造一个新的类,它是list一个子类。然后,您可以重载__getitem__魔术方法,以将[]运算符重载为适当的行为。考虑这一小类的list称为MyList

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方法,而不是返回MyListlist

class Stats(object): 
    @property 
    def pending(self): 
     return MyList(self._pending) 

希望这会有所帮助。

相关问题