2011-10-12 39 views
6

我的一个测试单元检查一个范围是否在读取日志文件后正确设置,我想测试var == range(0,10)。但是,range(0,1) == range(0,1)在Python 3中的计算结果为False如何测试等效范围

是否有直接的方法来测试Python 3中的范围等价性?

+2

你为什么要比较两个范围? –

+0

我的单元测试只是断言范围是正确构造的。在该程序中,不是存储最小和最大可接受值,而是存储范围,然后测试val是否在范围内。 – oneporter

回答

10

在Python3,range返回range类型的迭代。两个range s为等于当且仅当它们是相同的(即分享相同的id。)为了测试其内容平等,转换rangelist

list(range(0,1)) == list(range(0,1)) 

此工作正常的短范围。对于很长的范围,Charles G Waldman's solution更好。

+0

@oneporter:被警告,这消耗了迭代器,你将无法在稍后重新调用它。 –

+2

@StevenRumbalski:由于'range'对象是可迭代的,而不是迭代器,所以它们不能被“消耗”。 [你可以迭代它们多次。](http://ideone.com/RGvxv) –

+2

@Sven Marnach。优秀。感谢您的更正。 –

1

尝试assertItemsEqual,(在docs):

class MyTestCase(unittest.TestCase): 
    def test_mytest(self): 
     a = (0,1,2,3,4) 
     self.assertItemsEqual(a, range(0,4)) 
+0

请注意,assertItemsEqual在py3中不可用,这是OP所要求的。 – jmagnusson

6

第一个建议的解决方案 - 使用“list”将范围转换为列表 - 是无效的,因为它会首先将范围对象转换为列表(如果范围很大,可能消耗大量内存),然后比较每个元素。考虑例如a =范围(1000000), “范围”对象本身很小,但如果将它强制为一个列表,它将变得非常庞大。那么你必须比较一百万个元素。

答案(2)效率更低,因为assertItemsEqual不仅要实例化列表,还要在进行元素比较之前对它们进行排序。

相反,由于您知道对象是范围,因此当它们的步幅,起始值和结束值相等时,它们是相等的。例如。

ranges_equal = len(a)==len(b) and (len(a)==0 or a[0]==b[0] and a[-1]==b[-1])

+3

如果范围步骤不起作用。例如范围(1,20,2)和范围(1,20)将是等效的。 – krs1

+0

好点krs1。我认为我的方法可以通过比较范围的len()来解决....或者,如果避免空范围的问题:'ranges_equal =(len(a)== len(b)和a [0] == b [0]和a [-1] == b [-1]) –

+0

= len(b)和a [0] == b [0]和a [-1] == b [-1] –

1

另一种方式来做到这一点:

ranges_equal = str(a)==str(b)

字符串表示指示开始,结束和范围的步骤。

这个问题让我觉得,也许Python应该提供一种方法来从范围对象本身获取这些属性!