I agree that, in general, duck-typing is preferable. However in cases like this, where you really want to ensure the count of shares is a whole number, I can see an argument for `isinstance`.
What I can’t understand is the argument that occasional use of `isinstance` is bad, but also that pervasive nominal type-checking via annotations is good.
It usually means there is a better way to do what you are doing.
If it's user input you should sanitize there. In Python this is often easy because you can usually cast as the type you need e.g. with int() and then raise exception if it cannot.
If it's your code, then you should make sure you are passing in an int if that's what is required. If you type hint the input as int, and somewhere in your code you pass in a string, you will get a warning in the IDE.
I would argue that's a very different time and place than checking for instanceof in the running code and that's why isinstance is bad and type-checking is good.
There are always exceptions but it's bad to write them in examples when teaching code.
> If you type hint the input as int, and somewhere in your code you pass in a string, you will get a warning in the IDE.
Statically-typed languages can guarantee to get this right 100% of the time. Can type-checkers for a highly-dynamic language like Python guarantee the same?
> Statically-typed languages can guarantee to get this right 100% of the time.
No they don't. They usually provide escape hatches for things typesystem does not cover, so there are cases where typechecker will just trust that you know what you are doing (even if you don't).
But more importantly, you don't need 100% to be useful. For aid in IDE, high precision (with somewhat lacking recall) is good enough. Of course, for refactoring, higher recall, the better (but you could substitute lacking recall with tests, which is suboptimal, but viable).
But it's interesting question on what python/mypy (python typechecker) can actually do. The answer here is it depends on configuration. Mypy with default configuration typechecks only typed code (i.e. functions which have type annotations) so you get guarantees only there. But you can configure it to be more and more strict (checking untyped defs, not allowing untyped code, and more), which increases guarantees you get (and it also increases the number of valid programs that it rejects). You can get in python into really strictly typed code, but you can also hit the wall if you need libraries that does not provide proper type hints (unless you write type hints by yourself).
> What I can’t understand is the argument that occasional use of `isinstance` is bad, but also that pervasive nominal type-checking via annotations is good.
it doesn't have to be nominal, MyPy supports structural sub-typing through Protocols [1]