Python for JavaScript Developers

An hitchhiker guide to Python for JavaScript developers. Enjoy!

Python for JavaScript Developers

JavaScript is my bread and butter, but I don't dislike other programming languages, at all. I always had a crush for Python which I used over the years ranging from scripts to API applications with Flask and Django.

In this post I'll guide you through a 10.000 feet comparison between these two languages.

To follow along you need at least a basic understanding of JavaScript and its quirks.

You can try the code examples for JavaScript in a browsers's console or in the Node.js REPL. For Python, you can use the Python REPL. Every time you see >>> in the code examples, that's the REPL.

Enjoy the reading!

Arithmetic operators in Python and JavaScript

Let's start with arithmetics!

Both Python and JavaScript share more or less the same arithmetic operators. In addition (no pun intended) to the division operator, Python has also a floor division operator.

OPERATOR PYTHON JAVASCRIPT
addition + +
subtraction - -
multiplication * *
exponent ** **
division / /
floor division // n/a
modulo % %

Floor division returns the integer quotient of the division between two numbers. Consider the following example in Python:

>>> 89 / 4

# Output: 22.25

To get an integer instead of a float we can use floor division. (// in JavaScript is a comment):

>>> 89 // 4

# Output: 22

To replicate the same result in JavaScript you would use Math.floor:

Math.floor(89 / 4)

// Output: 22

Python's arithmetic operators do not operate exclusively on numbers. For example, you can use multiplication on strings to repeat a pattern:

>>> "a" * 9

# Output: 'aaaaaaaaa'

Or addition as well to concatenate simple strings:

>>> "a" + "aa"

# Output: 'aaa'

For everything else Python raises a TypeError. That means you cannot sum number and string together:

>>> "a" + 9

# TypeError: can only concatenate str (not "int") to str

Nor divide them (besides making no sense):

>>> "a" / 9

# TypeError: unsupported operand type(s) for /: 'str' and 'int'

On this front JavaScript is a complete mess in the eye of an external observer because of the infamous type coercion. Not only JavaScript's arithmetic operators are free to convert numbers to string:

"a" + 9

// Output: "a9"

They do not raise any error in case of invalid arithmetic operations:

"a" / 9

// Output: NaN

Instead we get NaN, a special JavaScript value resulting from invalid arithmetic operations, difficulty to deal with, until ECMAScript 2015 Number.isNaN.

Increment and decrement operators in Python and JavaScript

OPERATOR PYTHON JAVASCRIPT
increment n/a ++
decrement n/a --

JavaScript has an increment and a decrement operator. Both can be used prefix (before the number):

var a = 34;
++a

or postfix (after the number):

var a = 34;
a++

In the first case (prefix), the operator increments the number and returns the new number:

var a = 34;
++a
// returns 35

In the second case (postfix), the operator increments the number, but returns the original number:

var a = 34;
a++
// returns 34
// increments to 35

The same rules are true for the decrement operator.

In Python instead there is no such thing as a decrement/increment operator. Rather you have to use an assignment operator. Here's an increment assignment in Python:

>>> a = 34
>>> a += 1
# a is now 35

And here's a decrement assignment:

>>> a = 35
>>> a -= 2
# a is now 33

JavaScript has assignment operators as well.

Comparison operators in Python and JavaScript

JavaScript and Python have the same comparison operators, except for the triple equal, emblematic of JavaScript's weird coercion rules.

There is a huge literature on that topic, I won't bother you too much. Here are Python and JavaScript comparison operators side by side:

OPERATOR PYTHON JAVASCRIPT
greater than > >
less than < <
greater or equal than >= >=
less or equal than <= <=
equal == ==
strict (triple) equal n/a ===
not equal != !=
strict not equal n/a !==

To be precise Python has also the is operator (not discussed here) which for me falls more in the identity operators family.

What matters here is that Python is predictable when comparing values:

>>> 9 == "9"

# Output: False

JavaScript on the other hand performs a conversion every time the abstract comparison operator is involved:

9 == "9"

// Output: true

Here the first operator 9 is converted to a string right before the comparison. To avoid the conversion you must use the "strict comparison operator", also called triple-equal:

9 === "9"

// Output: false

Logical operators in Python and JavaScript

Now that we talked about arithmetic and comparison operators let's see their companions: logical operators. Oh, my friend, I can still remember boolean algebra in high school. Do you?

Here are the most common logical operators for Python and JavaScript:

OPERATOR PYTHON JAVASCRIPT
logical and and &&
logical or or ||
logical negation not !

Logical operators are useful when you want to do (or not to do) something in your code depending on the outcome of an expression. Suppose we want to print "I am cool" only if 2019 is greater than 1900. Here's how you'll do it with the logical operator and in Python:

>>> 2019 > 1900 and print("I am cool")

# Output: "I am cool"

and means: do the stuff on the right only if the stuff on the left is true. The same logic in JavaScript maps to:

2019 > 1900 && console.log("I am cool")

The or logical operator works the other way around. or means: do the stuff on the right only if the stuff on the left is false. Here's an example in Python:

>>> 2019 > 1900 or print("I am cool")

# Output: True

The result is True because 2019 is greater than 1900 so the evaluation stops there. Here's the same logic in JavaScript:

2019 > 1900 || console.log("I am cool")

Last but not least there is logical negation, useful when you want to flip the result of an expression. For example we can print "I am cool" even in if a given expression on the left is false. How? With the not operator in Python:

>>> not 2019 > 151900 and print("I am cool")

# Output: "I am cool"

2019 is clearly smaller than 151900, but logical not flips the result, so the right expression is still evaluated. The following example should be more simple to grasp:

>>> not False and print("I am cool")

# Output: "I am cool"

Logical negation in JavaScript uses an exclamation mark instead:

!false && console.log("I am cool")

Basic data types in Python and JavaScript

In computer programming data types are "shapes" that you can work on. Most programming languages have a group of basic data types like strings, numbers, and booleans.

Python and JavaScript make no exception. Here's an overview of the most important basic data types available on both languages (n/a stands for not applicable).

PYTHON JAVASCRIPT MUTABLE IN PYTHON MUTABLE IN JS
float Number no no
int BigInt no no
int n/a no n/a
string String no no
boolean Boolean no no
None Null no no
n/a Undefined n/a no
n/a Symbol n/a no

JavaScript has eight types, seven of which are called primitives (Object is a type on its own). You can notice from the table that both Python and JavaScript basic types are immutable. For example in Python we refer to string as an immutable sequence of unicode characters.

Like most basic types, Python strings have methods for common operations:

>>> name = "caty"

>>> name.capitalize()
>>> name.center(40)
>>> name.count("t")

## and more!

Since strings are immutable, the result of a string operation is always a new string.

Now numbers. In JavaScript there is no distinction between integers and floating point numbers, they are just a Number data type. In Python instead there are integers and floats.

JavaScript got recently a BigInt primitive type for representing very large numbers. Python instead seems to handle small and big integers with a single int type.

Would be remiss not to mention the quintessential boolean, which in Python can assume either the value of False or True.

An important note on special values. Python has None for describing an empty value. In JavaScript instead there is the dreaded null.

Also in Python there is neither the concept of undefined like in JavaScript, nor a corresponding type Symbol, a rather esoteric JavaScript primitive.

Regular expressions in Python and JavaScript

Regular expressions are a powerful tool for pattern matching against text. To work with regular expressions in Python we use the re module.

To create a new pattern, we can compile a regular expression with re.compile:

import re

regex = re.compile(r"\d\d\d\d")

re.compile is particularly useful for complex regular expression, since it can speed things up.

Once we have a regular expression, we can match it against a piece of text with .search():

import re

regex = re.compile(r"\d\d\d\d")

text = "Your id is 4933"

match = regex.search(text)

Here we search for four consecutive digits inside the text with \d\d\d\d. If a match occurs, the result is a match object which has two methods: .start() and .end().

These methods return respectively the start and the end index of the portion of text where the pattern has been found:

import re

regex = re.compile(r"\d\d\d\d")

text = "Your id is 4933"

match = regex.search(text)

start, end = match.start(), match.end()

# start is 11 and end is 15

With these indexes we can now extract the match:

import re

regex = re.compile(r"\d\d\d\d")

text = "Your id is 4933"

match = regex.search(text)

start, end = match.start(), match.end()

found = text[start:end] # 4933

To obtain the same result in JavaScript, we can use the literal form for building a regex, or the RegExp constructor:

const regex = new RegExp(/\d\d\d\d/);

We can also pass flags to the constructor. Here we build a global regex:

const regex = new RegExp(/\d\d\d\d/, "g");

Now given a text we want to match against, we can use .exec() and lastIndex to match multiple patterns in a string, or better, the new String.prototype.matchAll(), which returns an iterator:

const regex = new RegExp(/\d\d\d\d/, "g");
const text = "Your 7795 id is 4933";

const match = text.matchAll(regex);

const found = [...match].map((el) => el[0]);
// [ '7795', '4933' ]

Python data types and JavaScript: immutability and variables

You may have noticed from the table above that most of the basic Python data types are immutable. JavaScript in practice seems more relaxed. Try the following examples in a browser's console or in Node.js REPL. Numbers? Seem mutable:

var a = 34;
++a
// returns 35

Booleans? Seem mutable as well:

var x = false;
x++;
// returns 0 and x becomes 1

Null? Again, seems mutable:

var x = null;
x++;
// returns 0 and x becomes 1

Don't get fooled. What is changing here is not the underlying primitive, but the value assigned to the variable.

The last two examples with the boolean and null are a case of type coercion. The engine transforms both values to the corresponding numeric representation, and the variable gets assigned the new value.

See this example on MDN for more.

Complex data types in Python and JavaScript

A complex data type is a more sophisticated shape opposed to simple primitives like strings and numbers. In Python, we can name list, dictionary, set, and tuple.

In JavaScript instead the distinction is slightly less noticeable because Object is the topmost complex type and other subtypes like Array and Set are specialized versions of their "ancestor" (Function is an object too).

Here's a breakdown of complex data types in Python and JavaScript:

PYTHON JAVASCRIPT MUTABLE IN PYTHON MUTABLE IN JS
list Array yes yes
dictionary Object yes yes
set Set yes yes
tuple n/a n/a n/a

As you can see arrays and objects in JavaScript are always mutable, and so Object. Unless using an external library there is no way to truly protect objects (Object.freeze is shallow). However, there are plans for adding immutable types to JavaScript in the future.

Python on the other hand as an immutable complex type called tuple (while list, dictionary, and set are mutable). Let's see Python complex types in more detail.

Python data types: list and tuples

A list in Python is a collection of elements, just like JavaScript arrays. Here's a Python list:

>>> my_list = ["vale", 98, "caty", None]

List operations always mutate the original list:

>>> my_list = ["a", None, 44, True, "f"]

>>> my_list.append(44)
>>> my_list.remove('f')

>>> print(my_list) 

# Output: ["a", None, 44, True, 44]

A tuple instead is immutable, in fact it has only two read-only operations (index and count):

>>> my_tuple = ("vale", "Italy", 105)
>>> my_tuple.count("Italy") # 1
>>> my_tuple.index(105) # 2

Notice that tuples are enclosed in round brackets.

I really like how Python is able to concatenate two lists together with the addition operator:

>>> my_list = ["a", None, 44, True, "f"]
>>> another_list = ["b", None, 89, False, "x"]

>>> my_list + another_list

# Output: ["a", None, 44, True, 44, "b", None, 89, False, "x"]

But don't dare trying that trick with JavaScript, you'll be surprised:

var my_list = ["a", null, 44, true, "f"]
var another_list = ["b", null, 89, false, "x"]

result = my_list + another_list
// result is:"a,,44,true,fb,,89,false,x"

As the JavaScript spec goes, the addition operator converts its operands to string when they're both non-string like this example. Note, a Python list and a tuple cannot be concatenated together:

>>> my_tuple = ("vale", "Italy", 105)
>>> my_list = ["a", None, 44, True, "f"]
>>> my_tuple + my_list

# Output TypeError: can only concatenate tuple (not "list") to tuple

Python data types: dictionaries and JavaScript objects

JavaScript's object is a container for key/value pairs and it's also the pillar for other specialized objects:

var obj = {
  name: "John",
  age: 33
};

"Almost everything in JavaScript is an object" is not just a way of saying. It is the actual truth. Array, Function, Set, and more, are just JavaScript objects.

Python has something similar called dictionary (or dict for short), but it's just a container, not a fundamental building block:

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

Values from a dictionary can be accessed or changed via their key:

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

>>> my_dict["name"]

>>> my_dict["city"] = "Florence"

Python raises a KeyError when you access an inexistent key:

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

>>> my_dict["not_here"]

# Output: KeyError: 'not_here'

The .get() method is a safer alternative to direct key access, because it does not raise, and lets specify a default value for inexistent keys:

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

>>> my_dict.get("not_here", "not found")

# Output: 'not found'

Other read-only operations are .items(), or .keys():

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

>>> my_dict.keys() # ['name', 'city', 'age']

You can also remove an element from the dictionary or clear it completely with .clear():

>>> my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

>>> my_dict.pop("name") # returns 'John' and removes it

>>> my_dict.clear() # my_dict is empty now

List, tuple, dictionary, and set are collections or sequences because they hold a certain number of elements, and expose common operation for interacting with them.

No switch, no party

"No switch in Python?? How I am supposed to" ... you could hear me some years ago. You read it right there's no switch in Python. Java programmers are fond of it, and so JavaScript developers.

The switch statement is a common idiom in JavaScript. Consider the following example:

function getUrlConf(host) {
  switch (host) {
    case "www.example-a.dev":
      return "firstApp.urls";
    case "www-example-b.dev":
      return "secondApp.urls";
    case "www.example-c.dev":
      return "thirdApp.urls";
    default:
      return "Sorry, no match";
  }
}

getUrlConf("www-example-b.dev");

A function has to check the host string to return a corresponding configuration depending on the host value. With switch we compare the value switch (host) in a case clause case "www.example-a.dev":. For each case we return a value. The default clause ensures a default return value in case nothing matches.

In Python there's no switch: you can have the same outcome with a dictionary:

def get_url_conf(host):
    mapping = {
        "www.example-a.dev": "firstApp.urls",
        "www-example-b.dev": "secondApp.urls",
        "www.example-c.dev": "thirdApp.urls"
    }

    return mapping.get(host, "Sorry, no match")

Much cleaner if you ask me. The same pattern works for JavaScript too, if you like it more.

JavaScript object spread/merge, Python dict spread/merge

ECMAScript 2018 added the ability to "explode" JavaScript objects, also called "spread". This syntax is particularly convenient for leaving objects untouched (or for cloning them):

const initial = {
  dontTouch: "my breil"
};

const next = { ...initial, dontTouch: "just a copy" };

// initial.dontTouch is "my breil"
// next.dontTouch is "just a copy"

Or for merging them together:

const a = {
  name: "Juliana",
  age: 33
};

const b = {
  surname: "Crain",
  city: "San Francisco"
};

const movie = {
  title: "The man in the high castle"
};

const all = { ...a, ...b, ...movie };

console.log(all);

/*
Output:
{
  name: 'Juliana',
  age: 33,
  surname: 'Crain',
  city: 'San Francisco',
  title: 'The man in the high castle'
}
 */

Before object spread the same result were achieved with Object.assign:

const initial = {
  dontTouch: "my breil"
};

const next = Object.assign({}, initial, { dontTouch: "just a copy" });

There are a couple of ways to get the same result in Python: one involves going through dict.update() which I won't cover here.

Dict unpacking instead looks more like JavaScript's object spread, and I like it better. Here's a first example:

initial = {"dont_touch": "my breil"}

next = {**initial, "dont_touch": "just a copy"}

Here initial is spread into next, and the value for "dont_touch" overwrites the original, while preserving initial. To merge two or more dictionaries we could do:

a = {"name": "Juliana", "age": 33}

b = {"surname": "Crain", "city": "San Francisco"}

movie = {"title": "The man in the high castle"}

all = {**a, **b, **movie}

Unfortunately dict unpacking has some limitations which led Python to add a union operator for dictionaries. So from Python 3.9 you can do union:

a = {"name": "Juliana", "age": 33}

b = {"surname": "Crain", "city": "San Francisco"}

movie = {"title": "The man in the high castle"}

all = a | b | movie ## Dict union!

print(all)

"""
Output

{'name': 'Juliana', 'age': 33, 'surname': 'Crain', 'city': 'San Francisco', 'title': 'The man in the high castle'}
"""

Neat! More info here.

Python data types: Set and JavaScript Set

JavaScript's Set is a convenient data structure useful for storing unique values. A Set may contain primitive types (even null and undefined) or references to an object:

const mySet = new Set();

mySet.add( "aString" )
mySet.add( null )
mySet.add( NaN )
mySet.add(1)
mySet.add(1)

// Output: Set { 'aString', null, NaN, 1 }

There is no much you can do with a JavaScript Set, other than adding elements, checking their existence or looping over it. A Set has the following methods:

  • .add
  • .clear
  • .delete
  • .entries
  • .forEach
  • .has
  • .keys
  • .size
  • .values

Python's Set works more or less the same. You can add unique elements in it or check them as well:

>>> my_set = set()
>>> my_set.add( "aString" )
>>> my_set.add( None )
>>> my_set.add( 1 )
>>> my_set.add( 2 )
>>> my_set.add( 1 )
>>> my_set

# Output: {None, 2, 'aString', 1}

However the main difference from JavaScript is that Python has more useful methods for mathematical set operations like "difference", "intersection", "issubset", "issuperset", "union", and more.

For declaring a Set in Python there is also the literal form:

>>> my_set = { None, "caty", "venice", 84}
>>> another_set = { "and", "mouse", 44, "a" }

As you might have guessed Set in both languages is really useful for removing duplicates. And in Python can do nice things like union:

>>> my_set | another_set

# Output: {'and', 'mouse', None, 'venice', 'caty', 44, 84, 'a'}

or intersection:

>>> my_set = { None, "caty", "venice", 84, "common_element" }
>>> another_set = { "and", "mouse", 44, "a", "common_element" }
>>> my_set & another_set

# Output: {'common_element'}

Worth mentioning, a set is mutable both in JavaScript and Python, but single elements inside the set remain immutable.

The membership operator in Python and JavaScript

"Is this element present inside another element"? Membership operators know the answer. Both Python and JavaScript have a membership operator called in:

PYTHON JAVASCRIPT
in in

In Python you can use in on almost any data type. For example you can check if a character appears inside a string:

>>> "o" in "Florence"

# Output: True

It works for lists, tuples, and dictionaries as well:

>>> my_list = ["vale", 98, "caty", None]
>>> 98 in my_list # Output: True

>>> my_tuple = ("vale", "Italy", 105)
>>> "italy" in my_tuple # Output: False

my_dict = {
    "name": "John", 
    "city": "Rome", 
    "age": 44
    }

"age" in my_dict # Output: True

In JavaScript instead the in operator does not work intuitively neither on strings, nor on arrays:

"a" in ["a", "b", "c"]
// output: false

"o" in "Florence"
// output: TypeError: Cannot use 'in' operator to search for 'o' in Florence

It's useless for strings, and does not search for actual elements in the array. What it looks for instead is the array index:

1 in ["a", "b", "c"]
// output: true

It makes sense considering that Array is a subtype of Object and it's more correct to imagine it as an object with the following shape:

var myArr = {
  0: "a",
  1: "b",
  2: "c"
};

To recap, in in JavaScript works only on object keys and returns true if the given key is present in the object:

var my_obj = {"name": "John", "city": "Rome", "age": 44}

"name" in my_obj

// output: true

Instance operators: a disclaimer

"Who created this object"? Instance operators try to answer that question. Now, before you yell at me let me clarify. The following table is just my mental representation of a more complicated story:

PYTHON JAVASCRIPT
isinstance() instanceof
type() typeof

As you'll see it's impossible to map Python and JavaScript 1 to 1 on this matter because Python is truly object oriented, while JavaScript is based on prototypes.

If you know a bit of JavaScript you're aware that "class" is an illusion and every time we talk about classes in JavaScript we're just lying.

But let's demystify my table with some examples.

Python classes, isinstance, and JavaScript instanceof

Consider a Python class with a new object made from it:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def print_details(self):
        details = f"Name: {self.name} - Age: {self.age}"
        print(details)


tom = Person("Tom", 89)

tom.print_details()

What is tom? In object oriented programming we say that it's a class instance, that is, a new object constructed from the class blueprint. isinstance in Python (it's a function more than an operator) returns true if an object appears to be built by a given class. So in our case:

