What JavaScript can learn from Python

I recently started working at a company with a legacy system written in Python, which has also been my first introduction to Python as a programming language. Coming from the JavaScript/TypeScript world, there has been a few interesting language design decisions that Python has that I wish JavaScript had as well.

I am only starting my Python discovery journey now, so I will most likely update this post as I find new gems.

The sum() function

Python has a bunch of global functions that are available anywhere within the source code. One of these is the sum() function.

This function allows you to quickly calculate the total of a list of values (there are other use-cases as well):

listOfNumbers = [123, 75, 434, 234, 8472]

total = sum(listOfNumbers)

print(total)  # prints out: 9338

In JavaScript, you could implement your own sum() function with:

const sum = (list, startValue = 0) =>
  list.reduce((acc, item) => (acc += item), startValue)

This is not a lot of code to write yourself, but it is nice that Python gives it to you for free.

The sorted() function

Like JavaScript, Python also has a .sort() method that you can invoke on a list and like JavaScript, this will mutate the list/array in place. Mutating values has its place, but most often it is best to avoid them to make your code more predictable.

Python gives you the global sorted() function that solves this nicely, ie. you can sorted a given list without mutating the original list. This function doesn't only work on Python lists, but can also be used to sort tuples and dictionaries (objects or maps).

unsortedList = ["a", "d", "c", "b"]

sortedList = sorted(unsortedList)

print(sortedList) # prints out: ['a', 'b', 'c', 'd']
print(unsortedList) # prints out: ['a', 'd', 'c', 'b']

To create a new list sorted in descending order, you can simply pass a reverse=True keyword argument (the Pythonians call these kwargs which is kwite kwool):

sortedList = sorted(unsortedList, reverse=True)

JavaScript doesn't have this, so the easiest is probably to do something like this:

const sorted = (list, reverse = false) => {
  const clonedList = list.slice()
  clonedList.sort()

  if (reverse) {
    clonedList.reverse()
  }

  return clonedList
}

I don't know how Python does it internally, so hopefully a bit more performant than the JavaScript example I gave above. 🤷‍♂️

There is more to the sorted() function, but the main point I wanted to bring is the immutability of it.

Object comparison

Python does not have the strict equality (===) and loose equality (==) concept that you get in JavaScript. Python uses == to compare values for all types. In a way it behaves like JavaScript's strict equality, but not exactly.

For instance, take "2" == 2:

In JavaScript, that will evaluate to true since the 2 integer will be cast to the "2" string and it will be equal. In Python, it will evaluate to False because nothing will be cast, you need to be explicit with your types. To get this expression to evaluate to True, you would need to explicitly cast one of the values to the other's type: int("2") == 2 or "2" == str(2).

Up until here, it is debateable which behaviour is better. I'm someone that loves JavaScript for what it is, so I do embrace loose equality where it makes sense to do, but some people feel very strong about only using strict equality and even implement ESLint rules to enforce this. To each their own.

Where Python does better is when it comes to comparing objects. In JavaScript, objects (of all kinds), are compared by reference, which simply means that it compares the address of where the value is stored in memory instead of what is stored in the memory slot.

const objectA = { key: 'value' }
const objectB = { key: 'value' }

console.log(objectA === objectB)
console.log(objectA == objectB)

// Both of these comparisons will evaluate to `false` since they are different objects

Python actually compares the values in the object to determine if it is equal:

objectA = { "key": "value" }
objectB = { "key": "value" }

print(objectA == objectB)
# This comparison will evaluate to `True` because the values inside each object are the same

If you wanted to compare whether two objects are in fact the same object stored at the same address in memory, Python has you covered with the is operator:

objectA = { "key": "value" }
objectB = { "key": "value" }

print(objectA is objectB)
# This comparison will evaluate to `False` because these are not the same objects

objectC = objectA

print(objectA is objectC)
# This comparison will evaluate to `True` because these are the same objects in memory

This leads me to my next point, which is more a nice to have and probably not all that useful in practice, the id() global function.

The id() function

Each value (in any language really) is stored somewhere in the device's memory. Python makes it easy to find this reference or ID by using the global id() function.

someNumber = 123

print(id(someNumber)) # prints out the reference number for the given value (4326821360 in my case, but this will be different for you)

This is essentially how Python's is operator works as well. Taking the example from my previous point, it could be compared this way as well:

objectA = { "key": "value" }
objectB = objectA

print(objectA is objectB)
print(id(objectA) == id(objectB))
# These comparisons are equivalent and both will return `True` as they are the same objects

The object.get() method

In JavaScript, if you try and read a non-existent property from a object with object['someNonExistingKey'], you will simply get back undefined. Python doesn't do that, it throws an error. That doesn't sound better, but it is because it ensures you are more explicit about the data structures you're working with.

Python has a built-in method on objects called .get(), which is basically the equivalent of Lodash's _.get() method in JavaScript:

person = { "name": "Adam" }

name = person.get("name", "Eve")

print(name) # prints out: 'Adam'

age = person.get("age", 25)

print(age)  # prints out: 25

This method will not throw an error when trying to access a property (age) from the person object that doesn't exist, but will use the optional default values given as a second parameter as a fallback. Or alternatively, it will be None.

No var, let or const debates

TODO: Write this piece 🚢


If you have any other great Python features that you wished JavaScript had, please share them so I can also learn from you.