Skip to content

Instantly share code, notes, and snippets.

@horstjens
Forked from Julynx/15_python_tips.md
Created May 11, 2023 09:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save horstjens/6946f067bcc8ef5bb207bdf1365f0de0 to your computer and use it in GitHub Desktop.
Save horstjens/6946f067bcc8ef5bb207bdf1365f0de0 to your computer and use it in GitHub Desktop.
15 Python Tips To Take Your Code To The Next Level!


Basic Tips - Intermediate Tips - Advanced Tips

Basic Tips

1) Learn how to iterate properly

  • Use for index, item in enumerate(list): to loop over the index of an item and the item at the same time.
  • Use for key, value in dictn.items(): instead of iterating over keys and then getting values as dictn[key].
  • Use for item1, item2 in zip(list1, list2): to iterate over two lists at a time.

2) Use with statements to automatically close files

Instead of calling close() manually when you finish accessing a file, consider using a with statement. It's shorter, more readable, and less error-prone, as it will take care of closing the file automatically for you.

Instead of doing this... try this:
file = open(file_path, 'w')
file.write('Hello, World!')
file.close()                                   
with open(file_path, 'w') as file:
    file.write('Hello, World!')
# The file is closed automatically.             

3) Use f-strings for formatting

An f-string is preceded by the letter f and allows for inserting variables between curly braces {}. Using f-strings is generally faster and makes your code more readable.

Instead of doing this... try this:
name = input('Enter your name: ')
surname = input('Enter your surname: ')
                                               
print('Hello, ' + name + ' ' + surname)
name = input('Enter your name: ')
surname = input('Enter your surname: ')
                                                
print(f'Hello, {name} {surname}')

4) Learn to use split() and join()

If you want to separate a string into a list of substrings, use lst = text.split(separator). Use text = separator.join(lst) to merge a list of strings together.

Instead of doing this... try this:
names = ['Olivia', 'Nicholas', 'Violet']
text = ''
                                               
for name in names:
    text += name + ', '

text = text[:-2]

print(text)
# >> 'Olivia, Nicholas, Violet'
names = ['Olivia', 'Nicholas', 'Violet']
text = ', '.join(names)
 
                                                
 
 
 
 
print(text)
# >> 'Olivia, Nicholas, Violet' 

5) Transform list into set to remove duplicates

Instead of iterating over a list to remove duplicate elements, take advantage of the properties of certain data structures, like the set, which can only contain distinct elements.

Transform your list into a set to remove duplicate elements. You can transform it back to a list afterwards if you need to.

Instead of doing this... try this:
cities = ['London', 'Paris', 'London']
unique_cities = [] 
                                               
for city in cities: 
    if city not in unique_cities:
        unique_cities.append(city)

print(cities)
# >> ['London', 'Paris'] 
cities = ['London', 'Paris', 'London']
unique_cities = set(cities)

print(cities)
# >> {'London', 'Paris'}
                                                
cities = list(cities)
print(cities)
# >> ['London', 'Paris']

Intermediate Tips

1) Instead of if variable == a or variable == b use if variable in {a, b}

Instead of repeating a variable in different conditions of an if statement, check for belonging against a set of allowed values. This is shorter, less prone to error, and makes it easier to add or remove allowed values in the future.

Instead of doing this... try this:
if variable == a or variable == b:
    res = do_something(variable)               
if variable in {a, b}:
    res = do_something(variable)                

2) Learn how to use inline if statements

It is possible to write inline if statements to make assignments to variables based on a condition. Whether to use one or the other is mostly subjective and depends on which one you find more aesthetic and easier to read.

Regardless, you should know and understand both in case you come across them.

This code... is equivalent to this code:
if b > 10:
    a = 0                                      
else:
    a = 5
a = 0 if b > 10 else 5
                                                
 
 

3) Use or to handle None values

Learn that you can use or to set a fallback value to assign in case another variable is None or False.

Instead of doing this... try this:
if data:
    lst = data
else:
    lst = [0, 0, 0]                            
lst = data or [0, 0, 0]
                                                
 
 

4) Instead of asking for permission, ask for forgiveness

In Python, it's much more common to try: to do something and catch all possible exceptions, than to control input and output values using if statements.

More likely than not, the function already does the necessary value checks from the inside and raises all possible errors. The only thing left for you to do is to catch them and define what should happen in case of error inside an except Exception: clause.

This is why, instead of checking if a file exists and if you have permissions before opening it, you should just try to open it.

Instead of doing this... try this:
if not os.path.isfile(filename):
    print('File does not exist.')
                                               
if not os.access(filename, os.W_OK):
    print('You dont have write permission.')

with open(filename, 'w') as file:
    file.write('Hello, World!')
 
 
 
 
try:
    with open(filename, 'w') as file:
        file.write('Hello, World!')
                                                
except FileNotFoundError:
    print('File does not exist.')

except PermissionError:
    print('You dont have write permission.')