>>> isinstance(tom, Person)

# Output: True

How about JavaScript instead? Here's the same class:

class Person {

    constructor(name, age) {
        this.name = name
        this.age = age
    }

    printDetails() {
        const details = `Name: ${this.name} - Age: ${this.age}`
        console.log(details)
    }

}

const tom = new Person("Tom", 44)

What is tom now? Let's see:

console.log(tom instanceof Person)
// Output: true

An instance!? Not at all. tom is just a poor object connected to Person.prototype via the prototype chain. In fact it is also connected to Object:

console.log(tom instanceof Object)
// Output: true

So the instanceof operator in JavaScript returns true if an object appears to be built by a given class, but not because it's an instance in the strict term. It returns true only because tom is connected to Person.prototype via the prototype chain.

I tried to compare instance operators for both languages and that's the best I could come up with. I consider Python's isinstance() and JavaScript instanceof similar just because of how they behave, but it's still an hazardous comparison.

If so you might wonder, why bringing isinstance() in at all? That leads use to the next section ...

Python type() and JavaScript typeof

Anytime you want to inspect the type of a given value in JavaScript, typeof is your friend:

typeof "alex" // "string"
typeof 9 // "number"
typeof [1,2] // "object"

typeof in JavaScript is convenient when we want to check if a function exists, for example:

