class_docstr: This class implements rational numbers.
  
  In the two-argument form of the constructor, Fraction(8, 6) will
  produce a rational number equivalent to 4/3. Both arguments must
  be Rational. The numerator defaults to 0 and the denominator
  defaults to 1 so that Fraction(3) == 3 and Fraction() == 0.
  
  Fractions can also be constructed from:
  
    - numeric strings similar to those accepted by the
      float constructor (for example, '-2.3' or '1e10')
  
    - strings of the form '123/456'
  
    - float and Decimal instances
  
    - other Rational instances (including integers)
class_docstr_tok: ["This","class","implements","rational","numbers",".","In","the","two-argument","form","of","the","constructor",",","Fraction","(","8",",","6",")","will","produce","a","rational","number","equivalent","to","4\/3",".","Both","arguments","must","be","Rational",".","The","numerator","defaults","to","0","and","the","denominator","defaults","to","1","so","that","Fraction","(","3",")","==","3","and","Fraction","(",")","==","0",".","Fractions","can","also","be","constructed","from",":","-","numeric","strings","similar","to","those","accepted","by","the","float","constructor","(","for","example",",","'-2.3","'","or","'1e10","'",")","-","strings","of","the","form","'123\/456'","-","float","and","Decimal","instances","-","other","Rational","instances","(","including","integers",")"]
docstr: Generates forward and reverse operators given a purely-rational
  operator and a function from the operator module.
  
  Use this like:
  __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
  
  In general, we want to implement the arithmetic operations so
  that mixed-mode operations either call an implementation whose
  author knew about the types of both arguments, or convert both
  to the nearest built in type and do the operation there. In
  Fraction, that means that we define __add__ and __radd__ as:
  
      def __add__(self, other):
          # Both types have numerators/denominator attributes,
          # so do the operation directly
          if isinstance(other, (int, Fraction)):
              return Fraction(self.numerator * other.denominator +
                              other.numerator * self.denominator,
                              self.denominator * other.denominator)
          # float and complex don't have those operations, but we
          # know about those types, so special case them.
          elif isinstance(other, float):
              return float(self) + other
          elif isinstance(other, complex):
              return complex(self) + other
          # Let the other type take over.
          return NotImplemented
  
      def __radd__(self, other):
          # radd handles more types than add because there's
          # nothing left to fall back to.
          if isinstance(other, numbers.Rational):
              return Fraction(self.numerator * other.denominator +
                              other.numerator * self.denominator,
                              self.denominator * other.denominator)
          elif isinstance(other, Real):
              return float(other) + float(self)
          elif isinstance(other, Complex):
              return complex(other) + complex(self)
          return NotImplemented
  
  
  There are 5 different cases for a mixed-type addition on
  Fraction. I'll refer to all of the above code that doesn't
  refer to Fraction, float, or complex as "boilerplate". 'r'
  will be an instance of Fraction, which is a subtype of
  Rational (r : Fraction <: Rational), and b : B <:
  Complex. The first three involve 'r + b':
  
      1. If B <: Fraction, int, float, or complex, we handle
         that specially, and all is well.
      2. If Fraction falls back to the boilerplate code, and it
         were to return a value from __add__, we'd miss the
         possibility that B defines a more intelligent __radd__,
         so the boilerplate should return NotImplemented from
         __add__. In particular, we don't handle Rational
         here, even though we could get an exact answer, in case
         the other type wants to do something special.
      3. If B <: Fraction, Python tries B.__radd__ before
         Fraction.__add__. This is ok, because it was
         implemented with knowledge of Fraction, so it can
         handle those instances before delegating to Real or
         Complex.
  
  The next two situations describe 'b + r'. We assume that b
  didn't know about Fraction in its implementation, and that it
  uses similar boilerplate code:
  
      4. If B <: Rational, then __radd_ converts both to the
         builtin rational type (hey look, that's us) and
         proceeds.
      5. Otherwise, __radd__ tries to find the nearest common
         base ABC, and fall back to its builtin type. Since this
         class doesn't subclass a concrete type, there's no
         implementation to fall back to, so we need to try as
         hard as possible to return an actual value, or the user
         will get a TypeError.
code: def _operator_fallbacks(monomorphic_operator, fallback_operator):
      """Generates forward and reverse operators given a purely-rational
      operator and a function from the operator module.
  
      Use this like:
      __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
  
      In general, we want to implement the arithmetic operations so
      that mixed-mode operations either call an implementation whose
      author knew about the types of both arguments, or convert both
      to the nearest built in type and do the operation there. In
      Fraction, that means that we define __add__ and __radd__ as:
  
          def __add__(self, other):
              # Both types have numerators/denominator attributes,
              # so do the operation directly
              if isinstance(other, (int, Fraction)):
                  return Fraction(self.numerator * other.denominator +
                                  other.numerator * self.denominator,
                                  self.denominator * other.denominator)
              # float and complex don't have those operations, but we
              # know about those types, so special case them.
              elif isinstance(other, float):
                  return float(self) + other
              elif isinstance(other, complex):
                  return complex(self) + other
              # Let the other type take over.
              return NotImplemented
  
          def __radd__(self, other):
              # radd handles more types than add because there's
              # nothing left to fall back to.
              if isinstance(other, numbers.Rational):
                  return Fraction(self.numerator * other.denominator +
                                  other.numerator * self.denominator,
                                  self.denominator * other.denominator)
              elif isinstance(other, Real):
                  return float(other) + float(self)
              elif isinstance(other, Complex):
                  return complex(other) + complex(self)
              return NotImplemented
  
  
      There are 5 different cases for a mixed-type addition on
      Fraction. I'll refer to all of the above code that doesn't
      refer to Fraction, float, or complex as "boilerplate". 'r'
      will be an instance of Fraction, which is a subtype of
      Rational (r : Fraction <: Rational), and b : B <:
      Complex. The first three involve 'r + b':
  
          1. If B <: Fraction, int, float, or complex, we handle
             that specially, and all is well.
          2. If Fraction falls back to the boilerplate code, and it
             were to return a value from __add__, we'd miss the
             possibility that B defines a more intelligent __radd__,
             so the boilerplate should return NotImplemented from
             __add__. In particular, we don't handle Rational
             here, even though we could get an exact answer, in case
             the other type wants to do something special.
          3. If B <: Fraction, Python tries B.__radd__ before
             Fraction.__add__. This is ok, because it was
             implemented with knowledge of Fraction, so it can
             handle those instances before delegating to Real or
             Complex.
  
      The next two situations describe 'b + r'. We assume that b
      didn't know about Fraction in its implementation, and that it
      uses similar boilerplate code:
  
          4. If B <: Rational, then __radd_ converts both to the
             builtin rational type (hey look, that's us) and
             proceeds.
          5. Otherwise, __radd__ tries to find the nearest common
             base ABC, and fall back to its builtin type. Since this
             class doesn't subclass a concrete type, there's no
             implementation to fall back to, so we need to try as
             hard as possible to return an actual value, or the user
             will get a TypeError.
  
      """
  
      def forward(a, b):
          if isinstance(b, Fraction):
              return monomorphic_operator(a, b)
          elif isinstance(b, int):
              return monomorphic_operator(a, Fraction(b))
          elif isinstance(b, float):
              return fallback_operator(float(a), b)
          elif isinstance(b, complex):
              return fallback_operator(complex(a), b)
          else:
              return NotImplemented
  
      forward.__name__ = "__" + fallback_operator.__name__ + "__"
      forward.__doc__ = monomorphic_operator.__doc__
  
      def reverse(b, a):
          if isinstance(a, numbers.Rational):
              # Includes ints.
              return monomorphic_operator(Fraction(a), b)
          elif isinstance(a, numbers.Real):
              return fallback_operator(float(a), float(b))
          elif isinstance(a, numbers.Complex):
              return fallback_operator(complex(a), complex(b))
          else:
              return NotImplemented
  
      reverse.__name__ = "__r" + fallback_operator.__name__ + "__"
      reverse.__doc__ = monomorphic_operator.__doc__
  
      return forward, reverse
  
imports: from decimal import Decimal
  import functools
  import math
  import numbers
  import operator
  import re
  import sys
label_desc: Use image node_id 15 for calling the Fraction obj's underlying member method code with example usage: obj._operator_fallbacks(monomorphic_operator, fallback_operator) and returns: forward,  reverse, monomorphic_operator, monomorphic_operator, monomorphic_operator, fallback_operator, fallback_operator, fallback_operator, NotImplemented, fallback_operator, NotImplemented