Because you are copying one object, all the object data is the same. Because of that you can not add different materials to the object data (there is only one). Instead you will need to assign the material to the object, not the objects data. ![material link button][1] These five lines below are what create a material, add it to the object and set the link to *object*, instead of the default *object data*. The `diffuse_color = [R, G, B]` is where you specify the color you would like that material to have (blender is expecting value between 0.0 and 1.0 for each color channel). Keep in mine this code is only for cycles, the blender internal render has a different way of doing materials. mat = bpy.data.materials.new("materialName") mat.diffuse_color = [R, G, B] ob.active_material = mat ob.material_slots[0].link = 'OBJECT' ob.material_slots[0].material = mat Full edited code below. import bpy bpy.ops.object.select_all(action='DESELECT') bpy.ops.mesh.primitive_uv_sphere_add() sphere = bpy.context.object R,G,B = 1,0,0 for i in range(-1000, 1000, 2): ob = sphere.copy() ob.location.y = i bpy.context.scene.objects.link(ob) mat = bpy.data.materials.new("materialName") mat.diffuse_color = [R, G, B] ob.active_material = mat ob.material_slots[0].link = 'OBJECT' ob.material_slots[0].material = mat bpy.context.scene.update() # version < 2.8 # bpy.context.view_layer.update() # version 2.8 [1]: https://i.sstatic.net/Zh5w5.png