2011-03-13 136 views
1

我知道,当我比较两个物体lhs == rhs两者定义__eq__,只是lhs.__eq__被称为除非它返回NotImplementedrhslhs一个子类。欺骗Python的运算符优先级

但是我想实现一个类,在与任意对象进行比较时,它们的实例将有机会说出他们想说的内容,而不管arbitrary_object.__eq__的实现细节以及比较语句中的位置如何。听起来有些尴尬,但我正在开发一个面向测试的项目,看看testmania.expect,你就会明白我需要的是什么。

我最初的想法是让我的课是使用元类魔法和__instancecheck____subclasscheck__任何其他类的子类。但他们根本不会在简单比较的情况下被调用。

有人有什么新鲜的想法吗?

回答

1

我不知道这是否适合您的需要,但为什么不测试这两个操作,我的意思是测试如果:object1 == object2object2 == object1,通常你应该最终得到相同的值,除非其中一个对象被覆盖该__eq__方法,因此将执行这一新__eq__方法,并返回一个是真的,一个例子是胜于言:

def _assert_just_now(first, second): 
    """A Dump function to simulate if two dates are almost equal. 

    N.B: In this Dump function i will just test if the two datetime object have the 
    same hour 

    """ 

    from datetime import datetime 
    assert isinstance(first, datetime) and isinstance(second, datetime), \ 
      "This function only accept datetime objects" 

    return first.hour == second.hour 

class Expectation(object): 

    def __init__(self, assertion, first): 
     self.assertion = assertion 
     self.first = first 

    def __eq__(self, other): 
     return self.assertion(self.first, other) 

def assert_equal(first, second): 
    """Usage : 

    >>> from datetime import datetime 
    >>> t1 = datetime(year=2007, hour=1, month=3, day=12) 
    >>> t2 = datetime(year=2011, hour=1, month=5, day=12) 

    Without using Expectation it's False. 
    >>> assert_equal(t1, t2) 
    False 

    Use the Expectation object. 
    >>> assert_equal(t1, Expectation(_assert_just_now, t2)) 
    True 

    Can use Expectation in the first argument too. 
    >>> assert_equal(Expectation(_assert_just_now, t2), t1) 
    True 

    Work also in Container object. 
    >>> assert_equal({'a': 1, 'b': Expectation(_assert_just_now, t2)}, 
    ...    {'a': 1, 'b': t1}) 
    True 

    We change a little bit the values to make the assert equal fail. 
    >>> t3 = datetime(year=2011, hour=2, month=5, day=12) 
    >>> assert_equal(t1, t3) 
    False 

    This just to make sure that the _assert_just_now doesn't accept object 
    other than datetime: 
    >>> assert_equal(t1, Expectation(_assert_just_now, "str")) 
    Traceback (most recent call last): 
     ... 
    AssertionError: This function only accept datetime objects 

    """ 

    return first == second or second == first 

if __name__ == '__main__': 
    import doctest 
    doctest.testmod() 

希望这可以帮助。

+0

感谢您的回答。那么,始终保持期望值是一个解决方案,但它打破了习惯:许多人习惯于写'some_assert(what_i_have,what_i_want_to_have)'。改变这只是为了期望逆转不是好主意imho。 – nkrkv 2011-03-13 21:45:33

+0

@nailxx:也许我在答案中不够清楚:)你可以在doctest中看到,你可以在函数assert_equal的第一个或第二个参数中传递期望对象,它会起作用,因为我'先执行==第二或第二个第一个',那么你将首先执行'first .__ eq __(second)',如果它不是True,你将执行'second .__ eq __(first)',如果对象的第一个或第二个是'__eq__'记者将运行的期望:) – mouad 2011-03-13 22:34:22

+0

嗯,好吧,你要重新实现'assert_equal'本身。 Uff,替换标准的'TestCase.assertEqual'有点奇怪。但也许这是正确的方向。 – nkrkv 2011-03-14 09:29:24