Advance Your Python Skills
10 Idiotic Ways to Refactor Your Python Code
Make your Python code more readable and performant
Jul 3 ·7min read
Python is a general-purpose programming language that is widely used in scientific computation, artificial intelligence, web development, financial modeling, and many other areas. One major reason for its popularity is its flexibility of having multiple solutions for various operations. However, in most cases, there is one possible idiotic solution that is preferred among seasoned Python programmers. In this article, I would like to review 10 idiotic cases that you can consider using to refactor your Python code.
1. Comprehensions
There are three common mutable container data types in Python, including lists, dictionaries, and sets. If we start with an iterable, we can use a for loop to go over the iterable using the for loop to create a new list from it. However, the idiotic way is to use list comprehension, which has the following syntax: [expression for x in iterable if any_condition]
. Note that the conditional evaluation part is optional. Let’s see the following code.
Besides the list comprehension, we can also use comprehension for dictionaries and sets, which are termed dictionary comprehension and set comprehension, respectively. The dictionary comprehension has the following syntax: {key_expr: val_expr for item in iterable}
, while the set comprehension’s syntax is: {expr for item in iterable}
. The following code shows you their usages.
2. F-Stings
Strings are a common primitive data type that we use in almost all our projects. To display string data, in most cases, we need to take a step further by formatting strings in a specific way. We can do the string formatting with the C-style method which involves using the % symbol or the format method of Python strings.
However, in recent releases of Python, the new string formatting method has been introduced. It’s known as the f-strings, which stand for formatted string literals — a concise and readable way to format the strings. Let’s see the comparisons between these different formatting approaches.
Certainly, the above code only shows you the very basic usage about f-strings, which in fact implement almost all formatting styles that are supported by the C-style or the string’s format method. You can read more about f-strings in the official documentation or in my recent article .
3. Multiple Assignment and Tuple Unpacking
When we work with variables, it’s a common practice that we define one variable in each line. However, when we’re declaring multiple variables, we can do that in a single line. Please note that to avoid confusion, you may want to declare variables that are semantically related. If they serve distinct purposes, I wouldn’t recommend doing that. Let’s see the refactoring below.
Under the hood, the multiple assignments involve the creation of a tuple on the right side and unpacking of the tuple on the left side. The following code shows you how to unpack a tuple. As you can see, it looks like multiple assignment, because they’re using the same mechanism.
4. Catch-All Unpacking
In the above section, we reviewed how to unpack a tuple using the most basic format — the same number of variables to denote each of the elements in the element. However, when there are multiple elements in the tuple, sometimes you may want to unpack it using the catch-all method. Specifically, all the elements that are not explicitly denoted by variables will be captured by the variable with an asterisk prefix. To achieve the same result, the non-idiotic method usually involves slicing, which is error-prone if we miss the correct indices.
As you may notice, the values of middle_numbers0
and middle_numbers1
aren’t equal. It’s because that the catch-all unpacking (using the asterisk) generates a list object by default. Thus, to make the final unpacked data have the same data type, we can use the tuple constructor, as shown below.
5. Assignment Expression
The assignment expression is better known as the walrus expression using the walrus operator :=, which looks like a walrus with a pair of eyeballs and tusks, doesn’t it? As indicated by its name, assignment expression allows you to assign a value to a variable and in the meantime, it can be used as an expression, such as in an if statement. The definition sounds confusing, and let’s see its usage in the following code snippet.
As shown above, when we don’t use the assignment expression, we have to get the account number first and use it to for the money withdrawing operation, which creates some code duplication. By contrast, we can eliminate one line of code by assignment expression, which calls the function and assigns the returned value to the new variable to be evaluated in the meantime.
Some people may argue that saving one line of code doesn’t matter too much, but it makes our intention more clear that the variable account_number
is only relevant in the scope of the if statement. If you have coding experience in Swift, the usage of assignment expression in the if statement is pretty much like the optional binding technique, as shown below. Basically, the temporary variable accountNumber
is only used in the subsequent scope when it's valid. Thus, you should get familiar with assignment expression, and after a while, you’ll find the code more readable.
6. Iteration with enumerate
In almost every project, we inevitably make our program repeat particular operations for all the elements in a list, tuple, or some other container data types. These repeated operations can be achieved with the for loop. Normally, we can use the basic form: for item in iterable
. However, for the iteration, if we need to track the count of the current iteration loop, it’s better to use the enumerate
function, which can create the counter for us. Moreover, we can set the number at which we can start the counter.
7. Join Iterables With zip/zip_longest
Suppose that we start with two iterables, and we want to join these two iterables for each corresponding pair of elements. Typically, we can use the indexing method by retrieving the elements from each iterable such that we can join them to form a dictionary. However, Python has the built-in function zip , which does exactly what we want to achieve. Basically, the zip function takes multiple iterables, and create an iterable of the length that matches use the shortest length of the iterables. Let’s see the following example.
What’s the zip function does is to create an iterator zip object with each element as a tuple consisting of items from the supplied iterables. One thing to note is that by default, the zip function will stop when it reaches the end of any iterable. By contrast, the zip_longest function will use the longest iterable.
The above idiotic way is taking advantage of the dict constructor being able to use an iterable to create a dict object. Besides the above usage, the zip object can be directly used in an iteration, as shown below.
8. Concatenate Iterables
In the above example, we used the zip function to join the iterables element-wise. What should we do if our specific business need is to concatenate iterables? Suppose that we need to go over two iterables of elements of the same category for the same operation. We can achieve this functionality by using the chain function. Let’s see the usage below.
As shown above, the non-idiotic ways need the creation of extra lists, which are not the most memory-efficient. By contrast, the chain function creates an iterable from these initially defined iterables. Moreover, the chain function is flexible and it can take any kinds of iterables, which means it can take dictionaries, sets, lists, zip objects, map objects (using the map function), and many other kinds of iterables in Python.
9. Ternary Expression
If we need to assign something to a variable, different values will be assigned based on the condition. In this case, we can use the if statement to evaluate the condition and determine what value to use for the assignment. This typically involves several lines of code. However, we can use the ternary expression to get the job done with just one line of code, which has the following general syntax: var = true_value if condition else false_value
. Let’s see their respective usages.
10. Use of Generators
The concept of generators can be unfamiliar to those people who are new to Python, because it’s not a common technique in many other programming languages. It’s a neat trick to allow you to work with a stream of data without the need of establishing the stream at front. Instead, the generator yields the next value when it’s asked to do so, which is very memory efficient.
Consider the following trivial example. Suppose that we need to process tons of data in a file. Theoretically, we can read the entire file to a list and process each row of the data in the list. However, it’s entirely possible that your computer can run out of memory when the file is enormously large. Instead, the better and more idiotic solution is to make a generator from the file, which yields only one row of data each time at demand.
Conclusions
There are many more idiotic ways to do various kinds of things in Python, and the topics covered in this article is just an incomplete list of tricks that I find useful in my daily projects. I hope they can help you write Python code too. A final tip is that you’ll have to purposely refactor your code using these and other idioms, which are usually more performant ways. By refactoring your code consistently, you will gradually improve your Python coding skills.
Thanks for reading this piece and happy coding.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。