Easy ways to make your python code more Concise and efficient!
I just wanted to share some tricks to make code more concise and more efficient that are really simple to implement
F-Strings
F-Strings come in really handy when you need a clean way to use strings with variables, and to format them!
If you want to make your strings and prints look much cleaner, and perform better, F-strings are by far the easiest way, lets say we have some variables:
name='bob'
address='123 Park Place'
Hours=(9,17)
A lot of people would print it like this:
import random
print('Hello '+name+',\nwe have a package to deliver to you at '+address+', If it is alright with you, we will be dropping your package off at '+str(random.choice(list(set(range(24))-set(range(*Hours)))))+' oclock')
While that approach certainly works, It looks quite a bit cleaner to use F-Strings
An F string is declared by putting an f before quotations like f''
or f""
, all you have to do to get your variables in your string, is to wrap them in brackets within those quotations, I.E f'Hello, {name}'
, If we were to do what we did above with F-strings this is how it would appear:
print(f'Hello {name},\nwe have a package to deliver to you at {address}, if it is alright with you, we will be dropping youre package off at {random.choice(list(set(range(24))-set(range(*Hours))))} oclock')
And lets say we are just making a program that says hi,
name=input()
print('hello, '+name+' how are you doing')
print(f'hello, {name} how are you doing')
The f-string looks quite a bit cleaner, and also allows you to use formatting to do things like this:
print(f'{"hello":->10} {name},\n how are you doing')
The :->10
just means,
(:
means this is going to format)
(-
Can be any character you want to be used as padding (or none at all))
(>
implies which direction, you can also use ^
or <
)
(10
is how much to pad it by, doing a higher number would move it further)
Lambdas, Maps, Listcomps, Zips, and Filter, and Enumerate (tools for iteration)
Listcomps and maps
One of the easiest ways to make your code more precise, and potentially faster is with the use of These handy functions and loop syntax,
Lets say that we are trying to remove all odd numbers from a list of numbers that have been converted to strings, The long way to accomplish this would probably be something along the lines of this
list1 = ['0', '7', '21', '3', '0', '8', '13', '10', '21', '8', '19', '17', '3', '5', '2', '18', '18', '2', '15', '13', '20', '1', '22']
#list for the converted strings
list2=[]
for num in list1:
#check if even
if int(num)%2==0:
#add to final list
list2.append(int(num))
That method is definitely Great, but it can be vastly improved upon with something called a list comprehension, a list comprehension is essentially the concise version of the code above. A list comprehension is always enclosed in brackets, always iterates over something and always returns a list, here are a few examples of the syntax in different scenarios:
If you want an if else, this is the syntax:
newlist = [<output> if <condition> else <output> for item in iterable]
#an example of this in use
evenodd=['even' if number%2==0 else 'odd' for number in range(30)]
What is happening here is that it checks the conditional every time it iterates over an item, and the output is what will appear in the position it was on in the old list.
The next syntax style is when you only want items if a certain condition is true, I.E We only want to keep the item if it has a 'b' in it
l=['bad','bass','oops','fish','salt','bin']
onlybs=[text for text in l if 'b' in text]
#^the code above basically goes through these steps
#for every text in the list
#if there is the letter b in text
#add that text to the new list
#That listcomp is equivelant to this:
newl=[]
for text in l:
if 'b' in text:
newl.append(text)
Now that we now how to use listcomps,our adjusted odd remover would like this:
list2=[x for x in list1 if int(x)%2==0]
In that specific case, converting to an int before checking if it was even was fine, but in some situations, youl end up needing to convert the whole list before you iterate, which is where maps come in. ap is a function that needs a function, and an iterable, and all it does is apply that function to every iterable. There is one caveat to maps though, the first one being that it doesnt actually store all the values until converted to a list, or iterated over, and the second one being that due to its unique implementation, it is quite a bit faster then listcomps when given a builtin method I.E
#map(function,iterable)
strin=map(str,range(50))
print(strin)
print(list(strin))
what we did there was apply str() to every item in range(50), which is a concise and easy way to convert large amounts of items types.
zip, enumerate and filter
enumerate
A lot of times when iterating, knowing which index you are on is useful, and thats exactly what enumerate is for. Simply all it does is simplify counting which index you are on.
c=0
for x in range(50):
print(x)
c+=1
#this can be done with enumerate like this
for index,item in enumerate(range(50)):
print(f'{item} is at {index}th index')
What enumerate does is take an iterable, and create a new one that is a list of tuples where the first item is the index, and the second item is the actual part of the itarable. when iterating over an enumerate, it is best to unpack it into two variables. Her is a real world use case for enumerate:
def findall(iterable,target):
res=[]
for index,item in enumerate(iterable):
if item==target:
res.append(index)
return res
in listcomp form:
def findall(iterable,target):
return [count for count,item in enumerate(iterable) if item==target]
filter
lets say we want to remove all digits from a string, this could be done with a listcomp or a normal loop, But filter can do it much more concisely
lol='eufu803fnhanus830j'
rmdigit=''.join([x for x in lol if x.isdigit()==False])
rd=''.join(filter(str.isalpha,lol))
Just like maps, filter is only better than a listcomp performance-wise if it is using a builtin function
Zips
lets say we have a list of cars, a list of their colors,a list of their model numbers, and a list of their years, and we want to have all of them together, the best way to do this is with the zip function, instad of iterating over all the lists.
name=['corola','tokoma','aventador','focus']
numb=[334,556,7778,3321]
colors=['green','beige','grey','pink']
years=[2020,2019,2021,2013]
cars=zip(name,numb,colors,years)
#as apposed to
cars2=[]
for x in range(len(name)-1):
cars2.append(name[x],numb[x],colors[x],years[x])
Although the zip doesn't seem much shorter, than the naive method, it does a lot more in cases where lists could be uneven. It automatically accounts for the lengths of the iterates which means it wont error if one is longer than the other. Another great use of zips is in portioning out an iterable
i.e:
foo=[1,4,5,7,83,3,13,56,6]
#we want to divid it into sections of 3
bar=zip(foo[::3],foo[1::3],foo[2::3])
Lambdas
Though lambdas dont really have anything to do with iterables, they are quite often used within maps filters and other things. Basically a lambda is a mini one line function Here is how you define one:
<name>=lambda <parameters>:<what to spit out>
I.E
printdown=lambda s:print('ew') if 'q' in s else print('\n'.join(list(s)))
Using sets for better SPEED, and more concise functions
sets are a unique type of data structure, they cant have duplicates, dont have an order, are slow to iterate over but are huge speed boosts in certain scenarios.
Detecting duplicates
One of the most useful things that sets can help you with is detecting/removing duplicates, because a set conversion removes duplicates, it will be shorter than what it was converting from which allows you to use stuff like
isdupe=lambda i:len(set(i))==len(i)
instead of
def isdupe2(i):
for item in i:
if i.count(item)!=1:
return False
return True
That second example actually brings us to another efficiency trick with set
Making count more effecient
This one is pretty simple, you dont to need more counts of items than there are items so reducing a list to just unique items makes getting the count of a given item much faster
def isdupe2(i):
for item in set(i):
if i.count(item)!=1:
return False
return True
or the very barebones count dictionary (using a dictcomp :D)
frequency = lambda t:{l:t.count(l) for l in set(t)}
Super set,Subset,difference
Finding wheather all items in one thing are countained in another can best be done by converting iterables to sets,and then using the built issubset and issuperset methods
subset =lambda x,y:set(x).issubset(y)
In speed
One of the most important thing about sets is that checking if an item is contained is significantly faster with a set than with a list or a tuple
i.e
l=[7,33,3282801,83]
g=set(l)
s=7 in l
u=7 in g
Removing duplicates, set and dict.fromkeys
If you want to remove all duplicates from a list and dont care about order, its as simple as this:
nodupes=lambda t:list(set(t))
If you care about order:
nodupes2=lambda r:list(dict.fromkeys(r))
more info
https://www.w3schools.com/python/python_ref_set.asp
shorthand if-else
One of the easiest ways to make code look cleaner is to use shorthand if else
<thing> if <condition> else <thing>
i.e:
def iseven(i):
return True if i%2==0 else False
#^shorthand
def iseven2(i):
if i%2==0:
return True
else:
return False
Dataclasses
This one is pretty simple, The example on their docs pretty much explains why its so great
from dataclasses import dataclass
@dataclass
class InventoryItem:
name: str
unit_price: float
quantity_on_hand: int = 0
#looks a lot cleaner than
class item2:
def __init__(self, name: str, unit_price: float, quantity_on_hand: int=0):
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
it makes classes meant for storing data a lot a easier
Conclusion
I hope this was helpful and that you had fun reading, and learned a lot! :)
p.s if youre wondering about the performcance differences between map and listcomp, here ya go
https://replit.com/@dumbCodr/map-v-lcomp
As a writer, I'm working on an article that can describe this easily, currently I'm working in vector art company near me, with highly professional designer nad writers of the USA.
Nice!! this must have took a lot of time.
These are some super tips! Thanks for sharing!
Nice tutorial! Just a tip, add the
py
extention at the end of the three ticks to get syntax highlighting, like this:@DynamicSquid Thank you!
@DynamicSquid yess! another person trying to spread syntax highlighting lmao