if (typeof window.futureStuff === "undefined") {
    window.futureStuff = function () {
        // do stuff    
    }
}

Coming from JavaScript you may want to reach for a similar operator in Python. The type() function might be your first pick because seems related to JavaScript's typeof. But type() returns something different:

>>> type(tom)
# Output: <class 'person.Person'>

>>> type('ahh')
# Output: <class 'str'>

Not so convenient. isinstance() is betted suited for this job here and that's why I brought it in the previous section. Here's how it works:

>>> isinstance(9, int)
# Output: True

>>> isinstance(tom, Person)
# Output: True

>>> isinstance("caty", str)
# Output: True

isinstance() is useful when you need to check a value against another known type. However there might be situation where you need to mimic typeof. In that case you can still use Python's type function by checking objects against builtin types:

>>> type(9) is int
# Output: True

How to handle exceptions in Python: what is an exception?

Would be nice if programs could always work well. But the real world is a bit wild. If a program can fail it certainly will.

Consider a simple Python function. What can go wrong here?

def divide(a, b):
    result = a / b
    return result


divide(89, 6)
divide(89, "6")
divide(89, 2)

Save the code in a file (I called mine exceptions.py) and run it. You'll see a lot of stuff, and more important, a TypeError:

TypeError: unsupported operand type(s) for /: 'int' and 'str'

