Solution 1 : Quick and dirty
Here is a trivial implementation built on top of bidict, done on the suggestions made by adrin and Austin :
class couple ( bidict ) :
    self._flags = {}
    def add ( self, key, val, flag ) :
        try :
            del self._flags[ self._inv[ val ] ]
        except KeyError :
            pass
        self._put(key, val, overwrite_key=True, overwrite_val=True)
        self._flags[ key ] = flag
    def flag ( self, key, val ) :
        if ( self._fwd.get( key ) == val ) :
            return self._flags[ key ]
        else :
            raise KeyError( key, val )
This way, one can obtain the following behaviour :
bbt = couple()
bbt.add( 'stephen', 'amy', 0.4 )
bbt.flag( 'stephen', 'amy' )
>> 0.4
bbt.add( 'sheldon', 'amy', 1.0 )
bbt.flag( 'sheldon', 'amy' )
>> 1.0
bbt.flag( 'stephen', 'amy' )
>> KeyError: ('stephen', 'amy')
Solution 2 : Specific and standalone
Since I finally ended up coding my own structure. It is standalone and can be c/c if needed by anyone passing here :
class FlaggedDoubleMapper :
    """Flagged Double Mapper"""
    def __init__ ( self, keys = [], vals = [], flags = [] ) :
        """Initializes a flagged double mapper with lists of keys, values and
        flags.
        """
        self._flg = {}     # Flags dictionary
        self._fwd = {}     # Forward dictionary
        self._bwd = {}     # Backward dictionary
        for key, val, flag in zip( keys, vals, flags ) :
            self.add( key, val, flag )
    def __repr__ ( self ) :
        """Representation bidict-style."""
        return 'fdm({})'.format( self._fwd )
    def contains ( self, key, val ) :
        """Returns True if and only if self contains the key-val binding."""
        try :
            return ( self._fwd[ key ] == val )
        except KeyError :
            return False
    def add ( self, key, val, flag ) :
        """Adds a flagged binding, overwriting all corresponding bindings."""
        try :
            _val = self._fwd[ key ]
            del self._bwd[ _val ]
        except KeyError :
            pass
        try :
            _key = self._bwd[ val ]
            del self._flg[ _key ]
            del self._fwd[ _key ]
        except KeyError :
            pass
        self._flg[ key ] = flag
        self._fwd[ key ] = val
        self._bwd[ val ] = key
    def remove ( self, key, *args ) :
        """Removes a binding.
         - remove( key ) will send a KeyError( key ) if no binding with key as a
         forward key is found.
         - remove( key, val ) will send a KeyError( key, val ) if no forward
         key-val binding is found.
        """
        try :
            _val = args[0]
            if ( _val != self._fwd[ key ] ) :   # Can raise a KeyError( key )
                raise KeyError( key, _val )
        except IndexError :
            _val = self._fwd[ key ]             # Can raise a KeyError( key )
        del self._flg[ key ]
        del self._fwd[ key ]
        del self._bwd[ _val ]
    def flag ( self, key, *args ) :
        """Returns the flag of a binding.
         - flag( key ) will send a KeyError( key ) if no binding with key as a
         forward key is found.
         - flag( key, val ) will send a KeyError( key, val ) if no forward
         key-val binding is found.
        """
        try :
            _val = args[0]
            if ( _val != self._fwd[ key ] ) :   # Can raise a KeyError( key )
                raise KeyError( key, _val )
        except IndexError :
            pass
        return self._flg[ key ]