The morning begun as you hoped it would of. I was done with a new feature before I finished my coffee. My work output was amazing and climbing even higher. At the time, I was unaware of what was about to set me back. It took the issue only a couple hours to appear.
However, finding the core of the problem required a lot of time and effort. The fix required all my day. I was new to all of this back then. I learned an important lesson that day. I will not make that mistake in Python again. Can you relate to this? If so, then I have some tips that should help reduce your mistakes and save you a bucket of time.
Functions with Side Effects
Since Python is no 100% a functional language like Haskell, functions can make side effects. I would not call this a mistake, but it is easy to unintentionally mess things up. Being aware of these side effects can help you better predict the outcome of your code.
In Python, objects are reference types. So, when you pass a list as an argument, a reference is passed instead of the value. This suggests that if you change them in a function, the changes will be reflected outside. This can lead to some weird and nasty surprises and too much time debugging. The best approach is always to write clean code, even if it takes you a lot longer because debugging always takes a lot longer.
Functional Calls in Default Arguments
Default arguments can be difficult to use sometimes. You could easily find yourself in a situation where the return value is the same for every cell. The reason is that Python evaluates the expressions in default arguments when the function is defined. If you want to dynamically generate default arguments, you will want to take a different approach. Be careful with how you lay out default arguments.
Mutable default Arguments
This problem is a combination of the two above. Have you ever found yourself in this situation? There are a couple things happening here. Python evaluates the expression [ ], which is a common expression in these kinds of arguments, when the function is defined. Think of it as if you are using the list( ) expression. So, using mutable objects as default arguments is not a good idea. Avoid that at all costs.
Joining Paths with String Concatenation
Suppose you have to open a file called data.csv from the folder given by the variable data_folder. How should you determine the file path? If you are doing data_path = data_folder + “/data.csv”, then you are not doing it correctly. This would not work on Windows, which is the most popular operating system so you probably are using Windows. You might not of had this issue yourself, but your colleagues using different development setups will find this frustrating. To fix this, you should use pathlib, Python’s built in tool, or use the os.path.join function.
Low Test Coverage
This is a massive issue. Especially when you are just getting your feet wet in Python professionally, the benefits of unit testing is not clear. However, every experienced programmer can tell you that it is critical. Working with untested code is like playing whack-a-mole: fix one bug, bring in another one.
Avoiding this starts right away. The second you boot up your development program of choice you should add a feature (or a function), you should write test cases to validate the implementation. There are a ton of great libraries that can help with this. Unittest and pytest are two of the most popular.
To summarize, we have all been there with Python, mistakes happen but the best way to reduce mistakes is to listen to more experienced developers and learn from their time in the development workflow. And test your code as often as possible. It will reduce so many headaches when you are trying to implement anything. You will thank us later.