# Follow Your Gut!

## But not this time…

--

I only recently learnt how to code in Python. Or should I say to code at all? I still consider myself a Python newbie, and I even doubt I will ever fully master it when I see how many things I learn every time I code. But on the other hand, that is what makes it fun, and I find it very motivating!

Throughout the last year, I have encountered a few cases with results I was not expecting. Sometimes, I clearly did not know how Python processes things under the hood and made a mistake, other times I thought I understood how things were going under the hood but, I misunderstood, it was an error of judgment.

There is a lot of articles about “why programming is so hard to learn” or “how to think like a programmer”. Hopefully, this shortlist of code snippets with unexpected ending will drag you slightly up the learning curve and make programming a little easier next time.

# Booleans

In Python, any object is `Truthy`, if it evaluates as `True`, or `Falsy` when it evaluates as `False`.

## Numerical values

This means `True` and `False` can have a numerical value (it is a subclass of integers after all): `True = 1` and `False = 0`. It makes sense (everything in computers is either 1 or 0, is it not) and it probably will not impact 99% of your code, but bear that in mind when counting elements.

`>>> print(f"False = {False * 4}\nTrue = {True * 3}") False = 0True = 3`

## Empty vs. Non-Empty

An empty sequence is considered `False` whilst a non-empty one is `True`. It makes perfect sense to me, and I find the truthiness of objects quite useful. For example:

`>>> d = {} >>> d == TrueFalse>>> if d:    # Instead of `if d == True:`...     print('not empty')... else:...     print('empty')empty`

With this in mind, let us look at the following:

`>>> lt = ['', 'item']>>> lf = []`

Let us check for membership now:

`>>> print(f"lt = {'' in lt}\nlf = {'' in lf}\n[] == [''] = {[] == ['']}")lt = Truelf = False[] == [''] = False`

Put this way, it does make sense because the check is on the value `''` and, I am sure if there were a way to represent "nothing", the interpreter would return `True`. But it is worth keeping in mind that Python is quite literal about what empty is.

Another example of this would be using the `all()` and `any()` functions:

`>>> d = {} >>> print(f"d == True: {d == True}\nall(d): {all(d)}\nany(d): {any(d)}")d == True: Falseall(d): Trueany(d): False>>> d = {''} >>> print(f"d == True: {d == True}\nall(d): {all(d)}\nany(d): {any(d)}")d == True: Falseall(d): Falseany(d): False`

In both cases, the dictionary evaluates to `False`. In the first case, it does not have any "Falsy" element so `all()` returns `True` but `any()`, checking for at least one truthy element, returns `False`. In the second case, it explicitly contains an empty element.

Once again, the correct way to see this is there are two ways for a sequence to be empty: by being empty (`[]` case) or by containing empty (`['']` case).

# Strings

## Automatic Concatenation

Somehow, if you put two strings on the same line of code, the interpreter will concatenate them:

`>>> 'Hello' 'World''HelloWorld'`

In the same spirit, creating a list of letters can be quick and easy when using `list()`.

`>>> list('Hello World')['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']`

## `split()`

This method will split a string on a specific character. By default, it will split the string on the space character. However:

`>>> print('          Hello    '.split(' ')) ['', '', '', '', '', '', '', '', '', '', 'Hello', '', '', '', '']>>> print(' Hello                     World      '.split())['Hello', 'World']>>> print(''.split(' '))['']>>> print('aaa'.split('a'))['', '', '', '']`
• When `split()` is given the whitespace character to use to split the string, it splits the string on every occurrence of this whitespace.
• When the whitespace is implicit, `split()` processes the string before splitting it. It cuts off the leading and trailing whitespaces and compresses the remaining whitespaces. After turning the multiple whitespaces into a single occurrence, it is used as a marker to split the string.
• If the string is empty, `split()` returns an empty list.
• When `split()` is given a string containing only the character to split the string with, it returns a list that is `+1` longer than the initial string.

# Integers

## Special Cases

`infinity` is `infinity`, but `not a number` is not `not a number`.

`>>> float('inf') == float('inf')True>>> float('NaN') == float('NaN')False`

## Pre-allocation

Numbers `-5` to `256` are allocated when the interpreter starts.

`>>> a = 256>>> b = 256>>> a is bTrue>>> a = 257>>> b = 257>>> a is bFalse>>> a, b = 257, 257>>> a is bTrue`

After these examples, it is worth reminding:

`is` checks the identity of objects. Whilst `==` checks for the equality of objects

• In the first example, 256 is allocated when the interpreter starts. This `256` object is then referenced as `a`, then `b` but it is the same object being referenced as two different variables.
• In the second example, `257` is created when assigned to `a`, then another `257` is assigned to `b`. We are dealing with two different `257` objects.
• The last case shows that object allocation is done at the same time when put on the same line. The object `257` is created once then assigned to `a` and `b`.

Instinctively we expect these statements to be `True` because we see the values are the same. Instinctively we think `a == b`. Using `is` in this case was a mistake.

By the way, multiple assignments are considered best practice:

`# Don't use temporary variables when it is not necessary>>> def fibonacci(n):>>>     x = 0>>>     y = 1>>>     for i in range(n):>>>         print(x)>>>         t = y>>>         y = x + y>>>         x = t        # Multi assignment saves the day>>> def fibonacci(n):>>>     x, y = 0, 1>>>     for i in range(n):>>>         print(x)>>>         x, y = y, x + y`

Have a look at my previous article for more tips about code readability, best practice, and other pythonisms:

# Tuples

`>>> t = 'item',>>> type(t)tuple>>> t = ('item' 'other_item')>>> print(t)itemother_item`

Unlike lists and dictionaries, defined by their respective brackets, a tuple is defined by its comma, not its parenthesis.

# L0lz !!1

If you have enjoyed this article and your brain does not hurt enough, head to WTF python for more Python fun! (I am not affiliated)