Handy Python Snippets for Cleaner Code
Dynamically call a function, list functions with a specific part of their name, and more
Refactoring existing code effectively is an art. If you have ever inherited someone else’s code or even looked back at your own after some time, you know how trying this process can be. Oftentimes, features are made and bugs get fixed under tight timelines, which can lead to sloppy, inefficient code.
That’s completely fine. You’re allowed to commit some bad code from time to time. What is imperative is that you can identify the bad code and always return to fix it.
In this article, we’re going to look at some small segments of Python code that make refactoring for cleaner code easier. In most cases, these use simple, standard library functions and don’t obfuscate intent behind exceedingly complex algorithms or dense one-liners. When you’re refactoring code, you want a good balance between being concise and readable. Let’s take a look at a few examples.
Dynamically Calling Functions
klass = MyClass()
return getattr(klass, name)()call_func('function_name')
If you encounter sections of code where you won’t necessarily know the name of a function you wish to invoke until later, this is the answer. By using the built-in Python function
getattr, you can call a function by name using a string. This is great for reducing tightly coupled code and improving extensibility. If you reduce hard-coded function names and allow more flexibility, then there is a strong chance your code will break less.
Using this simple method also reduces the overhead for other developers to add functionality to existing code. If all you have to do is add a new function to a class and it becomes immediately usable, that reduces complexity and makes code easier work with.
You can read more about the
getattr function in the documentation.
Using Destructuring Assignment
var_one, var_two = [1, 2]
You’ve probably heard about this concept a million times before, but it bears repeating: Use destructuring assignment where possible to display values and convey intent more clearly. When you access a list or an array by index values, you inadvertently hide your intent. Referencing values by a clear variable name assigned through destructuring assignment makes your code easier to read.
In the example below, we have some data about a person on a list. This data includes basic information like the person’s name, age, and profession. Let’s assume for the sake of this example that this is part of a response we received back from a web request and that we’d have to parse multiple responses just like this. If we wanted to get the person’s name, we could simply access it by the index value:
person = ['Bill', 26, 'Programmer']print(person)
This is sloppy and hides intent if you ever reference it more than once. Referencing
person all over the place in your code will make it difficult to interpret what value that should be. There is a very simple fix for this that does not hide your intent and makes your code more readable. Simply assign this to a variable and, if possible, destructure the entire list into appropriately named variables as well. Let’s look at an example of putting this into practice:
person = ['Bill', 26, 'Programmer']name, age, profession = personprint(name)
Now if you need to reference the name later, you will be doing so via a named variable vs. an index value. This works well for response data that you’ll likely know the structure of. As long as the person’s information is always in the same order, you can destructure and assign everything over and over again to avoid using index values.
Listing Functions With a Specific Pattern
In this example, let’s assume we have the class above containing a large number of functions. Some of these functions serve a special purpose and should be dynamically accessible. We want any special function that we add to this class to be immediately picked up by the rest of our code so that it begins working right away. One way to accomplish this is simply by using
dir on the containing class.
If you pass a class to
dir, it will list all of the attributes for that object. This includes the names of its functions. By filtering for a prefix, suffix, or included keyword in the string name, we can group the functions of this class into different categories. This allows us to “pick up” new functions whose names include a keyword and either call them all or perform other logic with them later on in the code.
Check out more on the built-in
dir function in the docs.
Passing Multiple Function Arguments as a Dict
There is a strong chance that you’ve come across something similar to this before while refactoring code:
Although certain formats of this indentation style might technically be allowed in PEP8, I personally do not enjoy looking at heavily indented function arguments. You are forced to move your eyes all the way over to the right, some IDEs don’t play nice with this indentation, and using this style inhibits future extensibility.
One option to consider for improving readability and reuse when there are a lot of function arguments is to pass them in dict form. Here is an example of this:
** operator on the dict as you’re passing a dict to the function allows you to unpack all of the arguments successfully (instead of accidentally passing the dict object itself). Although this method does add another variable and a separate data structure, it improves overall readability when there are a larger number of arguments. Moving the function call around or referencing multiple calls to the same function with the same (or slightly tweaked) arguments now becomes infinitely easier and requires less overall modification.
Thank you for reading! I hope these code snippets will help improve your efficiency the next time you find yourself picking apart some Python code.