Not always
After calling an add primitive operator it is almost always the case that the new object is both active and selected. In which case it rings true.
>>> bpy.ops.mesh.primitive_cube_add()
{'FINISHED'}
>>> C.object is C.selected_objects[0]
True
but the selection can be manipulated such that the active object is None, and there are still selected objects.
>>> for o in C.scene.objects:
... o.select_set(True)
...
>>> C.view_layer.objects.active = None
>>> C.object is C.selected_objects[0]
False
Then not true.
Selecting then setting active object
>>> for o in C.scene.objects:
... o.select_set(True)
...
>>> C.view_layer.objects.active = None
>>> C.selected_objects[0]
bpy.data.objects['Cube']
>>> C.view_layer.objects.active = C.scene.objects['Cube.001']
>>> C.selected_objects[0]
bpy.data.objects['Cube']
Again not true.
Or no selected objects, with or without an active object
>>> C.view_layer.objects.active = C.scene.objects['Cube'] # or None
>>> for o in C.scene.objects:
... o.select_set(False)
...
>>> C.object is C.selected_objects[0]
Traceback (most recent call last):
File "<blender_console>", line 1, in <module>
IndexError: list index out of range
In conclusion, suggest if you want to be sure it's the active object use context.active_object
or context.object
. Check if not selected and set selection if need be Don't rely on using context.selected_objects[0]