Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing builtin types in Python 2 and Python 3

Tags:

When subclassing builtin types, I noticed a rather important difference between Python 2 and Python 3 in the return type of the methods of the built-in types. The following code illustrates this for sets:

class MySet(set):      pass  s1 = MySet([1, 2, 3, 4, 5])  s2 = MySet([1, 2, 3, 6, 7])  print(type(s1.union(s2)))  print(type(s1.intersection(s2)))  print(type(s1.difference(s2))) 

With Python 2, all the return values are of type MySet. With Python 3, the return types are set. I could not find any documentation on what the result is supposed to be, nor any documentation about the change in Python 3.

Anyway, what I really care about is this: is there a simple way in Python 3 to get the behavior seen in Python 2, without redefining every single method of the built-in types?

like image 254
khinsen Avatar asked Nov 02 '11 15:11

khinsen


1 Answers

This isn't a general change for built-in types when moving from Python 2.x to 3.x -- list and int, for example, have the same behaviour in 2.x and 3.x. Only the set type was changed to bring it in line with the other types, as discussed in this bug tracker issue.

I'm afraid there is no really nice way to make it behave the old way. Here is some code I was able to come up with:

class MySet(set):     def copy(self):         return MySet(self)     def _make_binary_op(in_place_method):         def bin_op(self, other):             new = self.copy()             in_place_method(new, other)             return new         return bin_op     __rand__ = __and__ = _make_binary_op(set.__iand__)     intersection = _make_binary_op(set.intersection_update)     __ror__ = __or__ = _make_binary_op(set.__ior__)     union = _make_binary_op(set.update)     __sub__ = _make_binary_op(set.__isub__)     difference = _make_binary_op(set.difference_update)     __rxor__ = xor__ = _make_binary_op(set.__ixor__)     symmetric_difference = _make_binary_op(set.symmetric_difference_update)     del _make_binary_op     def __rsub__(self, other):         new = MySet(other)         new -= self         return new 

This will simply overwrite all methods with versions that return your own type. (There is a whole lot of methods!)

Maybe for your application, you can get away with overwriting copy() and stick to the in-place methods.

like image 130
Sven Marnach Avatar answered Sep 28 '22 08:09

Sven Marnach