It comes from the second call to divide, where we tried to divide a number and a string, which is invalid in Python (and in JavaScript as well). The program stops, never reaching the third function call.

What Python does here is raising an exception, that is, an exceptional event that blows up our code.

So exceptions are serious errors that most of the time can halt a program. How we handle exceptions makes the difference between a failing program and one that could recover by itself.

Handling synchronous exceptions in Python and JavaScript

If we stay in a synchronous world, Python and JavaScript are pretty similar when it comes to handling exceptions.

In Python there is try/except. The try block should deal with the "happy path" of your code, while except will intercept the actual exception.

The previous example can be refactored to:

def divide(a, b):
    try:
        return a / b
    except TypeError:
        print("Oops!")

divide(89, 6)
divide(89, "6")
divide(89, 2)

Notice that you should specify the error type on except, TypeError in our case.

try/except means more or less: try this code, if it fails intercept the error and do something else.

Now the program prints "Oops!", but it does not stop anymore. All function calls (except the one erroring out) continue to run.

You discovered how to handle exceptions in Python! How about JavaScript?

Consider the following example (JavaScript):

function find(member, target) {
  return member in target;
}

find("a", "siena");

It's an invalid use of the in operator (it works only on objects).

Run the code, and you should see:

TypeError: Cannot use 'in' operator to search for 'a' in siena

