Python - Overview of the most popular programming languages #3

Posted: 2023-01-26
Written by: Tomasz Przedziński

In our ongoing review of the most popular programming languages, we have already covered C#, C, and C++:

Our review concludes with Python, which has literally exploded in popularity in recent years, giving it the top spot in the index.

Popularity of the Python programming language over time. Source: www.tiobe.com

There are many factors behind this. We are experiencing a tremendous increase in interest in the language in the following areas:

Using Python in these areas makes complete sense, and I hope you will agree with me after reading this article.

 

Simplicity, convenience, and utter freedom

Python differs from the languages discussed so far in virtually every respect. Once you try Python, you will find that every other programming language is difficult to use. It requires years of experience and is fraught with problems that Python pretty much does not possess.

Python is one of the easiest programming languages to learn. Its applications are versatile – from simple scripting to complex machine-learning environments. Thanks to the vast array of libraries that can be used by typing a single line in the console (or with a single click in the IDE), the programmer has a powerful arsenal of ready-made solutions at their fingertips from the very first minutes of working with the Python language. Within a few minutes, a range of programs can be written, including an HTTP server or a simple game with a graphical interface. For instance, after importing the appropriate module, just two lines of code display a pop-up window saying, “Hello world!”.

“Hello world!” program in Python

A program that displays a pop-up that says, “Hello world!”. It works on Windows, Linux, and many other systems, I would suspect. Requires typing an extra line in the console once: pip install PyMsgBox.

Since Python is an interpreted language, adding new lines of code to run a new version takes no time, and there is no need to compile it. A few hours is all it takes to learn and use the language effectively due to the simplicity of its grammar. At the same time, it supports many different programming paradigms, including object-oriented programming, letting you pick the programming style that ideally suits the task at hand.

Code is easily broken down into modules in Python, which undoubtedly contributes to the massive base of ready-made modules. When tackling a new problem, it’s always wise to double-check whether someone hasn’t already done it, as it may only take one line of code to import and re-use an existing working solution.

Python manages memory using Garbage Collection mechanisms, much like the .NET platform, thus easing the burden on the programmer. Moreover, it comes with tools for asynchronous1,  programming, including mechanisms that implement both the Task-based Asynchronous Pattern (TAP) and Event-based Asynchronous Pattern (EAP) approaches. There is one feature that makes Python stand out among all the other languages mentioned in this article – dynamic typing, that is.

Dynamic typing, as opposed to static typing in most modern programming languages, means that the type of variables does not have to be known when coding the program. It’s determined at runtime, which impacts a lot on how code is written. You can, for instance, write a function that expects a specific type of variable but doesn’t enforce that type. By later extending this function to other types, you do not have to make changes to either the API or the parts of the code that are common to these types. You may even find that you don’t need to change anything at all. This is because, thanks to a typical Python programming style called duck typing2, we can take the opposite approach and extend other types’ functionality to meet our function’s needs3.

And this is just the beginning. We can, for instance, expect our type to have a ‘test’ function and deal with the situation where the type does not have it. This way, we do not constrain the list of types for which our functionality works correctly; we only handle exceptions. To achieve the same effect in other programming languages, you must create appropriate abstractions and algorithms that operate on them. In other words, it is not uncommon to rewrite a large chunk of code to make one type handle two types. It is possible that similar work needs to be done to address the third one, too. Such code extensions are trivial in Python language.

As if that weren’t enough, in many ways, Python treats variables and collections of variables (arrays, tuples, etc.) the same way. Instead of a single variable, you can pass an array of them. The same rules apply to what we return from a function. Again, most programming languages are very strict about what a function can return. No problems like this exist in Python. You can return whatever you want, whenever you want, without declaring in advance what a function will return. The type returned can also be derived from the function’s arguments and be different for each call to the function.

You don’t really have to worry about too many things when programming in Python. All you have to do is sit down and get started writing code. Need support for this or that? There’s probably a module for that. Need a generic function? No need for a series of classes, abstractions, or type definitions – you write what you need. And as the project gets more complex, you can wrap what you require into classes or modules and organize the code better. Importing your modules is, again, just one line. No thought is given to compilation, headers, and other ‘relics’ of statically-typed languages. There is a reason why beginner programmers are most likely to start with Python. It makes it very easy to learn what is most critical in programming – problem-solving skills. You don’t need a rigid, restrictive language that forces you to learn and use lots of unnecessary mechanisms before you write your first decent program. Its ease of use is by far the strongest magnet for attracting new programmers, thereby increasing Python’s popularity.

It’s hard to imagine how programming in languages with dynamic and static typing differs without having at least a smattering of experience with both. If you don’t have that experience, believe me when I say it varies dramatically. However, there is more to dynamic typing than just the advantages alone. Like an asterisk on an advertisement or contract – the disadvantages of it are hidden from the developer until they read deeper into the content.

 

Python – love it or hate it?

Python is the most internally polarized language I know. What I mean by that is I could praise every essential feature and then add a ‘but’ and some sort of accusation.

