In [7]:
ip = get_ipython()
from IPython.display import display
iopub = ip.kernel.iopub_socket
session = get_ipython().kernel.session


def display_with_id(obj, display_id, update=False):
    """Create a new display with an id"""
    data, md = ip.display_formatter.format(obj)
    transient = {'display_id': display_id}
    content = {
        'data': data,
        'metadata': md,
        'transient': transient,
    }
    msg_type = 'update_display_data' if update else 'display_data'
    session.send(iopub, msg_type, content, parent=ip.parent_header)

def update_display(obj, display_id):
    """Update existing displays with id"""
    return display_with_id(obj, display_id, update=True)
In [8]:
display_with_id('x', display_id='here')
'z'
In [9]:
display_with_id('y', display_id='here')
'z'
In [11]:
update_display('z', display_id='here')

An example ProgressBar using these messages:

In [16]:
import os
from binascii import hexlify

class ProgressBar(object):
    def __init__(self, capacity):
        self.progress = 0
        self.capacity = capacity
        self.width = 48
        self._display_id = hexlify(os.urandom(8)).decode('ascii')
        
    def __repr__(self):
        fraction = self.progress / self.capacity
        filled = '=' * int(fraction * self.width)
        rest = ' ' * (self.width - len(filled))
        return '[{}{}] {}/{}'.format(
            filled, rest,
            self.progress, self.capacity,
        )
    
    def display(self):
        display_with_id(self, display_id=self._display_id)
    
    def update(self):
        update_display(self, display_id=self._display_id)

bar = ProgressBar(10)
bar.display()
[================================================] 10/10

Update the progress bar:

In [ ]:
import time

for i in range(11):
    bar.progress = i
    bar.update()
    time.sleep(0.25)