Python's popularity has been skyrocketing in recent years, thanks to the increase in interest and use of data science as a discipline to analyze and process large bulks of data.
Thanks to its open-source status and vibrant community, as well as for having batteries included, lots of libraries appeared that pushed Python's popularity to the top of the charts (scientific IDEs like Spyder, libraries like numpy, pandas, among others).
And, while for data processing a Number type suffices when tied with matrices and plotting utilities, Python, as a dynamically typed language has some shortcomings when it comes to normal product based web development.
Dynamic and static type systems
There are different ways languages go about using type information.
Some enforce that all types are correct up to function definition level (like Haskell, where types need to be specified), then Java, C/C++ and the lot, due to their statically typed nature enforce types to be explicitly declared (or not: if the compiler/JVM supports it, it's possible to do type inference, where the compiler deduces the types from context, even when no type is specified:
var x = 5; is valid Java 11+ and it denotes that x is of type integer, because it's inferred on compile-time), and checked upon compilation.
Other languages, like Python, which are interpreted, have dynamic typing, which means that types don't need to be explicitly declared and because of being interpreted, no compile-time checks are ever done on the correctness of types, which means that this is valid Python:
a = 10 #integer a = ["a", "b"] #List of strings
What this means is that there are no guarantees before runtime regarding the types of variables you're operating on. This can become very hard to manage with large codebases filled with legacy code and lots of modules and functions and classes, all with no explicit type checking, it means you're basically on your own.
It also means, in languages similar to Python, that a variable knows nothing about itself NOR the type of value it holds, it's literally like having a cardboard box with a tag attached to it. The identifier is what's written in the tag, but, that provides absolutely no information about the contents of the box, and, as an important consequence, it also provides no information regarding what we can do with what's inside the box. It's up to the programmer to keep track of it somehow and dynamically adjust the code to accommodate to what operations the value supports in its type. Meaning: you can concatenate strings and sum integers, and the plus sign as an operation doesn't really care. It will be information that will be encoded in the types.
Purposefully losing this information, makes the language more versatile and compact, so you can write more code faster and express more behaviour and functionality with less code, but at a very high cognitive cost, since no types are available to help you understanding the code. And we reach the cornerstone of this article. The purpose of code is to be understandable and explicit and predictable to other developers. Types are free documentation that increase understanding and improve developer's productivity.
Seeing as how types are so important in providing a framework of intrinsic code documentation, it's good practice to try and use languages that give you the benefit of static analyses and type checking. This is even crucial for lots of tasks that some developers just take for granted in their IDEs and tool sets. IntelliJ can offer you great refactoring candidates information, code simplification, point to locations with code duplication, simplification of expressions, inlining variables, creating constants out of literals because it has type checking and type information during writing phase.
Types allow for IDEs and other tools to perform what's known as static code analysis. So, thanks to knowledge of types, a tool like a daemon in your development environment can analyze your code and immediately point out to you how you can improve your code.
Case-study: how Dropbox improved their Python codebase
You can read here how Dropbox developed a tool for performing type checking on interpreted languages (specifically Python) and how, by keeping in touch with developers, they successfully developed a tool which is now widely used and brings all the benefits of types that were discussed above to a dynamically typed language.
Their main argument is that code at scale is about ensuring that developers can quickly understand the current codebase so they can get up to speed quickly and being productive quickly. They managed to effectively combine the flexibility and code churn production speed of a dynamically typed language, with the power and reassurance of types and type-checking, which enables new developers to see a very versatile and well documented codebase that is easier to maintain and easier to work with, which enables both developers and the company to extract much more value out of it. Win-win.
We saw that type-checking is such an important "tool" to benefit from, with so many benefits on so many different fronts, that even companies which used dynamically typed languages, realized that, at scale, types become an intrinsic part of your business, because the code is the business, and harnessing the help and gains of types becomes vital to stay efficient.
Multiple companies and individuals have since adopted this tool, I hope more people will like, understand and love types and their power!!