Getting started is pretty straightforward, but as functionality is extended with modules, it becomes much more complicated. Simple projects can be written quickly, but complex ones are harder to maintain over time. The lack of compilation and many other aspects of working with a code interpreter are welcome. However, this comes at a significant cost to the performance of the program4. Dynamic typing makes it significantly easier to write new code quickly. However, it does so at the expense of static analysis. Several basic programming errors can be eliminated through this analysis.

Python allows you to pass anything as an argument to a function. The example on the left will allow you to write arbitrary things on the screen. However, its behavior is rarely as expected. In order to handle lists and collections correctly, we need to extend the code like the example on the right. On top of this, we would need to handle boundary conditions, such as handling missing arguments or handling functions. We have no way of limiting the types for which the user will use our function. We can only “suggest” the use by means of hints. We should therefore protect ourselves against its erroneous use. A lack of safeguards may cause an error, or, more seriously, the code will work contrary to expectations without reporting an error.

It is this last point that I find most frustrating of all5. The lack of a compiler in Python means that simple errors, such as typos in variable names, only come up when the interpreter gets to the wrong line of code. It is not difficult to imagine the significant problems this can cause. Let’s take a look at this example: if we have written a piece of code including error handling, the code responsible for this action will only be executed (which also means: checked) when an error occurs. If the error never occurs, we will not know whether we have made a typo or not – the same applies to any other branch of the code. Errors in the code responsible for error handling are critical insofar as tests do not usually cover them. At least not from the very beginning.

The code above presents a typical example of Python problems. In the example on the left, the typo on line 4 will not be highlighted by the IDE because “something” may have an “appen” function. There is no mechanism to tell in advance whether or not it has such a function. When run, this code will throw an error for both use cases even if, as intended, it should output ’10’ for the second. The example on the right, on the other hand, shows a more serious problem to me: the incorrect sum of types ‘str’ and ‘int’ on line 9 will not be caught because this line will never be executed – both function calls do not raise an exception. It is not known when this error will be discovered. In this case, its consequences are minor, but even such a seemingly “innocent” error in production can be problematic, as it can terminate the entire program.

This problem entails a number of consequences. If you are developing production code or a publicly-available module, you should test every path in it. This is not because the manager has set a 100% code coverage with tests as a project goal. Instead, by not running through every line of code in tests, we will not be sure that there are no fundamental errors in it. While the parser that analyzes the executing file will check for missing brackets, inverted commas, or similar problems in the structure of the code, there is no way to tell if there is a typo in a particular function call. Even the most expensive paid IDEs cannot perform thorough code analysis as a function may be called with a different, utterly unexpected type. Even tests that cover 100% of the code will not check it for every supported type.

In practice, this means significantly delayed error detection. On the one hand, this is a problem we should be concerned about; on the other hand, these bugs must occur in less frequently used program paths. Otherwise, we would have found them long ago. Thus, the issue lies in ensuring the code is complete or of high quality – it may be harder, or at least more difficult, compared to other programming languages, to guarantee that the code will work correctly, taking into account future applications and project developments.

On top of this, there is a problem due to the very error handling performed by the interpreter. When the Python interpreter finds a problem, it throws an exception. Again, another great feature of the interpreter, to which I must add a BUT – this feature is the bane of novice programmers. Suppose someone inadvertently overrides a piece of code with the typical beginner’s try-except form, which catches all possible exceptions. In that case, they may also notice an interpreter exception and handle it generically, suppressing the actual reason for throwing it. This takes error detection even further back in time.

Error handling is necessary because we do not usually assume that an error will occur when we write code. We also typically do not test such scenarios, at least not immediately. Dynamic typing and code interpretation make it significantly more difficult not only to guard against errors but also to recognize their causes when they do occur.

Other programming languages also suffer from similar problems, but not to this extent. The reason for this is another difference in the style of working with Python – most projects written in statically-typed languages follow the LBYL (Look Before You Leap) practice, which, in a nutshell, tries to limit exception handling to genuinely exceptional situations and mandates verification of the initial requirements of various functions and modules. Python adheres to the EAFP (Easier to Ask for Forgiveness than Permission) doctrine, which says exactly the opposite – don’t verify; try to do what you want. You will, at most, cause an exception, which will be handled. The same approach should also be expected of external modules used in a project. This consequently means that it is much more common to have to deal with exceptions of various types.

The increased number of exceptions entails a desire to have it easy on the code at one point or another, leading to generic try-excepts that sometimes cover too wide a range of exceptions thrown, thus hiding various relevant errors in the code.

 

So what’s the deal with Python? Is it cool or not?

After reading the previous chapter, one might conclude that working with Python is all about problems. It is, therefore worth pointing out that the author of this article works with statically-typed languages on a daily basis. Hence, the differences in approach and errors he encounters are more apparent to him than to someone who has been programming Python for years.