Ok JavaScript, fair enough. To handle errors, in JavaScript there is try/catch. try tries the happy path, while catch deals with the problem.

We can rewrite the code (with another call to find for testing the program) to:

function find(member, target) {
  try {
    return member in target;
  } catch (err) {
    console.log("Oops!");
  }
}

find("a", "siena");
var result = find("city", { name: "Jane", city: "London" });
console.log(result);

Now the program prints "Oops!", "true", and does not stop anymore.

Notice the parameter err? Let's see in the next section how to use it.

Psst. Check out "A mostly complete guide to error handling in JavaScript" for a in-depth guide to errors and exceptions.

How to handle exceptions: using the error message in Python and JavaScript

Handling exceptions is great and all, but printing "Oops" not so. Would be nice to print the error message instead.

In JavaScript, we can use the parameter for catch, most of the times called error or err as a convention. It contains the actual exception object.

In turn, almost every exception has a property called message, with the actual text error. The previous JavaScript example becomes:

function find(member, target) {
  try {
    return member in target;
  } catch (err) {
    console.log(err.message);
  }
}

find("a", "siena");
var result = find("city", { name: "Jane", city: "London" });
console.log(result);

which prints:

Cannot use 'in' operator to search for 'a' in siena
true

Way better than "Oops".

In Python, you can do the same, with as:

