Home TechnologyCoding Learn To Write Beautiful Python Code

Learn To Write Beautiful Python Code

Improve your Python skills by beautifying your code

by Ivan
learn beautiful python code

To remain relevant as a python programmer, It is important to constantly improve your programming skills – and learning to write beautiful code should be part of your upskilling repertoir.

One of the most daunting aspects of being a python programmer is the sheer amount of skills to learn. Whether you are just beginning your programming journey or you are already on your way to becoming a competent software engineer, working to continuously improve your knowledge and skills is always important. Since computer science advances so quickly with languages and frameworks coming in and out of style, the need to learn new skills never really goes away.

I personally found that after I graduated from university I had to ensure I set aside time to continue broadening my programming knowledge. Although I started to gain valuable skills at work, I didn’t want to begin forgetting topics from school that my current job didn’t require me to use very often. Even when I was in school, going beyond the assigned homework helped me improve faster. In this post, I will discuss the topics and strategies that helped make me a stronger programmer and how you can use them to improve your Python programming skills.

Pay Attention To Data Structures

Algorithms and Data Structures are two of the most important areas to understand to become a strong programmer. While it is true that you can find an implementation of pretty much any algorithm or data structure on the internet, having a robust understanding of how they work allows you to solve problems more effectively. When it comes to nailing a technical interview or impressing your boss, the ability to look at a new problem and come up with a viable solution quickly is critical. Oftentimes, having a deep understanding of commonly used algorithms and data structures makes solving problems much easier.

Python is an interesting language because it is super easy to use built-in functions and libraries to abstract away a lot of the things we would do manually in other languages. Many universities start students off with a language like c++ because it forces them to learn things like how memory allocation works alongside a more rigorous syntax. However, it is more and more common for students to begin with Python since it has so much utility in a broad range of topics like data science, web development, and software engineering.

Data Structures

Since Python has so many useful data structures already implemented and easily accessible, understanding which situations to use a specific data structure is important.

Choosing a data structure depends on the quantity of data you are working with, how you want to access it, and how fast you need your code to run. Some data structures are very fast with certain operations, but may not support other operations at all. A Python dictionary, which is a built-in implementation of a hash table, is fast when it comes to inserting or finding an item; however, there is no way to slice or sort a dictionary. This means that a dictionary can be a great choice for tasks involving lots of unique data points that need to be queried frequently, but a poor choice if the order of the data matters.

Python also has access to libraries, like Numpy, which uses C to produce faster and more efficient data structures. A good example of this is Python lists versus Numpy arrays. In some cases a Numpy array and a list are interchangeable, however when your data is homogenous — all the same type — an array can save you time and memory. The code below creates a list and a Numpy array of equal length and then adds two to each element; take a look to see how fast Numpy can be compared to lists.

import numpy as np import time size = 1000000 # Create array and list npArray = np.arange(size) pyList = [i for i in range(size)] # Add 2 to each element in list startL = time.time() pyList = [i+2 for i in pyList] endL = time.time() print("It Took {} seconds to add two to each element in our list." .format(round(endL-startL,5))) # Add 2 to each element in array startA = time.time() npArray += 2 endA = time.time() print("It Took {} seconds to add two to each element in our array." .format(round(endA-startA,5)))
It Took 0.03738 seconds to add two to each element in our list
It Took 0.00026 seconds to add two to each element in our array

We can see that the Numpy array with the same number of integers can be altered much faster than its list counterpart. This efficiency comes at the cost of flexibility, though. A Python list can store a mix of data types and is easier to append elements to than Numpy arrays. Numpy does offer some operations that aren’t easily achieved on a Python list without needing loops, but Numpy is designed specifically for math and isn’t meant to handle a variety of data types like a list can. Hopefully, this example shows just how much thought can go into when to use the many data structures available to you in Python.

Look at Code on Github

While it is important to work on ideas of your own, learning to look at code written by other programmers and understand what it is doing is a very important skill to master. There will be many times throughout your career when you are handed a program written by a past developer and expected to upgrade or maintain it going forward. Depending on the developer that came before you, this task can range from simple to extremely difficult. Since Python is a very flexible language there are often many ways to solve the same problem with a range of syntax options available. Sometimes developers focus more on being succinct at the cost of readability, and if they aren’t available to explain their thought process it can take much longer to update their code.

This may sound like a difficult skill to practice, however, languages like Python with thriving open source communities offer ample opportunity to explore the code of experienced developers through the libraries they publish. As you make use of more libraries like Numpy, Pandas, and smaller libraries it can be very beneficial to get on GitHub and try to understand how they implement the functions you use. While some of the larger libraries — Numpy — can be overwhelmingly large, there are a plethora of smaller libraries that are easier to start with.

There is also a good chance you may find bugs or inefficiencies in the functionality of libraries that you use in projects; this is the primary reason that GitHub has an “Issues” tab. If you find a bug, you can go much further than simply reporting it by fixing it yourself and proposing the changes you made as a pull request. Since most Python libraries are developed by volunteers it can be massively helpful when a community member offers a solution to a bug. Finding bugs can be harder than it sounds, and users are often the ones that find edge cases that weren’t anticipated by the developers. The maintainers of the library can merge your changes into their codebase or discuss the bug and proposed solution with you to come up with the best solution possible.

