This behavior is not specific to Python, but this answer will focus on Python explanation.
The dependency goes from parent to children classes.
You can see inheritance as creating a new dict from a previous one.
foo = {
"speak": 1,
"run": 2,
}
bar = foo | {"speak": 3} # we merge/override new values into the newly formed dict
print(foo) # {'speak': 1, 'run': 2}
print(bar) # {'speak': 3, 'run': 2}
To give you an example close to your case:
Animal = {"speak": lambda: "Animal speaks"}
# Merge with already existing values is similar to subclass overriding
Dog = Animal | {"speak": lambda: "Dog barks"}
# Your can see .copy() as the object instanciation in this demonstration
some_animal = Animal.copy()
some_dog = Dog.copy()
print(some_animal["speak"]()) # Animal speaks
print(some_dog["speak"]()) # Dog barks
And that would be pretty close to reality. Under the hood, a class is only a glorified dict that you copy when you create an instance (and add new values in the init). In fact, you can find this dict in the dunder attribute __dict__:
class Animal:
def speak(self):
return "Animal speaks"
print(Animal.__dict__)
# {..., 'speak': <function Animal.speak at 0x...>, ...}
If that helps: https://docs.python.org/3/tutorial/classes.html#inheritance
You need to remember that in Python, names are only references to a memory value. Those references are bound to a namespace. The speak reference doesn't exists, only Animal.speak and Dog.speak. By defining an override in Dog, you create a new function named "speak" in memory, and make the Dog.speak reference point to that function. Doing so, you changed one and only one reference, Dog.speak, not Animal.speak who keep referencing the first speak function created.

You can play with this code here.
speakon the parent? Subclassing affecting the parent would be a mess that would lead to fragile code.