Disassemble python bytecode into a series of :class:`Op` and
    :class:`Label` instances.

    Arguments:
        code(bytes): The bytecode (a code object's ``co_code`` property). You
            can also provide a function.
        origin(dict): The opcode specification of the python version that
            generated ``code``. If you provide ``None``, the specs for the
            currently running python version will be used.

    Returns:
        list: A list of opcodes and labels.

def disassemble(code, origin=None):
    """
    Disassemble python bytecode into a series of :class:`Op` and
    :class:`Label` instances.

    Arguments:
        code(bytes): The bytecode (a code object's ``co_code`` property). You
            can also provide a function.
        origin(dict): The opcode specification of the python version that
            generated ``code``. If you provide ``None``, the specs for the
            currently running python version will be used.

    Returns:
        list: A list of opcodes and labels.
    """

    if inspect.isfunction(code):
        code = six.get_function_code(code).co_code

    origin = get_py_internals(origin)

    opname = origin['opname']
    hasjrel = origin['hasjrel']
    hasjabs = origin['hasjabs']
    hasjump = set(hasjrel) | set(hasjabs)
    wordcode = origin['wordcode']
    if not wordcode:
        ext_arg_shift = 16
    else:
        ext_arg_shift = 8

    ext_arg_name = opname[origin['extended_arg']]
    ext_arg = 0

    addr_labels = {}
    addr_ops = []

    code_iter = enumerate(six.iterbytes(code))
    for op_addr, op_code in code_iter:
        if op_code >= origin['have_argument']:
            rel_addr, arg = next(code_iter)
            if not wordcode:
                rel_addr, b = next(code_iter)
                arg += b << 8

            arg += ext_arg

            if op_code in hasjrel:
                arg += rel_addr

            if op_code in hasjump:
                arg = addr_labels.setdefault(arg, Label())
        else:
            if wordcode:
                next(code_iter)
            arg = None
        ext_arg = 0

        op_name = opname[op_code]

        if op_name == ext_arg_name:
            ext_arg = arg << ext_arg_shift
            op = None
        else:
            op = Op(op_name, arg)

        addr_ops.append((op_addr, op))

    ops = []
    for op_addr, op in addr_ops:
        label = addr_labels.get(op_addr)
        if label is not None:
            ops.append(label)

        if op is not None:
            ops.append(op)

    return ops