Useful Python code snippets and language properties

In this article I want to share a few code Python snippets that can help writing short and efficient code. I tested it with Python 3.5.2 on Ubuntu 16.04.

I will keep updating this article.

Check list for duplicate entries

If you want to check if a list contains any element more than once you can compare its length to the length of the set representation of that list. Converting a list to a set automatically removes duplicates. So if the list contains duplicates, the set of the list will have less elements.

def has_duplicates(_list):
	return len(_list) != len(set(_list))

print(has_duplicates([1,2])) # False
print(has_duplicates([2,2])) # True

Revert list (e.g. string) with array slicing

Reverting any list in python can be done by this:

elements = [1,2,3]
reverted = elements[::-1] # [3,2,1]

[::-1] is the slice operator [a:b:c] which extracts all elements from index a to index b by using stepwidth c. As we do not provide a and b, the whole list is extracted. By setting c = -1 we start at the end and go to the start, so the result is the reverted list.

You can also easily check if a string is a palindrome by using this operator:

def is_palindrome(item):
  return item == item[::-1]

print(is_palindrome("anna")) # True
print(is_palindrome("python")) # False

Insert element(s) to lists at arbitrary positions using array slicing

Python’s array slicing operator [::] is extremely powerful. It does not only allow you to read/extract arbitrary elements of lists, it also supports list manipulation:

a = [1,2,3]

# Prepend element to a list (you can also prepend multiple elements this way)
a[:0] = [0]
print(a)	# [0, 1, 2, 3]

# Mirror the list (generate palindrome)
a[-1:] = a[::-1]
print(a)    # [0, 1, 2, 3, 2, 1, 0]

# remove elements 2 to 4 (5 is not included)
a[2:5] = []
print(a)	# [0, 1, 1, 0]

# Insert element at position 1 (you could also insert multiple elements here)
a[1:1] = [99]
print(a) 	# [0, 99, 1, 1, 0]

# Replace all elements from position 1 to the end with the elements in range 1 to 2 (3 is not included)
# Note that range(1,3) is a generator which gets converted to a list automatically
a[1:] = range(1,3)
print(a)	# [0, 1, 2]

# remove all elements except the last
a[:-1] = []
print(a)	# [2]

# prepend multiple elements to the list
a[:0] = [1,2,3,4,5,6]
print(a)	# [1, 2, 3, 4, 5, 6, 2]

# remove last element (2)
a[-1:] = []
print(a)	# [1, 2, 3, 4, 5, 6]

# Only revert every second element of the list (1,3,5 becomes 5,3,1)
a[::2] = a[::2][::-1]
print(a)	# [5, 2, 3, 4, 1, 6]

These features can save lots of time. If you know other python shortcuts not covered in this article, please feel free to write a comment.

Python does store lists as references

When you add a list to another list and then manipulate the original list, the “copy” in the other list will also get manipulated:

a = [1,2,3]

b = []
b.append(a)

print(b) # [1,2,3]
a[1] = 5
print(b) # [1,5,3]

If you want to make a real copy of a list, you can either transform it via list(a) or a[:]

a = [1,2,3]

b = []
b.append(a)
b.append(a[:])
b.append(list(a))

print(b) # [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
a[1] = 5
print(b) # [[1, 5, 3], [1, 2, 3], [1, 2, 3]]

You can see that the list appended to another list also gets manipulated when not using a[:] or list(a), but not if you use one of these. a[:] is the slicing operator with no start and end specified, so it will just copy all elements in the original order. But be careful: If a also contains just references they get copied, too. If you want to get a deep copy, you have to use copy.deepcopy(a) which resolves all references.

I think python uses references instead of copies by default in order to save memory

Print tables using Python’s string format function

I wrote a small helper function that enables me to print tables with the column width automatically calculated:

def print_table_row(data, maxlengths, padding, alignment):
  print("|".join(['{0:{align}{len}}'.format(data[i], len=maxlengths[i]+padding, align=alignment[i]) for i in range(len(data))]))

def print_table(header, data, padding=3, alignment=None, line_every=-1):
  columns = len(header)

  if not alignment:
    alignment = ["^"] * columns

  lenghts    = [[len(item[i]) for i in range(columns)] for item in data]
  maxlengths = [len(h) for h in header]
  
  for clength in lenghts:
    for i in range(columns):
      maxlengths[i] = max(maxlengths[i], clength[i])
  
  print_table_row(header, maxlengths, padding, alignment)
  sepline = "-"*(sum(maxlengths) + padding * columns)
  print(sepline)
  for i, item in enumerate(data):
    print_table_row(item, maxlengths, padding, alignment)
    if line_every > 0 and (i+1)%line_every == 0 and i  != len(data)-1:
      print(sepline)



items = [["This", "is"], 
         ["a", "test"], 
         ["Python", "strings"], 
         ["are", "awesome"]]

print_table(["Column A", "Column B"], items, 10)

The output is:

     Column A     |     Column B     
------------------------------------
       This       |        is        
        a         |       test       
      Python      |     strings   
       are        |     awesome   

In print_table_row() I use python’s extremely useful string format function. With this function you can align strings inside a given space, e.g. align a 5 character string in the space of 10 characters in the middle, on the left or on the right of the specified space. To print a table, I iterate over all elements of the table to determine the maximum width of each column and use that as the input for the string format function. You can also specify a padding in order to get more readable tables.

 

Leave a Reply

Your email address will not be published. Required fields are marked *