diff -r 2150c7d6426c Lib/operator.py --- a/Lib/operator.py Sat Aug 17 01:01:23 2013 +0300 +++ b/Lib/operator.py Sat Aug 17 22:20:28 2013 +0300 @@ -85,9 +85,30 @@ "Same as a // b." return a // b +_no_such_method = object() +def _get_special_method(obj, attr): + for t in type(obj).__mro__: + try: + descr = t.__dict__[attr] + except (AttributeError, KeyError): + continue + return descr.__get__(obj) + return _no_such_method + def index(a): "Same as a.__index__()." - return a.__index__() + if isinstance(a, int): + return a + index = _get_special_method(a, '__index__') + if index == _no_such_method: + msg = ("'%s' object cannot be interpreted as an integer" % + type(a).__name__) + raise TypeError(msg) + n = index() + if not isinstance(n, int): + msg = ('__index__ returned non-int (type %s)' % type(n).__name__) + raise TypeError(msg) + return n def inv(a): "Same as ~a." @@ -142,7 +163,7 @@ def concat(a, b): "Same as a + b, for a and b sequences." - if not hasattr(a, '__getitem__'): + if _get_special_method(a, '__getitem__') == _no_such_method: msg = "'%s' object can't be concatenated" % type(a).__name__ raise TypeError(msg) return a + b @@ -198,13 +219,12 @@ except TypeError: pass - try: - hint = type(obj).__length_hint__ - except AttributeError: + hint = _get_special_method(obj, '__length_hint__') + if hint == _no_such_method: return default try: - val = hint(obj) + val = hint() except TypeError: return default if val is NotImplemented: @@ -301,7 +321,7 @@ def iconcat(a, b): "Same as a += b, for a and b sequences." - if not hasattr(a, '__getitem__'): + if _get_special_method(a, '__getitem__') == _no_such_method: msg = "'%s' object can't be concatenated" % type(a).__name__ raise TypeError(msg) a += b diff -r 2150c7d6426c Lib/test/test_operator.py --- a/Lib/test/test_operator.py Sat Aug 17 01:01:23 2013 +0300 +++ b/Lib/test/test_operator.py Sat Aug 17 22:20:28 2013 +0300 @@ -170,6 +170,35 @@ self.assertRaises(TypeError, operator.getitem, a, None) self.assertTrue(operator.getitem(a, 2) == 2) + def test_index(self): + operator = self.module + self.assertRaises(TypeError, operator.index) + self.assertRaises(TypeError, operator.index, 1, 1) + self.assertEqual(operator.index(42), 42) + self.assertEqual(operator.index(True), 1) + self.assertRaises(TypeError, operator.index, '42') + self.assertRaises(TypeError, operator.index, 42.0) + class A: + def __index__(self): + return 42 + a = A() + a.__index__ = lambda: 1729 + self.assertEqual(operator.index(a), 42) + class F: + def __index__(self): + return 42.0 + self.assertRaises(TypeError, operator.index, F()) + class I(int): + def __index__(): + return 42 + i = I() + self.assertIs(operator.index(i), i) + class S: + @staticmethod + def __index__(): + return 42 + self.assertEqual(operator.index(S()), 42) + def test_indexOf(self): operator = self.module self.assertRaises(TypeError, operator.indexOf)