def divide(a, b):
    try:
        return a / b
    except TypeError as err:
        print(err)

The example speaks for itself: intercept TypeError and create a binding named err for convenience. Then print the error.

Raising your own exceptions in Python and JavaScript

As with almost anything in programming, the terminology is blurry, even for simplest things.

Take the term throw for example. It's common to say "throwing" in JavaScript when we developers need to terminate the program and say, "ehi, this is not good, let's stop".

Errors can be thrown by the JavaScript engine or on purpose by developers when checking for invalid values.

We can also say "raising" instead of throwing, and call errors "exceptions". Why would you raise or throw an error? Consider the JavaScript example again. We know that the in operator works well only on objects.

If we check the parameter target we can throw an error when it's a string. Here's how:

function find(member, target) {
  if (typeof target === "string")
    throw TypeError("Target must be an object, got string");

  try {
    return member in target;
  } catch (err) {
    console.log(err.message);
  }
}

Now call the function:

find("a", "siena");

The net effect of adding throw is that the consumer of this function will get the error back:

Error: Target must be an object, got string

This is expected, we want to stop the execution if target is a string, so the code will never reach the try block.

Now let's go back to Python. We left with this code:

def divide(a, b):
    try:
        return a / b
    except TypeError as err:
        print(err)

Here we can check if both parameters are numbers before dividing them, and then throw an error. The throw counterpart in Python is raise:

