How to get random color variation on a single mesh?
Following the several comments, I've thought an addon can be useful to do that and may have a general interest.



What does it do:


Identify loose parts of the object (or all selected objects)
Generate a random color for each loose part
Follow the mesh loops to assign the vertex colors


(can be installed as an addon)

The code is commented below (please comment if needed):

bl_info = {
    "name": "Assign random vertex color to each loose part of a mesh",
    "author": "lemon",
    "version": (1, 0),
    "blender": (2, 78, 0),
    "location": "Properties Editor &gt; Object data",
    "description": "",
    "warning": "",
    "wiki_url": "",
    "category": "Mesh"}

import bpy
import time
import random
from mathutils import Color

def LoosePartsMakeVertPaths( verts, edges ):
    #Initialize the path with all vertices indexes
    result = {v.index: set() for v in verts}
    #Add the possible paths via edges
    for e in edges:
        result[e.vertices[0]].add(e.vertices[1])
        result[e.vertices[1]].add(e.vertices[0])
    return result

def LoosePartsFollowEdges( startingIndex, paths ):
    current = [startingIndex]
    result = set( current )

    follow = True
    while follow:
        #Get indexes that are still in the paths
        eligible = set( [ind for ind in current if ind in paths] )
        if len( eligible ) == 0:
            follow = False #Stops is no more
        else:
            #Get the corresponding links
            next = [paths.pop( i ) for i in eligible]
            #Get the new links as new inputs
            current = set( [ind for sub in next for ind in sub] )
            result = result.union( current )

    return result

def LoosePartsCountIslands( obj ):
    #Prepare the paths/links from each vertex to others
    paths = LoosePartsMakeVertPaths( obj.data.vertices, obj.data.edges )
    found = True
    n = 0
    while found:
        try:
            #Get one input as long there is one
            startingIndex = next( iter( paths.keys() ) )
            n = n + 1
            #Deplete the paths dictionary following this starting index
            LoosePartsFollowEdges( startingIndex, paths )               
        except:
            found = False
    return n

def LoosePartGetIslands( obj ):
    paths = LoosePartsMakeVertPaths( obj.data.vertices, obj.data.edges )

    result = []

    found = True
    while found:
        try:
            #Get one input as long there is one
            startingIndex = next( iter( paths.keys() ) )
            #Deplete the paths dictionary following this starting index and append the result
            result.append( LoosePartsFollowEdges( startingIndex, paths ) )
        except:
            found = False

    return result

def RandomColor( rnd ):
    return Color( (rnd.random(), rnd.random(), rnd.random()) )

def RandomColors( rnd, count ):
    return [RandomColor( rnd ) for i in range( count )]

def ColorFromVertexIndex( vertexIndex, looseParts, colors ):
    for c, lp in zip( colors, looseParts ):
        if vertexIndex in lp:
            return c
    return Color()

def RandomVertexColorsByLooseParts( obj, vcolName, useSeed, seed ):

    rnd = random.Random()
    if useSeed:
        rnd.seed( seed )

    mesh = obj.data

    #Create vertex colors if it does not already exist    
    if vcolName not in mesh.vertex_colors:
        mesh.vertex_colors.new( vcolName )
    #Update it so that it is available below
    mesh.vertex_colors.update()
    #Get the vertex colors
    vertexColors = mesh.vertex_colors[vcolName]

    #Get loose parts
    looseParts = LoosePartGetIslands( obj )
    #Generate random colors
    colors = RandomColors( rnd, len(looseParts) )

    mesh.loops.update()

    #Follow the loops    
    for i, vertexIndex in enumerate( [loop.vertex_index for loop in mesh.loops] ):
        #Assign vertex colors from loop index and vertex index
        vertexColors.data[i].color = ColorFromVertexIndex( vertexIndex, looseParts, colors )

def InitProperties():
    bpy.types.Scene.VertexColorsName = bpy.props.StringProperty( name = "Vertex colors", description = "Vertex colors to use or create", default = "Col" )
    bpy.types.Scene.VertexColorsUseSeed = bpy.props.BoolProperty( name = "Use seed", description = "Use fixed seed to generate random values" ) 
    bpy.types.Scene.VertexColorsSeed = bpy.props.IntProperty( name = "Seed", description = "Seed for random values" ) 
    bpy.types.Scene.VertexColorsAllSelected = bpy.props.BoolProperty( name = "All selected objects", description = "Apply to all selected object or only active one" ) 

class RndVColToLoosePartsPanel(bpy.types.Panel):
    bl_label = "Random vcol to loose parts"
    bl_space_type = "PROPERTIES";
    bl_region_type = "WINDOW";
    bl_context = ""

    @classmethod
    def poll(self, context):
        return context.object and context.scene

    def draw(self,context):
        layout = self.layout
        scn = context.scene

        layout.prop( scn, 'VertexColorsName', icon='GROUP_VCOL' )
        layout.prop( scn, 'VertexColorsUseSeed' )
        layout.prop( scn, 'VertexColorsSeed' )
        layout.operator( "rndvcoltolooseparts.ope")
        layout.prop( scn, 'VertexColorsAllSelected' )

class RndVColToLooseParts(bpy.types.Operator):
    bl_idname="rndvcoltolooseparts.ope"
    bl_label="Generate random vcol to each loose parts"

    def execute(self, context):

        scene = context.scene
        obj = context.object

        if scene and obj and obj.type == 'MESH':

            prevMode = obj.mode
            bpy.ops.object.mode_set( mode='OBJECT', toggle=False )

            if scene.VertexColorsAllSelected:
                for obj in [obj for obj in context.selected_objects if obj.type == 'MESH']:
                    RandomVertexColorsByLooseParts( obj, scene.VertexColorsName, scene.VertexColorsUseSeed, scene.VertexColorsSeed )
            else:
                RandomVertexColorsByLooseParts( obj, scene.VertexColorsName, scene.VertexColorsUseSeed, scene.VertexColorsSeed )

            bpy.ops.object.mode_set( mode=prevMode, toggle=False )

        return {'FINISHED'}     


def register():
    InitProperties()
    bpy.utils.register_class(RndVColToLooseParts)
    bpy.utils.register_class(RndVColToLoosePartsPanel)


def unregister():
    bpy.utils.unregister_class(RndVColToLooseParts)
    bpy.utils.unregister_class(RndVColToLoosePartsPanel)


if __name__ == "__main__":
    register()