It cannot be said that dynamically-typed Python is better or worse than statically-typed Python – they are just different. It has other advantages, different problems, and, consequently, different applications. You won’t find high-performance demanding games6, in Python language, nor complex numerical algorithms or machine learning. Anything that requires high computational complexity is written in dedicated languages, and yet you can write a game in Python for the Source engine, perform complex and labor-intensive matrix calculations using the NumPy library, or teach neural networks using the Tensorflow or PyTorch environment. Some Python development communities will create a suitable interface if the project is widespread. If the tool in question allows the user to add their code, the user may write it in Python.

Scientific and business areasBack-endOther
  • machine learning
  • big data
  • data science
  • NLP
  • scripts
  • process automation
  • console tools
  • installers
  • test environments
  • tests for other projects
  • web applications and servers
  • graphical interfaces
  • scripts for other tools (graphics, design, game engines, etc.)

The general-purpose nature of Python makes it suitable for a wide variety of applications. However, it is most readily used where programming is merely a tool to achieve a much more complex goal, such as in scientific environments.

 

What do the C#, C, C++, and Python languages have in common?

You may find it hard to believe, but the four languages Python, C, C++, and C# work well together. I have twice (in two different companies) encountered a project in which all four languages were used simultaneously – for very different purposes, of course. Both projects were embedded software projects, where the device driver layer was written in C, the application layer in C++, and a desktop application was created in C# to communicate with the device (management, configuration, debugging, updates, etc.), and Python was used for functional testing7.

Many projects seek to make the most of the diversity offered by different programming languages. As I see it, language choice was based on the team’s experience and capabilities for each of the tasks in the mentioned projects.

Nowadays, it is increasingly difficult to find a project written in one language, and very narrow specialization is starting to be limiting for programmers. It is, therefore, worth broadening your horizons and seeking out other languages to master. The TIOBE Index, which we have used as a guide in this series of articles, is a reliable reflection of the job market. In order to determine the potential future direction, we recommend more surveys published annually by StackOverflow8. They contain plenty of details and highlight current trends among developers in this vast and diverse community. They show, among other things, slightly different proportions when it comes to the four languages discussed in this series. C and C++ are rather marginalized, while Python and the .NET platform are gaining more and more fans. Python is, without a doubt, a significant player in the programming language market today, and this situation is unlikely to change anytime soon.

Have an idea for a mobile app, web app, or custom system and are looking for an experienced technology partner? Take a look at the projects we have completed for clients who were in need of custom software. If you have a roadmap and description of the application ready, we’ll be able to prepare a quote in as little as 24 hours. This is after you send us the specifications. If not, no worries. Get in touch and set up a free consultation to work out the next steps together.

Everything you should know about creating an application

1 – Python supports both multi-threaded and multiprocess programming. Both approaches can be used in other programming languages, but Python allows you to choose between one or the other easily.
2 – This term has no equivalent in Polish. It derives from the saying that if it walks like a duck and quacks like a duck, it must be a duck. In this approach, the type of object analyzed results from the characteristics that this object represents rather than from a rigid declaration that a given thing is a duck. In simple terms, this approach means that it is correct to think of people as ducks if the only attribute we look at is the presence of two legs.
3 – To make things more interesting in Python, we can even do this within the function being called! For example, if we need a type that enters a function to “quack” but we get a type that does not, we can add an implicit quack to it to get the functionality we need. It sounds rather complicated and unintuitive, and for many programmers used to other programming languages, it is, but these mechanisms are Python’s real power.
4 – Notoriously, Python fares very poorly in comparisons like this one: https://thenewstack.io/which-programming-languages-use-the-least-electricity/ where the energy, time, and memory consumption for solving tricky numerical problems is analyzed. Of the 27 languages analyzed, Python ranks second-to-last in energy consumption and execution time (the comparison is made against the C language). However, such a dramatic result can be seen as unfair – the Python language is not used for intensive numerical calculations precisely because it will be much slower in this application for obvious reasons. For this reason, numerical libraries for Python are written in C or C++ and only provide the interface in Python. This is a typical approach in many modern computing environments where it is possible to work in Python.
5 – The fact that I mainly work with statically typed languages is not insignificant. Often, I forget that habits have to change when switching to Python.
6 – Not counting the rather niche modules aimed at hobbyists.
7 – In addition, in one of these projects, Python was used to write the servers that manage and test the devices (including the generation of a simple HTTP interface for testers), and in the other C# was used to analyze the telemetry data collected from the running devices.
8 – The 2022 survey is available here: https://survey.stackoverflow.co/2022/
Written by: Tomasz Przedziński,
Software Architect

Born in ‘86, graduated with a master’s degree in Applied Computer Science from Jagiellonian University in Krakow. He received his Ph.D. in Software Engineering from the AGH University of Science and Technology. He specializes in C++ but has developed a strong liking for embedded environments. His fondness for algorithmics and solution optimization is no secret. Quality, building advanced test environments, or extending existing ones in his professional work are his main focuses.

CONTACT US
Complete
the form below.
We will contact you to set up
a conversation at the convenient
moment for you.