I\'d like to emulate overflow behavior of unsigned 4-bit integers, like this:
>>> x, y = Int4(10), Int4(9)
>>> x + y
Int4(3)
>>> x * y         
        No, subclassing int will not automatically re-use the type when applying arithmetic to it:
>>> class Int4(int):
...     def __new__(cls, i):
...         return super(Int4, cls).__new__(cls, i & 0xf)
... 
>>> x, y = Int4(10), Int4(9)
>>> x + y
19
>>> type(x + y)
<type 'int'>
You have to override the __add__, etc. methods to cast back to Int4() when you do this.
If you only ever want to support the type itself (e.g. not support converting other numeric types in the process), then you could can generate most of these:
from functools import wraps
class Int4(int):
    def __new__(cls, i):
        return super(Int4, cls).__new__(cls, i & 0xf)
def add_special_method(cls, name):
    mname = '__{}__'.format(name)
    @wraps(getattr(cls, mname))
    def convert_to_cls(self, other):
        bound_original = getattr(super(cls, self), mname)
        return type(self)(bound_original(other))
    setattr(cls, mname, convert_to_cls)
for m in ('add', 'sub', 'mul', 'floordiv', 'mod', 'pow',
          'lshift', 'rshift', 'and', 'xor', 'or'):
    add_special_method(Int4, m)
    add_special_method(Int4, 'r' + m)  # reverse operation
This produces methods that always return the type of self from arithmetic special methods; this'll allow for further subclassing of Int4 as well.
Demo:
>>> from functools import wraps
>>> class Int4(int):
...     def __new__(cls, i):
...         return super(Int4, cls).__new__(cls, i & 0xf)
... 
>>> def add_special_method(cls, name):
...     mname = '__{}__'.format(name)
...     @wraps(getattr(cls, mname))
...     def convert_to_cls(self, other):
...         bound_original = getattr(super(cls, self), mname)
...         return type(self)(bound_original(other))
...     setattr(cls, mname, convert_to_cls)
... 
>>> for m in ('add', 'sub', 'mul', 'floordiv', 'mod', 'pow',
...           'lshift', 'rshift', 'and', 'xor', 'or'):
...     add_special_method(Int4, m)
...     add_special_method(Int4, 'r' + m)  # reverse operation
... 
>>> x, y = Int4(10), Int4(9)
>>> x + y
3
>>> x * y
10
This isn't as clever as @martijn-pieters' answer, but it does seem to work on python 2.7 and 3.*, whereas I get AttributeError: 'wrapper_descriptor' object has no attribute '__module__' on python 2.7 with that answer.
import sys
lt_py3 = sys.version_info < (3,)
lt_py33 = sys.version_info < (3, 3)
class Int(int):
    '''
    int types
    '''
    def __new__(self, val=0):
        return int.__new__(self, val & (1 << self.bits - 1) - 1)
    def __max_type_bits(self, other):
        '''
        determine the largest type and bits available from those in `self` and
        `other`
        '''
        if hasattr(other, 'bits'):
            if self.bits < other.bits:
                return type(other), other.bits
        return type(self), self.bits
    def __unary_typed(oper):
        '''
        return a function that redefines the operation `oper` such that the
        result conforms to the type of `self`
        '''
        def operate(self):
            return type(self)(oper(self))
        return operate
    def __typed(oper):
        '''
        return a function that redefines the operation `oper` such that the
        result conforms to the type of `self` or `other`, whichever is larger
        if both are strongly typed (have a `bits` attribute); otherwise return
        the result conforming to the type of `self`
        '''
        def operate(self, other):
            typ, bits = self.__max_type_bits(other)
            return typ(oper(self, other))
        return operate
    def __unary_ranged(oper):
        '''
        return a function that redefines the operator `oper` such that the
        result conforms to both the range and the type of `self`
        '''
        def operate(self, other):
            '''
            type and bitmask the result to `self`
            '''
            return type(self)(oper(self) & (1 << self.bits - 1) - 1)
        return operate
    def __ranged(oper):
        '''
        return a function that redefines the operator `oper` such that the
        result conforms to both the range and the type of `self` or `other`,
        whichever is larger if both are strongly typed (have a `bits`
        attribute); otherwise return the result conforming to the type of
        `self`
        '''
        def operate(self, other):
            '''
            type and bitmask the result to either `self` or `other` whichever
            is larger
            '''
            typ, bits = self.__max_type_bits(other)
            return typ(oper(self, other) & (1 << bits - 1) - 1)
        return operate
    # bitwise operations
    __lshift__  = __ranged(int.__lshift__)
    __rlshift__ = __ranged(int.__rlshift__)
    __rshift__  = __ranged(int.__rshift__)
    __rrshift__ = __ranged(int.__rrshift__)
    __and__     = __typed(int.__and__)
    __rand__    = __typed(int.__rand__)
    __or__      = __typed(int.__or__)
    __ror__     = __typed(int.__ror__)
    __xor__     = __typed(int.__xor__)
    __rxor__    = __typed(int.__rxor__)
    __invert__  = __unary_typed(int.__invert__)
    # arithmetic operations
    if not lt_py3:
        __ceil__  = __unary_typed(int.__ceil__)
        __floor__ = __unary_typed(int.__floor__)
        __int__   = __unary_typed(int.__int__)
    __abs__       = __unary_typed(int.__abs__)
    __pos__       = __unary_typed(int.__pos__)
    __neg__       = __unary_ranged(int.__neg__)
    __add__       = __ranged(int.__add__)
    __radd__      = __ranged(int.__radd__)
    __sub__       = __ranged(int.__sub__)
    __rsub__      = __ranged(int.__rsub__)
    __mod__       = __ranged(int.__mod__)
    __rmod__      = __ranged(int.__rmod__)
    __mul__       = __ranged(int.__mul__)
    __rmul__      = __ranged(int.__rmul__)
    if lt_py3:
        __div__   = __ranged(int.__div__)
        __rdiv__  = __ranged(int.__rdiv__)
    __floordiv__  = __ranged(int.__floordiv__)
    __rfloordiv__ = __ranged(int.__rfloordiv__)
    __pow__       = __ranged(int.__pow__)
    __rpow__      = __ranged(int.__rpow__)
class Int4(Int):
    bits = 4
x, y = Int4(10), Int4(9)
print(x + y)
print(x*y)
Running this code in a file called answer.py produces
$ python2.7 answer.py 
3
2
$ python3.4 answer.py 
3
2
Overriding the __add__ method is a good idea, because you can make your calculations look clearly. Int4(4) + Int4(7) looks better than Int4(4).addTo(Int4(7)) (or something like this).
Here is the code that could help you:
class Int4:
  def __init__(self, num): # initialising
    self.num = self.cap(num)
  def __str__(self):
    return str(self.num)
  def __repr__(self):
    return "Int4(" + self.__str__() + ")"
  def __add__(self, other): # addition
    return Int4(self.cap(self.num + other.num))
  def __sub__(self, other): # subtraction
    return Int4(self.cap(self.num - other.num))
  @staticmethod
  def cap(num): # a method that handles an overflow
    while num < 0:
      num += 16
    while num >= 16:
      num -= 16
    return num
And testing it:
>>> x,y,z = Int4(5), Int4(8), Int4(12)
>>> x
Int4(5)
>>> y
Int4(8)
>>> z
Int4(12)
>>> print x+y
13
>>> print z+y
4
>>> print x-z
9