def replace_tup(tupl, old, new, count=-1):
    """
    Creates a copy of ``tupl`` with all occurrences of value ``old`` replaced by ``new``. 
    
    Objects are replaced by value equality, not id equality (i.e. ``==`` not ``is``).
    If the optional argument ``count`` is given, only the first count occurrences are 
    replaced.
     
    :param tupl: The tuple to copy
    :type tupl:  ``tuple``
    
    :param old: The old value to replace
    :type old:  ``any``
    
    :param new: The new value to replace with
    :type new:  ``any``
    
    :param count: The number of occurrences to replace
    :type count:  ``int``
    
    :return: A copy of ``tupl`` with all occurrences of value ``old`` replaced by ``new``. 
    :rtype:  ``tuple``
    """
    assert type(tupl) == tuple, '%s is not a tuple' % tupl
    result = []
    count = len(tupl) if count == -1 else count
    match = 0
    for item in tupl:
        if item == old and match < count:
            result.append(new)
            match += 1
        else:
            result.append(item)
    return tuple(result)
