I've just now studied about covariance and contravariance in static languages (more specifically C#). This concept is rather clear to me, however I'm in doubt on how this applies to dynamic languages like Python.Since Python is duck typed (or structural typed) it seems to me that there is not even a notion of variance and covariance in this language?If I'm not mistaking, things like contravariance and covariance are checked at compile-time in a language like C#, this is possible because a variable has a type, and the value it is bound to has a type as well and these have to match or be co(ntra)- or invariant. However, since there is no notion of typing at compile-time with a language like Python I don't know how to apply this concept.Any thoughts?My thoughts: The concept of covariance means that whenever we expect a type of X, any subclass of X will do as well. So, in Python this doesn't come up, because there is no type check to do this. The only check that happens is wether or not the object has the necessary implementations by means of methods and attributes.In C# for example where we have a method:void DoStuff(Person p){    p.Dance();};We could very well call this method with an instance of a Student (if this is a subclass of Person).Now, in Python, we could very well pass in a Bird object that would not be related to Person in any way in the inheritance hierarchy(except it would also inherit from object), as long as this bird implements Dance().This is why I'm asking about this concept. From what I understand Python is covariant and contravariant in.. well, everything?
Can parameters be contra- or covariant in Python?
programming languages;type theory
Here are some general thoughts on how contra- and co-variance issues affect programming in dynamically typed languages.Covariance: If B is a subtype of B' then functions A $\rightarrow$ B form a subtype of A $\rightarrow$ B'.Contrvariance: If A is a subtype of A' then functions A' $\rightarrow$ B form a subtype of A $\rightarrow$ B.For example, if Auto is a subtype of Vehicle, then the contravariance rule says that a function that takes a Vehicle argument can be regarded as a function taking an Auto argument (because the Auto can be regarded as a Vehicle).  However, a function taking an Auto argument cannot be treated as a function that takes a Vehicle argument.  If you do, then sooner or later, you might pass it a non-Auto argument, say a Bicycle, and you would get a run-time error.Whether the language is statically typed or dynamically typed makes little difference to the logic you use to design programs.  If the language is statically typed, the type checker would complain about the design flaws in your program that show up as type-mismatches.  If it is dynamically typed, you are likely to get a run-time type error such as message not understood.  That is if you are lucky.  If you are unlucky, the problem would go unnoticed during testing, and the program would crash in the hands of the end-user.