except OSError as exc:
    print(f'An OSError has occurred:\n{exc}')

5) Use center to center strings and os.get_terminal_size().columns to center to terminal.

Learn how to use text.ljust(length) to align text to the left, filling it with spaces until it reaches a desired length. Use text.rjust(length) or text.center(length) to align text to the right or center respectively. Set length = os.get_terminal_size().columns to center text relative to your terminal's width.

Instead of doing this... try this:
text = "Hello, World"
length = 20
                                               
text = " "*((length//2) - (len(text)//2)) \
     + text \
     + " "*((length//2) - (len(text)//2))

print(text)
# >> "    Hello, World    "
text = "Hello, World"
length = 20

text = text.center(length)
  
 
                                                
print(text)
# >> "    Hello, World    "                   

Advanced Tips

1) Learn to transform complex for loops into comprehensions

It's usually better to use comprehensions over for loops in Python when possible, as they are usually faster and shorter. However, it can be difficult to transform long and complex for loops into comprehensions.

If you are iterating over items, processing them in some way, and appending the results to a list to return it afterwards, try doing this instead:

First, extract the body of the loop to a separate function that processes one item at a time. Let's call it process_item(). Then, build your list comprehension by calling process_item() over all the items.

Instead of doing this... try this:
items = [item1, item2, item3, item4...]
new_items = []
                                               
for item in items:
    item = do_something(item)  # Extract
    item = do_smth_else(item)  # this
    ...                        # logic.
    new_items.append(item)
 
 
items = [item1, item2, item3, item4...]
                                               
def process_item(item):        # 'process_item'
    item = do_something(item)  #  now does the
    item = do_smth_else(item)  #  processing
    ...                        #  for a single
    return item                #  item.
                                                
new_items = [process_item(item) 
             for item in items]

2) Write readable comprehensions

List, set, dictionary, and generator comprehensions may generally be shorter and run faster, but they can also be much harder to read. This is why, instead of writing your comprehensions in a single line, try splitting them into multiple lines.

Notice how each keyword (for, in, if...) starts a new line. This makes the comprehension more comfortable to both read and modify if you need to add new conditions in the future.

Instead of doing this...
comments = {line_idx: line.strip() for line_idx, line in enumerate(file) if line.startswith('#')}     
try this:
comments = {line_idx: line.strip()    
            for line_idx, line
            in enumerate(file)
            if line.startswith('#')}                                                                  

3) Don't iterate if you don't have to

Iterating is expensive in Python and most common operations that require iteration can be done through functions that are either built-in or available in popular libraries/modules like functools, itertools, and numpy. The underlying code for these functions is usually written in C and they are highly optimized. Use them whenever possible and iterate only when strictly necessary.

Instead of doing this... try this:
numbers = [1, 3, 4, 5, 7, 9, 2]
sum = 0
                                               
for number in numbers:
    sum += number

avg = sum / len(numbers)
from numpy import mean
                                                
numbers = [1, 3, 4, 5, 7, 9, 2]
avg = mean(numbers)          
 
 
 

4) Use multiprocessing.Pool and get easy speedups with multiple processes

Your processor has multiple cores that can execute several tasks at the same time, but by default your code usually runs on a single core.

However, Python provides an easy way to make use of multiple processes to achieve parallelism and speedups that can go from x4 to x16 and even more for some machines.

Instead of doing this... try this:
requests = [req1, req2...]
results = []

for request in requests:
    res = process_request(request)
    results.append(res)
                                               
# Runs in 1m 22s, depending on HW.
from multiprocessing import Pool

requests = [req1, req2...]

with Pool as p:
    results = p.map(process_request, requests)
                                                
# Runs in 16s, depending on HW.

5) Use next(item for item in items if [condition]) to get the first item that matches a condition

It's a common task to get the first element of a list that has some specific property. The next() function can help you do that.

Instead of doing this... try this:
numbers = [1, 3, 4, 5, 7, 9, 2]
result = None

for number in numbers:
    if number > 3:
        result = number
        break
                                               

print(result)
# >> 4 
numbers = [1, 3, 4, 5, 7, 9, 2]

try:
    result = next(number for number in numbers
                  if number > 3)

except StopIteration:
    result = None
                                                
print(result)
# >> 4

Extra Tips

Here are some secret extra tips, for making it all the way to the end.

1) Assign values to multiple variables at a time or swap them

  • Use multiple assignments and commas to give values to more than one variable at a time: a, b, c = 1, 2, 3
  • Or easily swap two variables in a single line: a, b = b, a

2) Use all() and any()

  • all(a, b, c) returns True if a, b and c are True.
  • any(a, b, c) returns True if at least one of a, b or c is True.

You can use them as conditions in your if statements.


3) Simplify your conditions with intervals or ranges

Instead of writing separate conditions (if min < value and value < max:):

  • Use intervals: if min < value < max:
  • Or use ranges: if value in range(min, max):

Keep in mind that min is included in the range(), but max is not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment