What happens under the hood is that, when you assign an instance attribute, that instance's private dictionary (__dict__) gets updated, but not the class's __dict__. The former takes precedence for a look-up of the requested attribute, and if it can't be found (in the first few lines, and always for object2), the class's __dict__ is used to look up the attribute.
Specifically:
Attribute assignments and deletions update the instance’s dictionary, never a class’s dictionary. If the class has a __setattr__() or __delattr__() method, this is called instead of updating the instance dictionary directly.
(Emphasis mine. From the Python documentation on the standard type hierarchy in the data model; you'll need to find the subsection "Class instances", second paragraph. The paragraph before it deals with the instance attribute look-up order. The whole subsection and the one before, "Custom classes", may be good to read to get the concept; perhaps a few times, as it is somewhat condensed.)
What often helps me to understand what is going on underneath, is to print the ids and (in this case) __dict__ attributes of the relevant instances, class and attributes. The id is not a real guarantee you're seeing the same object, but has generally worked for me when using CPython.
Your code, adjusted to print this:
from __future__ import print_function
class MyClass(object):
value = 5
object1 = MyClass()
object2 = MyClass()
print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)
object1.value = 6
print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)
MyClass.value = 10
print(object1.value, id(object1.value), object1.__dict__)
print(object2.value, id(object2.value), object2.__dict__)
print(MyClass.value, id(MyClass.value), MyClass.__dict__)
and the output I get (with a few extra newlines and spaces inserted for reading comfort):
5 4325640816 {}
5 4325640816 {}
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__module__': '__main__', 'value': 5}
6 4325640848 {'value': 6}
5 4325640816 {}
5 4325640816 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__module__': '__main__', 'value': 5}
6 4325640848 {'value': 6}
10 4325640976 {}
10 4325640976 {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__module__': '__main__', 'value': 10}
The ids will vary per run and system, and conveniently here, 'value' is always printed last in the MyClass.__dict__, but you can see which attributes change and which are effectively the same, and how the __dict__ attribute gets updated.
(Note: do not modify the __dict__ attribute yourself. Generally, don't use it in any way, not to read from either. Let other built-in methods and functions handle that.)