Finally, you don’t have to have a bug to submit a pull request to a repository. If you find a project that interests you, feel free to propose improvements that come to mind as you use their software. Contributing to projects that you enjoy using is one of the best ways to support the open source community that has made Python such a powerful language to use.

Always be Looking For Ways to Optimize

As you work on a project, think about ways you could solve steps more efficiently. Python has access to so many tools and there are often several ways to solve the same problem. However, some of the methods will often be faster than other options. Since we often use Python to work with increasingly large datasets, improving the speed of your code can significantly reduce the amount of time you wait as you work and test.

Even if your current project doesn’t need to be efficient, learning how to write lean and fast code will make future projects that have more limited resources much easier. When I first started developing Python code for web apps, it quickly became apparent how easy it is to create bloated Python programs and how much faster certain tasks can be made with the right methods.

Use The Right Tools

As we saw when comparing Python lists to Numpy arrays there are often multiple ways to solve a problem, but each method will have certain advantages. Another good example can be found with making good use of Python’s built-in functions, which often are written in C to be much faster.

As an example, I’ve imported a list of just over 230,000 words using the nltk library. If I want to make every word uppercase I could loop through the list and call .upper() on each one. One step better is to use a list comprehension to make our loop a little more efficient. But the fastest option is to use Python’s built-in map() function to apply .upper() to each word in the list.

import time from nltk.corpus import words word_list = words.words() print("Our list contains {} words n" .format(len(word_list))) start0 = time.time() upper_list0 = [] for i in word_list: upper_list0.append(i.upper()) end0 = time.time() print("It took {} seconds using a for loop" .format(round(end0-start0,5))) start1 = time.time() upper_list1 = [x.upper() for x in word_list] end1 = time.time() print("It took {} seconds using list comprehension" .format(round(end1-start1,5))) start2 = time.time() upper_list2 = map(str.upper, word_list) end2 = time.time() print("It took {} seconds using 'map'" .format(round(end2-start2,5)))

Our list contains 236736 words

It took 0.03233 seconds using a for loop
It took 0.01148 seconds using list comprehension
It took 2e-05 seconds using 'map

While map() can’t be used in every situation, it is incredibly well optimized for tasks it can be used for. List comprehensions also have a significant speed boost over a traditional for loop while being more flexible than map().

Dependency Bloat

Many Python libraries are large and having to load in a large dependency only to make use of one function can add unnecessary size to a project. One of my first web apps asked the user for a location, how far they were willing to drive, and how far they wanted to hike. The Python program would grab all of the trails located within the driving radius and then solve for a loop closest to the desired length. Since so many trails cross each other in states like Colorado, our idea was to make a fun app that helped us find longer hiking trips in specific areas.

Designing the Python app to create a network of trails and then solve for an optimal loop was fun, and I learned a lot about graph algorithms. The hard part came when I tried to move it to the cloud. It’s expensive to host an AWS instance that is always running and waiting for someone to interact with the website, especially for a small project that will sit idle more often than it’s in use. So I went with a serverless approach, where a small instance is spun up whenever the website makes a request. I ended up choosing AWS Lambda for the serverless backend and it worked really well.

The only problem was that the code was too heavy for Lambda. I managed to optimize the graph solve to make the code fast enough, however, I had too many dependencies and exceeded Lambda’s strict size requirements for the environment. Loading in lots of libraries like sci-kit learn, NumPy, Pandas, and Scipy make for a large environment. Luckily I was able to refactor the code to use functions from a smaller pool of libraries. It’s great that it worked out, but it was a good lesson to consider how problems can be solved with libraries I’m already using rather than importing a new one every time I have a challenging task to figure out.

Practice, Practice, Practice

I find that the most important step to take to improve your skills as a developer is to practice consistently. There are a plethora of ways to practice programming like working on a personal project that interests you or setting aside time to learn new skills that you don’t use in your current job. It is also important to continue to pay attention to fundamental skills that may not be used every day, like algorithms.

Websites like Leetcode that present you with specific challenges to solve with constraints on speed are a great way to consistently challenge yourself. I also find Leetcode to be a way to make challenging myself a little more fun since it gives me a sense of reward when my code passes the test cases.

Don’t forget to increase the difficulty gradually if you are still new to programming. It can be frustrating to practice the fundamentals when you want to build cool apps and work on bigger projects. While it’s great to be ambitious, make sure to increase the difficulty of your work gradually. Nothing makes learning harder than getting overwhelmed or frustrated, and you’ll have a much easier time if you break down your learning into more manageable chunks.

This doesn’t mean you shouldn’t tackle a cool idea you have. But as you run into new challenges, it can help to take a step back and spend extra time really learning the new topic versus copying something off of Stack Overflow and seeing if it works. There are certainly times to just get the code to work, but in order to really improve it’s best to take the time to really comprehend what you find while Googling to solve your problem.

You may also like

Leave a Reply

[script_16]