These computer models of types just approximate the real world. The world isn't that well organized. You can take slices of things and they seem organized within the slice, but its only one perspective.
A typical example:
Birds can fly.
A penguin is a bird.
A penguin can fly.
An error caused by an overly general assumption early on. (Not all birds can fly - but most do).
This kind of error occurs in program development all the time. You make a simplifying assumption early on. You proceed based on that assumption. Eventually, some new information comes along that doesn't fit your original assumption.
Question - when your assumption is proven to be false, what do you do?
In a strong statically typed language, you have no choice, you must aggresively refactor you class hierarchy to account for these differences. Suddenly instead of abstract class Bird with operation fly(), you have to create FlyingAnimal, add each of the types of birds that can fly individually. And you've lost the birdness of them. You have gained the ability to add bats, flying fish, and flying squirrels.
You can say that you could solve this with multiple inheritance and divide the types into protocols or interfaces. Then you might have something like:
Penguin : <Bird, FurBearing, Swimmer, LandDweller, Diurnal>
Canary : <Bird, Feathered, Flying, TreeDweller, Diurnal>
Bat : <Mammal, FurBearing, Flying, CaveDweller, Nocturnal>
But this fine level of factoring maybe isn't necessary for your application to work (maybe its a zoo food distribution system).
I'd like to refer you to Bart Kosko's "Fuzzy Thinking" as an interesting (and not too technical) read. Fuzzy people's idea of set membership isn't binary, its a float - how strongly do you exhibit a certain membership? How Catholic are you? In my younger dating days I came to understand with girls that there's Catholic and Catholic. That's just life.
OK, so assuming we have a dynamically typed system and we make the same bad assumption. We don't have to refactor the entire type hierarchy to account for shifts in the way we look at things. We can implement the flying protocol on anything we like and simply remember to only hand flyers to things that expect things to fly.
a list in python can hold a combination of arbitary types
(I want to ask experienced programmers when is that useful)
Well, this is Smalltalk. But consider:
"a collection of stuff with nothing in common?"
stuff := OrderedCollection with: (Refrigerator new) with: (Sofa new) with: (Penguin new) with: (BowlingBall new) with: (Sandwich new).
truck := Truck withCapacity: 2000. "One ton truck"
weight := 0.
truck load: (stuff select: [:item |
((weight + (item weight)) < (truck capacity))
ifTrue: [weight := weight + item weight. true]
ifFalse: [false]]).
Apparently all that stuff has something in common after all.