COMP1531
3.2 - Python - Pythonic
Being Pythonic
Being "Pythonic" means that your code generally follows a set of idioms agreed upon by the broader python community.
"When a veteran Python developer calls portions of code not “Pythonic”, they usually mean that these lines of code do not follow the common guidelines and fail to express its intent in what is considered the most readable way. On some border cases, no best way has been agreed upon on how to express an intent in Python code, but these cases are rare."
Examples
- Docstrings
- Map, reduce, filter, lambdas
- Exceptions > Early returns
- Destructuring, ignored variables
- Enumerate
- Multi line strings
Docstrings
Docstrings are an important way to document code and make clear to other programmers the intent and meaning behind what you're writing. We are somewhat different on the formatting, but we want it to include 1) Description, 2) Parameters, 3) Returns
def string_find(str1, str2):
""" Returns whether str2 can be found within str1
Parameters:
str1 (str): The haystack
str2 (str): The needle
Returns:
(bool): Whether or not str2 could be found in str1
"""
docstring.py
Map, Reduce, Filter
- Map: creates a new list with the results of calling a provided function on every element in the given list
- Reduce: executes a reducer function (that you provide) on each member of the array resulting in a single output value
- Filter: creates a new array with all elements that pass the test implemented by the provided function
Map
Map: creates a new array with the results of calling a provided function on every element in the calling array
def shout(string):
return string.upper() + "!!!!"
if __name__ == '__main__':
tutors = ['Simon', 'Teresa', 'Kaiqi', 'Michelle']
angry_tutors = list(map(shout, tutors))
print(angry_tutors)
map.py
Reduce
Reduce: executes a reducer function (that you provide) on each member of the array resulting in a single output value
from functools import reduce
def custom_sum(first, second):
return first + second
if __name__ == '__main__':
studentMarks = [ 55, 43, 34, 23, 22, 10, 44 ]
total = reduce(lambda a, b: a + b, studentMarks)
print(total)
reduce.py
Filter
Filter: creates a new array with all elements that pass the test implemented by the provided function
from functools import reduce
if __name__ == '__main__':
marks = [ 65, 72, 81, 40, 56 ]
passing_marks = list(filter(lambda m: m >= 50, marks))
total = reduce(lambda a, b: a + b, passing_marks)
average = total/len(passing_marks)
print(average)
filter.py
Combined
from functools import reduce
if __name__ == '__main__':
marks = [ 39, 43.2, 48.6, 24, 33.6 ] # Marks out of 60
normalised_marks = map(lambda m: 100*m/60, marks)
passing_marks = list(filter(lambda m: m >= 50, normalised_marks))
total = reduce(lambda a, b: a + b, passing_marks)
average = total/len(passing_marks)
print(average)
allthree.py
Exceptions > Early Returns
You might be quite familiar with early returns:
def sqrt(num):
if num < 0:
return None
return num ** 0.5
myNum = int(input())
if sqrt(myNum) is not None:
print(sqrt(myNum))
early.py
The problems though are:
- Often we can only use "None" or some arbitrary return (-1) to signify that it didn't work
- It's harder to check for a client using it
Exceptions > Early Returns
So we use exceptions. And we can make our own.
class SqrtException(Exception):
pass
def sqrt(num):
if num < 0:
raise SqrtException("Number cannot be < 0")
return num ** 0.5
try:
print(sqrt(int(input())))
except SqrtException as e:
print(e)
early.py
Destructuring
Being able to make tuples and destructure them is very powerful. If you don't want all tuples you can use blanks to ignore them.
import math
def convert(x, y):
return (math.sqrt(x**2 + y**2), math.degrees(math.atan2(y,x)))
if __name__ == '__main__':
print("Enter x coord: ", end='')
x = int(input())
print("Enter y coord: ", end='')
y = int(input())
mag, dir = convert(x, y)
print(mag, dir)
mag2, _ = convert(x, y)
print(mag2)
destructure.py
Enumerate
Sometimes we want to iterate cleanly over the values in a list, but also know what index we're up to. In these situations the enumerate built-in is useful.
tutors = ['Vivian', 'Rob', 'Rudra', 'Michelle']
for idx, name in enumerate(tutors):
print(f"{idx + 1}: {name}")
enumerate.py
Multi-line strings
Someones strings need to exist over multiple lines, there are two good approaches for this
if __name__ == '__main__':
text1 = """hi
this has lots of space
between chunks"""
text2 = (
"This is how you can break strings "
"into multiple lines "
"without needing to combine them manually"
)
print(text1)
print(text2)
multiline.py
COMP1531 21T1 - 3.2 - Python - Pythonic
By haydensmith
COMP1531 21T1 - 3.2 - Python - Pythonic
- 429