[Python-Dev] Advice on numbers.py implementation of binary mixins.

2008-06-14 Thread Jim Jewett
Raymond Hettinger wrote:

 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)

I think for this mixin, it doesn't matter whether other is an Integral
instance; it matter whether it is has a more specific solution.

So instead of checking whether isinstance, check whether its __rand__
method is Integral.__rand__.

I think you also may want to guard against incomplete right-hand
operations, by doing something like replacing the simple

 return NotImplemented

with

try:
val = other.__rand__(self)
if val is not NotImplemented:
return val
except (TypeError, AttributeError):
pass
# Use the generic fallback after all
return int(self)  int(other)
___
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


[Python-Dev] Advice on numbers.py implementation of binary mixins.

2008-06-13 Thread Raymond Hettinger

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 rt, there is no common ancestor below Integral, so we want
Integral.__and__() to return NotImplemented and allow T.__rand__()
to do its thing.

With rs, 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 rs, 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