PEP-3141 outlines an approach to writing binary operators to allow the
right operand to override the operation if the left operand inherits
the operation from the ABC.

Here is my first approximation at how to write them for the Integral mixins:

class Integral(Rational):

   def __and__(self, other):
       if isinstance(other, (type(self), int, long)):         # XXX
           return int(self) & int(other)
       return NotImplemented

   def __rand__(self, other):
       if isinstance(other, Integral):
           return int(other) & int(self)
       return NotImplemented

The question for the group is what to put on the XXX line.

1. Limit it to type(self).  This approach claims the least knowledge about 
other types and uses their __rand__ methods().

2. Use type(self), int, and long. This approach says that we know that ints and longs can be reasonably converted to an int; however, it means that any int/long subtype cannot use __rand__ to override the mixin's __and__.

3. Emulate the PEP as closely as possible and accomodate subclassing without 
changing behaviors.  This approach is a bit complex:

       knowntypes = (set(type(self).__mro__)
                              & set(type(other.__mro__))
                              - set(type(Integral.__mro__))
                              | set([int, long]))
       if isinstance(other, tuple(knowntypes)):

I got this by analyzing the possible paths in an inheritance tree:

  class P(Integral): pass
  class Q(P): pass
  class R(Q): pass
  r = R(3)
  class S(Q): def __rand__(s,o) ...
  s = S(6)
  class T(Integral): def __rand__(s,o) ...
  t = T(5)

With r&t, there is no common ancestor below Integral, so we want
Integral.__and__() to return NotImplemented and allow T.__rand__()
to do its thing.

With r&s, both r and s share Q as a common ancenstor.
By using the mixin and not overriding __and__(), Q specifies that __and__()
should mean int(r)&int(s) whenever isinstance(r,Q) and isinstance(s,Q).

Approaches 1 & 2 don't search the mro for shared ancestors below
the level of Integral.  So, when evaluating r&s, Integral.__and__()
only checks that r is not an instance of S, int or long, and it
erroneously returns NotImplemented , leaving s.__rand__() to take over.

What do you guys think?


Raymond
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to