def divide(a, b):
    if isinstance(a, str) or isinstance(b, str):
        raise TypeError("Expected in, got object")
    try:
        return a / b
    except TypeError as err:
        print(err)

When calling the function with:

divide(1, "2")

you should see:

TypeError: Expected in, got object

Notice this time the use of TypeError for creating a custom error message. If you want you can also extend Exception to create your own custom exception:

class CustomError(Exception):
    pass


def divide(a, b):
    if isinstance(a, str) or isinstance(b, str):
        raise CustomError("Expected in, got object")
    try:
        return a / b
    except TypeError as err:
        print(err)


divide(1, "2")

As an alternative to raise we can also use assert, handy for debugging in development:

def divide(a, b):
    assert isinstance(a, str), "Expected int, got object"
    assert isinstance(a, str), "Expected int, got object"
    try:
        return a / b
    except TypeError as err:
        print(err)


divide(1, "2")

Code documentation in Python with reStructuredText

In JavaScript we use JSDoc to add documentation for classes, functions parameters, function return values, and so on. Here's an example of a JSDoc annotated function:

/**
 * Raises a number to exponent
 * @param {number} value - The base to raise
 * @param {number} exponent - The exponent
 * @return {number} - The exponent power
 */
function poooow(value, exponent) {
  return value ** exponent;
} 

Notice the type "number" on parameters and return. By adding these type hints you help the IDE to help you (no pun intended) when you use the function. The same concept applies to Python.

How to add code documentation in Python? Actually there are many ways, but reStructuredText is one of the recommended approaches. reStructuredText is plaintext, and can be embedded into Python Docstrings.

A Docstring is just a string that happens to live inside Python functions or modules, and acts as documentation for your code. To give you a bit of context here's an example of Docstring inside a Python function:

def string_repeat(string, count):
    """
    Repeats a string N times
    """
    return string * count

reStructuredText comes into play when you decide to add documentation for parameters and return values. Here's our example, enriched with reStructuredText:

def string_repeat(string, count):
    """
    Repeats a string N times
    :param string: The string to repeat
    :param count: The number of repeats
    :return: The string repeated N times
    """
    return string * count

I know, documentation may look redundant, but reStructuredText can shines if you decide to dip your toes into static typing. First things first, a bit of type theory.

A bit of type theory: dynamic typing vs static typing

Python and JavaScript are dynamic languages. That is, they give almost absolute freedom to programmers. In JavaScript for example a variable might contain a string at first, and later be changed to contain a boolean. The JavaScript engine won't complain. (However, you can prevent re-assignment of primitive types with const).

Python does the same. Consider the following example:

>>> name = "Caty"
>>> name = True
>>> print(name)
True

The variable name has a string type at first, but then gets changed to a boolean type. Most of the times with self-discipline you can tame dynamic typing and sleep at night. There are situations where dynamic typing might not be allowed, or too risky (think of financial systems).

Opposed to dynamic typing, static typing means assigning a fixed type to every variable, so that becomes more difficult to change a type by accident.

However, static typing is a different beast, and learning it might be a painful process, especially for beginners.

Luckily, both in JavaScript and Python we can use documentation for "gradual typing".

Let's see in the next section how to add types with reStructuredText in Python.

