0

下面的代码来自 SCons 的代码库。我们正在移植代码,以便它可以与 Python 2.7.x 和 3.x 一起使用。

下面的代码在 python 2.7.x 下运行良好,但是在 python 3.5 下运行失败如下:

python3.5 ~/tmp/blah123.py Traceback(最近一次调用最后):
文件“/home/bdbaddog/tmp/blah123.py”,第 73 行,在 print("stuff:%s"%nl[0:2 ].bar) AttributeError: 'list' 对象没有属性 '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)
4

1 回答 1

3

__getitem__调用的 aslice可能应该再次返回同一类的新实例。例如:

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
于 2017-02-27T18:35:24.363 回答