Enchanted Code

# Write Better Code In Python

## Logical Comparisons

Here we demonstrate how to adjust your comparison statements to use logical comparisons. This can allow for better code readability and even performance improvements in new versions of Python.

This can be used when comparing booleans or checking whether a variable is `None`.

Normal Comparison:

 ``````1 2 3 4 5 6 7 8 `````` ``````user = None has_write_access = False if has_write_access == False: pass if user == None: pass ``````

Logical Comparison:

 ``````1 2 3 4 5 6 7 8 `````` ``````user = None has_write_access = False if not has_write_access: pass if user is None: pass ``````

## Storing Unique Lists

If you are storing values that are unique in a list, utilising a `set` may bring some advantages to your code.

The first advantage is that any value stored in a set will always be unique, since duplicates are not stored. Second is that you gain a performance improvement when checking if a value exists in the set, since every value stored has O(1) look-up time. This allows the access time to remain the same no matter how many elements are stored.

Changing your list to a set may not be suitable for all projects, for one if you want to store multiple values that are the same; you will not be able to. Also if you want to store ordered values; you cannot, since values in a set are not stored in an ordered way.

Using a set in your code can be achieved by using the following code:

 ``````1 2 3 4 5 `````` ``````my_numbers = set([42, 0, 6]) if 42 in my_numbers: # Do something magical pass ``````

Be aware that converting a list into a set is a O(n) operation, so if you are only performing a few look-ups; it may actually make your code less performant. If your data is ordered there are also different ways of searching through data other than using a set, or performing linear search. For example you could use a binary search or use a data-structure like a tree.

## Iterating Over A Dictionary

A common way of iterating over keys in a dictionary is by using the `keys()` method. However, this is no longer needed in newer versions of Python.

Instead to iterate over the keys in a dictionary we can use the following method:

 ``````1 2 3 4 `````` ``````scores = {"Steve": 2, "Leo": 10, "Kate": 4} for name in scores: print(name) ``````
 ``````1 2 3 `````` ``````Steve Leo Kate ``````

If we wanted to access both the keys and the values in our loop we could use the `items()` method. This removes the need to perform two access operations on every element and can make the code’s function more clear.

 ``````1 2 3 4 `````` ``````scores = {"Steve": 2, "Leo": 10, "Kate": 4} for name, score in scores.items(): print(f"{name} = {score}") ``````
 ``````1 2 3 `````` ``````Steve = 2 Leo = 10 Kate = 4 ``````

## Checking Types

If you come into the situation of needing to check whether a value is a specific type, you may find yourself using the `type()` method. This however, may not be the best solution. Take this example:

 ``````1 2 3 4 5 6 7 8 `````` ``````class Animal: pass class Cat(Animal): pass class Dog(Animal): pass ``````

If we want to check if `animal_one` is cat we could do the following:

 ``````1 2 3 4 `````` ``````animal_one = Cat() if type(animal_one) == Cat: print("It's a cat!") ``````
 ``````1 `````` ``````It's a cat! ``````

However, if we want to check if the value stored is a animal, we cannot use the type method. We can instead use the `isinstance()` method.

 ``````1 2 3 4 `````` ``````animal_two = Dog() if isinstance(animal_one, Animal) and isinstance(animal_two, Animal): print("Animals!") ``````
 ``````1 `````` ``````Animals! ``````

## Iterating Over Collections

There are many ways of iterating over elements in a list. The two shown below are the most commonly used methods:

 ``````1 2 3 4 5 6 7 `````` ``````my_list = ["a", "b", "c", "d"] for i in range(len(my_list)): print(my_list[i]) for letter in my_list: print(letter) ``````
 ``````1 2 3 4 5 6 7 8 `````` ``````a b c d a b c d ``````

The first way allows us to access the index and then access the element via the index. If we just wanted the element and not the index, we may want to use the other method instead.

If we wanted to access both the index and the element, we could use a better method. This method would also reduce the operations from two to one. To do this we can use the `enumerate()` method. As shown below:

 ``````1 2 `````` ``````for i, letter in enumerate(my_list): print(f"{i} - {letter}") ``````
 ``````1 2 3 4 `````` ``````0 - a 1 - b 2 - c 3 - d ``````

## Using Dunders

Ever wonder how we can print objects other than strings, or how we can perform mathematical operations on numerical types. All of those features and more can be added to your classes, using something called “Dunders” or “Special Methods”. These are methods that are called by Python automatically but implemented by the developer.

Let’s take a look at a simple example, say we want to print an object directly to the users terminal. Normally we would get a object reference outputted, however in this code example we will not.

 ``````1 2 3 4 5 6 `````` ``````class FancyThing: def __repr__(self): return "Fancy!" thing = FancyThing() print(thing) ``````
 ``````1 `````` ``````Fancy! ``````

What happens when this is printed? Well we do not get the normal output of a object, instead we get our message that is returned in the `__repr__` method. This is one of the “Dunder” methods. These methods are always wrapped by double underscores. This method overrides the print representation, so when we pass the object into a print statement Python will call this.

How about something more cool, like allowing for two objects to be added together. Normally not possible, unless we use a numerical type.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 `````` ``````class Total: def __init__(self, total): self._my_total = total def __add__(self, other_total): total = self._my_total + other_total._my_total return Total(total) def __repr__(self): return str(self._my_total) total_one = Total(5) total_two = Total(5) total_three = total_one + total_two print(total_three) ``````
 ``````1 `````` ``````10 ``````

When this code is run we will see that a new `Total` object is created, containing the result of both the totals from the two objects added together.

There are many different “Dunders” available in Python. They are all spoken about in the official documentation.

## References

### Prevent Mistakes In Python

A collection of tips that can help prevent mistakes in Python. Useful for both new and experienced programmers....

### Selection In Python

Tutorial on how to use selection in Python by using 'if statements'....

### Python Cheatsheet

Python cheatseet, providing guidance to new or experienced programmers....

### Using Git In Python

A post on how you can use git from within python using the package git-interface...

### Using Python Virtual Environments (venv)

A Python 3 tutorial to show how to use Python's venv command...

### What Is Pip?

A Python 3 tutorial to show how to use Python's pip command...