Gradual typing in Python with reStructuredText

With reStructuredText you can get your feet wet with static typing in Python without adding actual types in the code.

In addition to common tags like ":param" and ":return", reStructuredText has also :type and :rtype, used respectively for adding types to parameters and return values.

If you want to follow along with the code it is a good time to create and activate a Python virtual environment (in the next section we'll need to install mypy too):

mkdir docs_and_typings && cd $_

python3 -m venv venv

source venv/bin/activate

To illustrate the example create a new file named my_str_utils.py in your project folder with the following function:

def string_repeat(string, count):
    """
    Repeats a string N times
    :param string: The string to repeat
    :param count: The number of repeats
    :return: The string repeated N times
    """
    return string * count

Now let's add types in reStructuredText with :type and :rtype:

def string_repeat(string, count):
    """
    Repeats a string N times
    :param string: The string to repeat
    :type string: str
    :param count: The number of repeats
    :type count: int
    :return: The string repeated N times
    :rtype: str
    """
    return string * count

This is gradual typing: you have now a typed function, without the cognitive load of a static type system. Most IDE are able to read reStructuredText types, in PyCharm for example you'll be warned when a parameter's type don't match the actual argument's type:

Python gradual typing

Also in Pycharm, by clicking on a function's name and pressing Ctrl+Q (or F1 on MacOs) you can get actual type hints:

Pycharm type hints

Those hints are the same as the "real type hints" that we're going to see in the next section (most of the times PyCharm is able to infer the return type even without :rtype, just by inspecting the return statement).

In JavaScript, we can get the same effect with JSDoc types.

Static Typing in Python and JavaScript

The definition of gradual typing I gave earlier is a bit blurry. It is true that you can get into static typing through code documentation in docstrings.

But a stricter interpretation of gradual typing is: the process of adding real types gradually in your code. And by types now I mean type annotations that can be checked with a tool.

JavaScript has TypeScript: a layer on top of JavaScript that you can plug into. TypeScript is an actual language on its own, but can fit into any JavaScript codebase, gradually.

The same holds true for Python: in recent years it gained an optional type system based on "type hints". Here we'll see Python type hints from 30,000 feet. Once grasped the basics hopefully you'll be able to apply types to your Python code. Let's take string_repeat from the previous section:

def string_repeat(string, count):
    """
    Repeats a string N times
    :param string: The string to repeat
    :type string: str
    :param count: The number of repeats
    :type count: int
    :return: The string repeated N times
    :rtype: str
    """
    return string * count

This time we're going to strip out reStructuredText types:

def string_repeat(string, count):
    """
    Repeats a string N times
    :param string: The string to repeat
    :param count: The number of repeats
    :return: The string repeated N times
    """
    return string * count

At this point the IDE will loose all the hints. But if you remember from previous section "real" type hints are like "parameter: type", so it should be easy to add them in the function signature:

def string_repeat(string: str, count: int):
    # omit

The style is similar to that used by TypeScript. You can also type the return value with -> type:

def string_repeat(string: str, count: int) -> str:
    """
    Repeats a string N times
    :param string: The string to repeat
    :param count: The number of repeats
    :return: The string repeated N times
    """
    return string * count

Once the code is type annotated you can check its correctness with a tool called mypy, our topic for the next section.

Checking types with mypy

mypy is a type checker for Python. To install mypy in your test project make sure to activate the virtual environment and then run:

pip install mypy

Open up my_str_utils.py and try to use string_repeat with a float instead of an int:

def string_repeat(string: str, count: int) -> str:
    """
    Repeats a string N times
    :param string: The string to repeat
    :param count: The number of repeats
    :return: The string repeated N times
    """
    return string * count


string_repeat('hello', 15.6)

The IDE will warn you, but you can also use mypy against the Python script:

mypy my_str_utils.py

mypy will warn you as well:

my_str_utils.py:11: error: Argument 2 to "string_repeat" has incompatible type "float"; expected "int"
Found 1 error in 1 file (checked 1 source file

Opposed to TypeScript, which compiles to "vanilla" JavaScript, mypy does not produce any code, it just checks its types.

Python for JavaScript developers: going further

Other articles you might be interested in:

Thanks for reading and stay tuned on this blog!

Valentino Gagliardi

Hi! I'm Valentino! I'm a freelance consultant with a wealth of experience in the IT industry. I spent the last years as a frontend consultant, providing advice and help, coaching and training on JavaScript, testing, and software development. Let's get in touch!