Programming languages are tools we use to solve problems. Yet most programmers transition from one language to another expecting these tools (programming languages) to behave like their previous languages. i.e why does language X not behave like language Y . Well my answer to that is quite simple. If you transition from English to Ga, you will obey the rules of Ga if you wish to communicate effectively. So don’t be too caught up in language wars and use the constructs if need be.
Below are three peculiarities I found when I started using python but in time I began to appreciate and use them.
try … except … else
The first time I came across this I felt one of the laws of nature had been broken. Why would one use exception handling as a means for flow control? In time, I realised there are situations where you need code to run only if the block of code within the try does not fail and unlike the way I would handle it in other languages, I’ve come to love python’s approach.
An example of such a case is manipulating a database object if successfully retrieved.
Using try … catch … else
# using Python 3 and Django 🙂
# try ... except ... else example
import logging
logger = logging.getLogger(__name__)
def un_publish(blog_id)
try:
blog = Blog.objects.get(pk=blog_id, is_published=True)
except Blog.DoesNotExist as e:
logger.info("blog with id {} does not exist".format(blog_id))
logger.error(e)
else:
blog.is_published=False
blog.save()
return blog
Using try … catch without else
# using Python 3 and Django 🙂
# try ... except ... example no else
import logging
logger = logging.getLogger(__name__)
def un_publish(blog_id)
# in order to prevent the if blog condition from failing, blog must be defined either before the try block or in the except blog
blog = None
try:
blog = Blog.objects.get(pk=blog_id, is_published=True)
except Blog.DoesNotExist as e:
logger.info("blog with id {} does not exist".format(blog_id))
logger.error(e)
if blog:
blog.is_published=False
blog.save()
return blog
In the second code snippet you would realise there is more code, and the worst part is- as a developer I have to remember the state of blog in the whole process. Perhaps it’s just me but I’ve come to love the first approach 🙂 If you won’t take my word for it read this
Inner Functions
In most cases this peculiarity will be called differently, but for our purposes I’ll stick with inner functions
.
The very first time I came across this was whilst reading a colleagues code at work and I thought to myself, “wow you can do this in python!?”. I could not really find a use case for ever using this peculiarity in my code except when I was developing decorators. In some rare cases, you have a piece of code which repeats itself within a function and it’s only needed within that said function. You could use an inner function to solve this problem.
An example could be adding empty rows to a csv file based on specific conditions.
def generate_report(start_date, end_date):
# do sales report stuff
sales = Sale.objects.filter(start_date=start_date, end_date=end_date)
number_of_empty_columns = [""]
for sale in sales:
if sale.number_of_items == 3:
number_of_empty_columns = [""] * 3
elif sale.number_of_items == 2:
number_of_empty_columns = [""] * 2
In the code above, the number_of_empty_columns
could be generated with a function and since this code will only be needed within the generate_report,
there is no need to write this piece of code outside the generate_report
.
def generate_report(start_date, end_date):
def gen_empty_strings(number):
"""
This method generates a list of empty strings based on the number provided
:param - number is the number of empty strings to be returned
"""
return [""] * number
# do sales report stuff
sales = Sale.objects.filter(start_date=start_date, end_date=end_date)
number_of_empty_columns = gen_empty_strings(1)
for sale in sales:
if sale.number_of_items == 3:
number_of_empty_columns = gen_empty_strings(3)
elif sale.number_of_items == 2:
number_of_empty_columns = gen_empty_strings(2)
Although the above code is a simplified use case of inner functions, inner functions can make code cleaner and easier to maintain, but over using it could make code harder to read. Some thoughts on inner functions in python:
https://softwareengineering.stackexchange.com/questions/232766/when-to-use-python-function-nesting
https://stackoverflow.com/questions/1589058/nested-function-in-python
Dictionaries as switch cases
In case you have not noticed, python has no switch cases for control flow, so most programmers resort to lengthy if statements. What if I told you that the pythonic way to create switch cases is to use a dictionary. Don’t believe me, follow the code below:
# Assuming you needed to show a different kind of menu to different kind of users. You will realise a switch-case may be cleaner than a series of if-statements:
# Note this is demo code.
def customer_menu():
print("welcome customer")
# do customer menu stuff
def admin_menu():
print("welcome admin")
# do admin menu stuff
def sales_menu():
print("welcome sales rep")
menu = {
'customer': customer_menu,
'admin': admin_menu,
'sales': sales_menu
}
# To call a specific menu
selected_menu = menu.get('customer', lambda: "Invalid menu choice")
selected_menu()
Perhaps my love for using dictionaries in place of switch cases may be a sign of Stockholme Syndrome 🙂