2017-02-27 6 views
0

아래 코드는 SCons의 코드베이스에서 가져온 것입니다. 파이썬 2.7.x와 3.x 모두에서 작동하도록 코드 포팅 작업을하고 있습니다.py2와 py3 모두에서 작동하는 슬라이스에 포함 된 객체 메소드를 호출 할 수있는 클래스와 같은 List를 만드는 방법

아래의 코드는 파이썬 2.7.x에서 잘 작동하지만 파이썬에서 실행할 때 다음과 같이 3.5 실패

python3.5 ~/tmp/blah123.py Traceback (most recent call last):
File "/home/bdbaddog/tmp/blah123.py", line 73, in print("stuff:%s"%nl[0:2].bar) AttributeError: 'list' object has no attribute 'bar'

이 코드는 다소 SCons는의 ​​기능에 핵심입니다. 어떤 도움이 가장 환영받을 것입니다. (여기에 원래 코드를 참조하십시오 src/engine/SCons/Util.py를)

from __future__ import print_function 


try: 
    from UserList import UserList 
except ImportError as e: 
    from collections import UserList 


class NodeList(UserList): 
    """This class is almost exactly like a regular list of Nodes 
    (actually it can hold any object), with one important difference. 
    If you try to get an attribute from this list, it will return that 
    attribute from every item in the list. For example: 

    >>> someList = NodeList([ ' foo ', ' bar ' ]) 
    >>> someList.strip() 
    [ 'foo', 'bar' ] 
    """ 
    def __nonzero__(self): 
     return len(self.data) != 0 

    def __bool__(self): 
     return self.__nonzero__() 

    def __str__(self): 
     return ' '.join(map(str, self.data)) 

    def __iter__(self): 
     return iter(self.data) 

    def __call__(self, *args, **kwargs): 
     result = [x(*args, **kwargs) for x in self.data] 
     return self.__class__(result) 

    def __getattr__(self, name): 
     result = [getattr(x, name) for x in self.data] 
     return self.__class__(result) 

# def __getitem__(self, index): 
#  return self.__class__(self.data[index]) 
#  return self.data[index] 

    def __getitem__(self, index): 
     """ 
     This comes for free on py2, 
     but py3 slices of NodeList are returning a list 
     breaking slicing nodelist and refering to 
     properties and methods on contained object 
     """ 
#  return self.__class__(self.data[index]) 

     if isinstance(index, slice): 
      # Expand the slice object using range() 
      # to a maximum of eight items. 
      return [self[x] for x in 
        range(*index.indices(8))] 
     else: 
      # Return one item of the tart 
      return self.data[index] 


class TestClass(object): 
    def __init__(self, name, child=None): 
     self.child = child 
     self.bar = name 

t1 = TestClass('t1', TestClass('t1child')) 
t2 = TestClass('t2', TestClass('t2child')) 
t3 = TestClass('t3') 

nl = NodeList([t1, t2, t3]) 
print("stuff:%s"%nl[0:2].bar) 
print("another:%s"%nl[1:].bar) 


assert nl.bar == [ 't1', 't2', 't3' ], nl.bar 
assert nl[0:2].child.bar == [ 't1child', 't2child' ], \ 
     nl[0:2].child.bar 

for f in nl: 
    print("->%s"%f.bar) 

답변

3

귀하의 __getitem__ 아마 다시 같은 클래스의 새로운 인스턴스를 반환해야 slice로했다.

다음
def __getitem__(self, index): 
    if isinstance(index, slice): 
     return self.__class__(self[x] for x in 
           range(*index.indices(len(self.data))) 
    else: 
     return self.data[index] 

테스트 케이스 인쇄 : 예를 들어

stuff:t1 t2 
->t1 
->t2 
->t3 
+0

감사합니다! 전체 테스트 스위트에서 거의 모든 테스트를 수행했습니다. 하나의 단위 테스트가 여전히 실패했습니다. 추적하고 단순화한다면 위의 샘플 코드에 추가 할 것입니다. – bdbaddog

+0

"another"를 참조하여 업데이트 된 테스트를 추가했습니다. 수정은 실제로 위의 index.indices (8)에서 최대 8 개를 제거하는 것입니다. 그리고 index.indices (len (self.data))로 대체하십시오. 위에서 편집하면 답변으로 표시됩니다. – bdbaddog

+0

@bdbaddog 좋습니다! 나는 그것이 기쁘다 :) – MSeifert