fractions data type -- when to reduce?
I would probably put it right in your __init__ method, which simplifies it every time a fraction is created (which includes after any operation).

I disagree with Jaime's answer that you should do the simplification as part of the operation, as you'll have to copy/paste that code for every new operation.

I’d write something like:



def gcd(x, y):
    while y:
        x, y = y, x % y
    return x

class Fraction(object):
    def __init__(self, numer, denom):
        cancel_factor = gcd(numer, denom)
        self.numer = numer / cancel_factor
        self.denom = denom / cancel_factor


A few other comments:


Per PEP 8 on class names, I'm using Fraction instead of frac.

Also from PEP 8, I would put spaces around your multiplication operators.
New style classes should inherit from object (as I've done above).
I think numer and denom are better attribute names than a and b.
The convention is to use other as the variable name in a method that takes two inputs, rather than x. For example:



def __add__(self, other):
    new_numer = self.numer * other.denom + self.denom * other.numer
    new_denom = self.denom * other.denom
    return Fraction(new_numer, new_denom)

I disagree with your use of __repr__. As a rule of thumb, __repr__ should be something you can eval() to get back to that object; __str__ is the human-readable object. See difference between __str__ and __repr__ for more.

Here's what I'd write:



def __repr__(self):
    return "Fraction(%s, %s)" % (self.numer, self.denom)

def __str__(self):
    return "%s / %s" % (self.numer, self.denom)