如何创建一个像 class 这样的列表,它允许在切片上调用包含的对象方法,这些方法同时适用于 py2 和 py3
How to create a List like class which allows calling contained objects methods on slices which work with both py2 and py3
以下代码来自SCons的代码库。我们正在努力移植代码,使其适用于 Python 2.7.x 和 3.x.
下面的代码在 python 2.7.x 下工作正常,但是当 运行 在 python 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)
你用 slice
调用的 __getitem__
可能应该再次 return 相同 class 的新实例。例如:
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
以下代码来自SCons的代码库。我们正在努力移植代码,使其适用于 Python 2.7.x 和 3.x.
下面的代码在 python 2.7.x 下工作正常,但是当 运行 在 python 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)
你用 slice
调用的 __getitem__
可能应该再次 return 相同 class 的新实例。例如:
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