8

Is there any difference between using the reversed union or intersection operators on sets in Python?

for instance,

s & z corresponds to s.__and__(z)

z & s corresponds to s.__rand__(z)

If these are supposed to return the same thing, why have the reversed operator in the first place? Am I missing something?

MadPhysicist
  • 5,401
  • 11
  • 42
  • 107

2 Answers2

3

set and frozenset follow the number protocol and they don't define the reversed operations explicitly but they get these "for free" because they implement the normal methods (like __and__).

However reversed operations are particularly useful when dealing with subclasses because if the right operand is a subclass of the left operand the reversed operation is attempted first. But in case of plain sets and frozensets this doesn't make any difference because they don't inherit from each other.

These reversed operations are also used if the first operand returns NotImplemented in it's __add__. But again this isn't really useful for set and frozenset because they only allow operations with other set-alikes and at least set and frozenset don't return NotImplemented when the other operand is another set.

Also z & s doesn't correspond to s.__rand__(z), except when s is a subclass of z. Otherwise z.__and__(s) will be attempted before s.__rand__(z).

So I doubt there are use-cases for the reversed union and intersection but it should explain "why these methods exist".

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • Are you saying that if I make custom classes that inherit from `set` or `frozenset`, and these classes have different `__and__` methods, then one needs to watch for the order and what the `__rand__` methods contain as well? – MadPhysicist Apr 04 '17 at 12:43
  • 1
    Indeed with `set` and `frozenset` you need to be careful about the order when you subclass one and try to operate with the other. If you subclass `set` and implement `__and__` and `__rand__` your subclasses methods will be called first when you try to do `set() & subclass()` (=> `subclass.__rand__` is called first) or `subclass() & set()` (=> `subclass.__and__` is called first). But if you try to use this subclass with `frozenset` you need to watch out for the order: `frozenset() & subclass()` will call `frozenset.__and__` first! – MSeifert Apr 04 '17 at 13:19
0

__rand__ is only called if if the left operand does not support the corresponding operation and the operands are of different types.

I would imagine that s.__rand__(z) would just call z.__and__(s) under the covers.

Alex
  • 1,432
  • 14
  • 26
  • Since the operation is invalid except between two sets, the other argument is guaranteed to have the correct method or else there's an error and the rand method doesn't need to be the one that produces it. – zondo Apr 04 '17 at 02:41