Python compared to JavaScript

This document provides a comparison of the most commonly used features of Python and JavaScript. Lesser used features are omitted.

Overview

TopicJavaScriptPython
standardECMAScriptPython 3 documentation
evaluationdynamicdynamic
performancefastslow unless libraries call C/C++ functions
style guidePrettierPEP 8, Black
most common indentation2 spaces4 spaces (not tabs)
type coercionimplicitexplicit except between number types

Note: PEP stands for Python Enhancement Proposal.

Some oddities about Python code formatting include:

Pros and cons

JavaScript

pros:

cons:

Python

pros:

cons:

Running scripts

JavaScript source files have an extension of .js or .mjs (for ECMAScript modules).

To run a JavaScript script outside a web browser:

Python source files have an extension of .py. Multiple words in file names should be separated by underscores rather than hyphens because the file name becomes the module name and hyphens are not valid in module names. Avoid using file names that match that of an existing module because doing so will prevent being able to import the existing module.

To run a Python script:

In both cases, command line arguments can be passed to the script.

A JavaScript script running in Node.js can get them from the array process.argv. The first element is the path to the node executable, the second is the path to the script that is running, and the remaining elements are the command line arguments.

A Python script can get them from sys.argv. The first element is the path to the script that is running, and the remaining elements are the command line arguments.

To make a Python source file directly executable in UNIX systems:

To automatically restart a script when it or a file it imports is modified:

  1. Install Node.js.
  2. npm install -g nodemon
  3. If running a JavaScript script, enter nodemon {name}.js
  4. If running a Python script, enter nodemon --exec python3 {name}.py.

Getting help

In JavaScript, perform web searches that begin with "MDN" (for the Mozilla Developer Network) followed by a JavaScript search term. For example, "mdn regexp".

For Python help, see the list of resources at the end. You can also enter the python command to start the REPL and enter help() to start the help utility. Once inside, enter the name of a module to get help on it. To exit the help utility and return to the Python REPL, enter quit or just q.

Alternatively, once a module has been imported, help on it can be obtained by passing it to the help function. For example:

import re # for regular expressions
help(re)

Comments

TypeJavaScriptPython
single-line//#
multi-line/* ... */none

Workarounds for multiline comments in Python include using triple-quoted strings and adding if False: before a code block.

Naming conventions

KindJavaScriptPython
constantUNDER_SCORESsame
variablecamelCaseunder_scores
functioncamelCaseunder_scores
classCamelCasesame
methodcamelCaseunder_scores
public instance propertiescamelCaseunder_scores
private instance propertiesno convention_under_scores

While Python uses a naming convention to identify constants (all uppercase), they can still be modified. And the naming convention for private instance variables (start with an underscore), doesn't prevent access from outside the class.

Many Python libraries, including the standard library, deviate from the Python naming conventions. In particular, it is common to find multi-word function and method names that are all lowercase with no separator between words. For example, the functools standard library defines the functions partial_method (follows convention) and singledispatchmethod (does not).

Built-in types

TypeJavaScriptPython
Booleantrue, falseTrue, False
numberdefault is double precision float, BigIntint, float, complex
characteruse stringssame
string'text' or "text"same
multi-line string`text`"""text""" or '''text'''
string interpolation`prefix${expr1}suffix${expr2}`f'prefix{expr1}suffix{expr2}'
arrayArray class, literal syntax [v1, v2, ...]array module in standard library
listuse Array classlist class with literal syntax [v1, v2, ...]
mutable and typically homogeneous
tupleno equivalenttuple class with literal syntax (v1, v2, ...)
immutable and typically heterogeneous
rangeno equivalentrange class
range(start, stop[, step])
key/value pairsObject class with literal syntax
{k1: v1, k2: v2, ...} and Map
dict class with literal syntax
{'k1': v1, 'k2': v2, ...}
setSet class;
create with new Set()
set class with literal syntax {v1, v2, ...}
or set(v1, v2, ...)
functionsee "Functions" section belowsee "Functions" section below
classclass Name { ... }
see "Classes" section below
class Name:
see "Classes" section below
no valueundefined or nullNone

Everything is an object in Python, even values that are primitives in JavaScript like Booleans, numbers, and strings.

Python has "sequences" whereas JavaScript has arrays. Kinds of sequences include string, list, tuple, range, set, and buffer. A list is a mutable sequence of values that typically have the same type. A tuple is an immutable sequence of values that can have varying types. A range is an immutable sequence of numbers that is often be used for looping.

JavaScript object keys must be strings, but Map keys can be any kind of value. Python dict keys can be any immutable type.

The values that are treated as false when used in a Boolean context are listed below:

LanguageFalse Values
PythonFalse, 0, 0.0, 0j (complex), empty strings, empty sequences, and None
JavaScriptfalse, 0, NaN, empty strings, undefined, and null

In JavaScript empty collections evaluate to true. These include arrays, objects, Map instances, and Set instances.

In Python the "not a number" value math.nan evaluates to true.

Modules

In both JavaScript and Python, modules are defined by a single source file. A source file can import other modules and those can import more modules.

In both JavaScript and Python each module is only imported once. If its code is modified, the script must be re-run to interpret the changes.

JavaScript modules that are imported with a relative file path are only searched for in that location. JavaScript modules that are imported with only a name are searched for in the project node_modules directory and the global node_modules directory.

Python searches for modules in the following order:

To see the directories that will be searched, import sys and execute print(sys.path).

Several module-related topics are described in the following table:

TopicJavaScriptPython
a module is defined by ...content of filesame
exportexport name = value;everything is automatically exported;
indicate private values by starting name with an underscore
default exportexport default name = value;not supported
import defaultimport name from 'path';not supported
import entire moduleconst name from 'modname';import modname or
import modname as other or
from modname import *
import specific valuesconst {name1, name2} from 'modname'; or
const {name1 as other1, name2 as other2} from 'modname';
from modname import name1, name2 or
from modname import name1 as other1, name2 as other2
import default and namedimport name, {name1, name2} from 'path';not supported
open source cataloghttps://www.npmjs.com/https://pypi.org/
tool to installnpm (installed with Node.js)pip (installed with Python) or
conda (installed with Anaconda)

In Python aliases are typically assigned to commonly used packages. The community has landed on using the aliases shown in the imports below.

PackageRecommended Import
collections
in standard library
import collections as co
functools
in standard library
import functools as ft
itertools
in standard library
import itertools as it
matplotlibfrom matplotlib import pyplot as plt
NumPyimport numpy as np
pandasimport pandas as pd
TensorFlowimport tensorflow as tf

Packages

JavaScript packages

JavaScript "packages" are managed using the npm tool which is install with Node.js is installed. To allow each project to use different versions of packages and make it easy for other developers to install the same set of packages, create a package.json file in each project by entering npm init and answering some questions.

Python packages

Python "packages" are managed using the pip tool which is installed when Python is installed. The name is an acronym for "Pip Installs Packages". It installs packages from the Python Package Index (pypi). To upgrade the version of pip being used, enter python -m pip install --upgrade pip.

To allow each project to use different versions of packages and make it easy for other developers to install the same set of packages, create a virtual environment. There are several tools that can be used to do this. Options include Anaconda, virtualenv (primarily for Python 2), and venv (a subset of virtualenv for Python 3).

To create a virtual environment using venv, enter python -m venv env while in the project root directory. This creates an env subdirectory.

To activate this virtual environment, run the activate script in the env/bin directory. In Windows, enter env\bin\activate.bat. In UNIX environments, enter source env/bin/activate. (When using the Fish shell, add the .fish extension.)

Activating a virtual environment changes the environment to use versions of tools and libraries found in the project env directory instead of global ones. Note that rather than including a copy of a specific version of the Python interpreter, a symbolic link to it is created. This also changes the shell prompt to indicate the environment directory being used, env in this case.

To deactivate a virtual environment and return to using global versions of tools and libraries, enter deactivate.

Note that Python virtual environments must be activated to take effect. This differs from Node.js where simply changing to the directory of a project causes its dependencies versions to be used based on the contents of the node_modules subdirectory.

For details on using Anaconda to manage virtual environments, see here.

Using packages

OperationJavaScriptPython
prepare a projectnpm init [-y]python -m venv env
where env is the directory name used by convention
install a package globallynpm install -g {pkg-name}with no environment activated,
pip install {pkg-name}
install a package locallynpm install {pkg-name}with an environment activated,
pip install {pkg-name}
install a specific version of a packagenpm install {pkg-name}@{version}pip install {pkg-name}=={version}
update to latest version of a specific packagenpm update {pkg-name}pip install --upgrade {pkg-name}
see where global packages are installednpm -g rootwith no environment activated,
pip list -v
see where local packages are installednpm rootwith an environment activated,
pip list -v
location of local packages{project-dir}/node_modules{project-dir}/lib/python{version}/site-packages
see list of locally installed packagesnpm ls or
open package.json and see
dependencies and devDependencies
with environment activated, pip list
create list of project package versionsautomatically maintained in package.jsonpip freeze > requirements.txt
install project package versionsnpm installpip install -r requirements.txt

Project Python packages

Project Python packages enable importing modules from subdirectories. These are subdirectories whose names are a package name. The subdirectories must contain a __init__.py file that can be empty or contain initialization code for the package.

Add .py files in the package directories that define modules. Then in .py files that wish to use a module in a package (located in ancestor directories), use from package-name import module-name. To import specific things from package modules, use from package-name.module-name import name1, name2.

The directory structure can be as deep as you like with each subdirectory containing a __init__.py file. When there are nested packages, imports look like from pkg1.pkg2 import module-name or from pkg1.pkg2.module-name import name1, name2.

For more information on Python packages, see the Packages in the Python Tutorial.

Printing/logging

OperationJavaScriptPython
write space-separated values to stdoutconsole.log(v1, v2, ...);print(v1, v2, ..)
write space-separated values to stderrconsole.error(v1, v2, ...);import sys
print(v1, v2, ..., file=sys.stderr)
write to stdout with interpolationconsole.log(`Hello ${name}, today is ${dayOfWeek}.`);print(f'Hello {name}, today is {dayOfWeek}.')
write to stdout without newlinein Node.js
const process = require('process');
process.stdout.write(v1, v2, ...);
print(v1, v2, ..., end='')

Variables and assignment

JavaScript variables should be declared using either the const or let keyword. Python variables are not declared and are created when a value is assigned to them.

JavaScript variable assignments can appear inside expressions such as an if or loop condition, which many developers find confusing. This was not allowed in Python until version 3.8 which adds the "walrus operator" for assigning values to variables inside larger expressions. For example:

from calendar import day_name
from datetime import date

def get_day():
index = date.today().weekday()
return day_name[index]

if (day := get_day()) == 'Tuesday':
print('Tacos!') # Tacos! if it's a Tuesday

print('day =', day) # Tuesday

# Typically the code is easier to read when
# the walrus operator is not used. For example:
day = get_day()
if day == 'Tuesday':
print('Tacos!') # Tacos! if it's a Tuesday

The pylint Python linting tool treats module-level variables as constants. It will output warnings if functions modify their values. To avoid this, list all such variables to be modified after the global keyword inside functions that modify them. The related keyword nonlocal enables functions to access variables in ancestor scopes that are not global.

TopicJavaScriptPython
constant declarationconst NAME = value;NAME = value
variable declarationlet name = value;name = value
get type of value in variabletypeof v and v.constructor.nametype v:
multiple assignmentconst [a, b] = [1, 2]a, b = 1, 2
destructure sequenceconst [v1, v2, ...] = array;
# of variables can differ from # of elements
v1, v2 = seq
# of variables must match # of elements
destructure objectconst {k1, k2, ...} = object;not supported
un-declare variablename = undefined - just removes valuedel name
additionname += exprsame
subtractionname -= exprsame
multiplicationname *= exprsame
divisionname /= exprsame
exponentiationname **= exprsame
mod (remainder)name %= exprsame
logical andname &&= exprnot supported
logical orname ||= exprnot supported
logical xorname ^= exprnot supported
bitwise andname &= exprsame
bitwise orname |= exprsame
bitwise xorname ^= exprsame
signed bit shift<<= (left), >>= (right)same
unsigned bit shift<<<= (left), >>>= (right)not supported

JavaScript destructuring can capture multiple values in one array variable. For example:

const arr = [1, 2, 3, 4];
[a, b, ...rest] = arr; // a=1, b=2, rest=[3, 4]

The rest variable above is set to an array. The "rest operator" ... must appear before the last variable.

Python refers to this operation as "unpacking" and it's even more capable.

seq = (1, 2, 3, 4) # using a tuple, but could also be a list
a, b, *rest = seq # a=1, b=2, rest=[3, 4]
a, *rest, b = seq # a=1, rest=[2, 3], b=4
a, b, *rest = seq # a=1, b=2, rest=[3, 4]

The rest variable above is set to a list.

Comparison

TopicJavaScriptPython
equal== (with coercion) or === (without)== (without coercion)
not equal!= (with coercion) or !== (without)!= (without coercion)
same object===is
different object!==is not
less than<same
less than or equal<=same
greater than>same
greater than or equal>=same

Python comparisons can be chained, but JavaScript comparisons cannot. For example, to determine whether the value of a variable is between 10 and 20 inclusive:

Code blocks

JavaScript code blocks are surrounded by curly brackets ({ code }). Long statements can be split over multiple lines without including any special character at the ends of initial lines.

Python uses leading whitespace (indentation) to determine which lines are part of the same block. All consecutive lines with the same indentation, ignoring empty lines, are considered to be in the same block. For the purpose of this determination, tab characters are replaced by spaces so that the number of spaces is a multiple of eight. This is significant when a mixture of tabs and spaces are used, which is not recommended. Python style guides recommend using multiples of four spaces for indentation and not using tab characters. Long statements can be split over multiple lines by adding a backslash (\) at the end of all but the last line when it is not clear that a statement is continuing.

Conditional logic

In the JavaScript syntax below, sOrB is short for "statement or block". It can be a single statement or a set of statements surrounded by curly braces.

A JavaScript if statement can contain any number of else if parts. A Python if statement can contain any number of elif parts. Python blocks must start on a new line and be indented.

TopicJavaScriptPython
ifif (cond) sOrBif cond: block
if/elseif (cond) sOrB1 else sOrB2if cond: block1 else: block2
if/else if/elseif (cond1) sOrB1 else if (cond2) sOrB2 else sOrB3if cond: block1 elif cond2: block2 else: block3
switchswitch (expr) { case v1: case v2: default }not supported
ternarycond ? trueValue : falseValuetrueValue if cond else falseValue

Here's an example of using a Python ternary statement.

import sys

name = sys.argv[1] if len(sys.argv) > 1 else 'World'

# This is a nice alternative.
name = sys.argv[1] or 'World'

# This syntax is NOT supported.
name = len(sys.argv) > 1 ? sys.argv[1] : 'World'

Iteration

As we will see in the "Key/value collections" section later, JavaScript can store key/value pairs in plain objects or in instances of the Map class. Python uses "dictionaries" (or dicts) to store key/value pairs.

TopicJavaScriptPython
classic for loopfor (let index = start; index < stop; index += step)for value in range(start, stop, step?):
over collectionfor (const value of iterable)for value in iterable:
over object/dict keysfor (const key of Object.keys(obj))
or for (const key in obj)
for key in dict.keys():
over object/dict valuesfor (const value of Object.values(obj))for value in dict.values():
over object/dict keys and valuesfor (const [key, value] of Object.entries(obj))for key, value in dict.items():
top-testedwhile (cond)while cond:
bottom-testeddo { ... } while (cond);while True: ... if !cond: break
break out of closest loopbreaksame
continue to next iterationcontinuesame

Functions

In JavaScript, functions can be defined in two ways.

// Named function
function myFn(p1, p2, ...) {
body
}

// Anonymous function (a.k.a. arrow function)
const myFn = (p1, p2, ...) => {
body
};

If an anonymous function has exactly one named argument, the parentheses around it are optional. If an anonymous function simply returns the value of a single expression, The curly braces around the body and the return keyword are optional.

In Python, functions can also be defined in two ways.

# Named function
def myFn:
body

# Lambda function
lambda args: expression

Python lambda functions can only return the value of a single expression. They cannot contain additional statements.

Python named functions can have a docstring as their first line. This is used by tools that generate documentation from code. It is typically delimited by triple quotes. For guidelines on the content of docstrings, see the Documentation Strings in the Python Tutorial and PEP-8 documentation strings. A good docstring for a function looks like:

    """Return the average of a sequence of numbers."""

JavaScript does not support function overloading where the same function name can be defined multiple times with different numbers and/or types of arguments. Python supports this in a limited sense using the singledispatch decorator defined in the functools standard library.

TopicJavaScriptPython
define namedfunction fnName(params) { ... }def fnName(params): ...
define anonymousconst fnName = (params) => definitionlambda params: expression
define anonymous w/ single parameterconst fnName = param => {...}same as above
define anonymous w/ single expressionconst fnName = (params) => exprsame as above
specify default parameter valuesfunction fnName(p1=v1, p2=v2) {...}def fnName(p1=v1, p2=v2): ...
gather variable number of argumentsfunction fnName(p1, p2, ...rest) {...}
rest is set to an Array
def fnName(p1, p2, *rest): ...
rest is set to a tuple
gather arguments as key/value pairsnot supporteddef fnName(**args): ...
call with fnName(p1=v2, p2=v2)
or fnName(**dict)
use named/keyword argumentsfunction fnName({p1, p2}) {...}
pass an "options" object
same as above;
any parameter can be specified by name;
important feature!
call with fnName(p1=v2, p2=v2)
return a valuereturn value;return value
default return value when no returnundefinedNone
callfnName(args)same
get required argument countfnName.lengthfrom inspect import getfullargspec
len(getfullargspec(fn).args)
passing fewer arguments than
positional parameters
remaining are assigned undefinedresults in an error
passing more arguments than
positional parameters with no gathering
all arguments are available in arguments array-like objectresults in an error
get namefnName.namefnName.__name__
get implementation codefnName.toString()from inspect import getsource
getsource(fn)
create partialconst newFn = fnName.bind(thisValue, arg1, arg2, ...)
thisValue can be null
from functools import partial
newFn = partial(fn, arg1, arg2, ...)
callfnName.call(thisValue, arg1, arg2, ...)
thisValue can be null
ClassName.methodName(obj, arg1, arg2, ...)
applyfnName.apply(thisValue, argArray)
thisValue can be null
ClassName.methodName(obj, *argList)
spread array to positional argumentsfnName(...arr)fnName(*seq)
spread object to keyword argumentsnot supportedfnName(**dict)

In Python:

Execute later or at intervals

In JavaScript, the setTimeout function registers a function to be called after some number of milliseconds in the future. For example:

function myFunction(p1, p2) {
console.log('myFunction: p1 =', p1, 'p2 =', p2);
}

// Call function above after one second.
const id1 = setTimeout(() => myFunction('arg1', 'arg2'), 1000);
if (tiredOfWaiting) clearTimeout(id1);

In Python the same can be done as follows:

import threading

def my_function(p1, p2):
print('my_function: p1 =', p1, 'p2 =', p2)

# The Timer function takes the number of seconds to wait,
# the function to call, and a tuple of arguments to be passed.
t = threading.Timer(1.0, my_function, ('arg1', 'arg2'))
t.start()
if tired_of_waiting:
t.cancel()

In JavaScript, the setInterval function registers a function to be called repeatedly every some number of milliseconds. For example:

// Call the function above once every two seconds.
const id2 = setInterval(() => myFunction('arg1', 'arg2'), 2000);
if (tiredOfWaiting) clearInterval(id2);

// Cancel interval after five seconds.
setTimeout(() => clearInterval(id2), 5000);

In Python there is no simple equivalent. But the same can be done if we define and use a class as follows:

import threading
import time

class SetInterval:
def __init__(self, seconds, fn, args):
self.seconds = seconds
self.fn = fn
self.args = args
self.event = threading.Event()
threading.Thread(target=self.__set_interval).start()

def __set_interval(self):
next_time = time.time() + self.seconds
while not self.event.wait(next_time - time.time()):
next_time += self.seconds
self.fn(*self.args)

def cancel(self):
self.event.set()

def my_function(p1, p2):
print('my_function: p1 =', p1, 'p2 =', p2)

interval = SetInterval(2, my_function, ('arg1', 'arg2'))
if tired_of_waiting:
interval.cancel()

# Cancel interval after five seconds.
threading.Timer(5, lambda: interval.cancel()).start()

Asynchronous functions

In Python 3.4+, asynchronous functions are supported by the asyncio library.

TopicJavaScriptPython
define async named functionasync function fnName(params) { ... }async def fnName(params):
define async anonymous functionconst fnName = async (params) => { ... }not supported
async call with awaitconst result = await name(args);
often wrapped in a try block
result = await name(args)
async call with then and catchname(args).
  then(result => { ... }).
  catch(err => { ...});
n/a

In JavaScript, async functions return a Promise object. Here is an example of running tasks that take a simulated amount of time to complete. The first takes 3 seconds, the second takes 2, and the third takes 1. Each tasks outputs its "starting" message immediately. The "ending" messages appear in reverse order due to their differing sleep durations.

const sleep = async ms => new Promise(resolve => setTimeout(resolve, ms));

async function doIt(name, sleepMs) {
console.log('starting', name);
await sleep(sleepMs);
console.log('ending', name);
}

async function main() {
const task1 = doIt('alpha', 3000);
const task2 = doIt('beta', 2000);
const task3 = doIt('gamma', 1000);
await Promise.all([task1, task2, task3]);
console.log('finished');
}

main();

The output is:

starting alpha
starting beta
starting gamma
ending gamma
ending beta
ending alpha
finished

In Python 3.4, the asyncio library was added. It can be used to create coroutines which are similar to JavaScript Promises. The Python language doesn't provide the equivalent of the JavaScript promises, but libraries do.

Here is an implementation of the previous JavaScript example in Python that produces the same output:

from asyncio import create_task, gather, run, sleep

async def doIt(name, sleepMs):
print('starting', name)
await sleep(sleepMs / 1000)
print('ending', name)

async def main():
task1 = create_task(doIt('alpha', 3000))
task2 = create_task(doIt('beta', 2000))
task3 = create_task(doIt('gamma', 1000))
await gather(task1, task2, task2)
print('finished')

run(main())

Classes

TopicJavaScriptPython
defineclass CName { ... }class CName: ...
inheritanceclass Sub extends Super { ... }
only single inheritance is supported
class Sub(Super1, Super2, ...)
multiple inheritance is supported
constructorconstructor(params) { ... }def __init__(self, params):
instantiate (create instance)const instance = new CName(args);instance = CName(args)
instance property declarationnot declared; set in constructor on this objectnot declared; set in __init__ on self object
instance property referencethis.propNameself.propName
class/static property declarationstatic propName = value;propName = value;
class/static property referenceCName.propNameCName.propName or instance.propName
instance methodname(params) { ... }def name(self, params): ...
class/static method declarationstatic name(params) { ... }@staticmethod
def name(params): ...
class/static method callCName.name(params)CName.name(params) or instance.name(params)

In addition to the @staticmethod decorator, Python also supports the @classmethod decorator. The difference is that methods defined with the latter are passed the class as the first argument.

Here is an example of a JavaScript class:

class Statistics {
constructor(...numbers) {
this.numbers = numbers;
this.min = Math.min(...this.numbers);
this.max = Math.max(...this.numbers);
this.sum = this.numbers.reduce((acc, n) => acc + n, 0);
}

add(number) {
this.numbers.push(number);
this.sum += number;
if (number < this.min) {
this.min = number;
} else if (number > this.max) {
this.max = number;
}
}

mean() {
return this.sum / this.numbers.length;
}

report() {
console.log('min =', this.min);
console.log('max =', this.max);
console.log('mean =', this.mean());
}
}

const stats = new Statistics(1, 2, 3, 4);
stats.report();
stats.add(5);
stats.report();

The output is:

min = 1
max = 4
mean = 2.5
min = 1
max = 5
mean = 3

Here is the same class implemented in Python:

class Statistics:
def __init__(self, *numbers):
self.numbers = list(numbers)
self.min = min(*self.numbers)
self.max = max(*self.numbers)
self.sum = sum(numbers)

def add(self, number):
self.numbers.append(number)
self.sum += number
if number < self.min:
self.min = number
elif number > self.max:
self.max = number

def mean(self):
return self.sum / len(self.numbers)

def report(self):
print('min =', self.min)
print('max =', self.max)
print('mean =', self.mean())

stats = Statistics(1, 2, 3, 4)
stats.report()
stats.add(5)
stats.report()

The output is the same as above.

Note how in Python the first parameter in all instance methods must be self.

Here is a JavaScript function that takes a class and prints its inheritance hierarchy:

function printClassTree(cls, level = 0) {
const name = cls.name || 'Object';
console.log(' '.repeat(2 * level) + name);
if (name !== 'Object') printClassTree(cls.__proto__, level + 1);
}

Here is a Python function to do the same:

def print_class_tree(cls, level = 0):
print(' ' * 2 * level + cls.__name__)
for base in cls.__bases__:
print_class_tree(base, level + 1)

Built-in Functions

JavaScript provides a small number (9) of built-in functions. Python provides many more (68). The tables below summarize these.

Often one of the languages does not have an equivalent function to the other, so the closest alternative is shown instead.

Descriptions below that begin with "determines if" mean that a Boolean value is returned.

Python built-in functionDescriptionClosest JavaScript equivalent
abs(x)returns absolute valueMath.abs(x)
all(iterable)determines if all elements are True
in a Boolean context
arr.every(predicate)
any(iterable)determines if any element is True
in a Boolean context
arr.some(predicate)
ascii(obj)like repr, but escapes non-ASCII charactersnot supported
bin(x)converts integer to binary stringnot supported
bool(x)converts value to BooleanBoolean(x)
breakpoint()breaks execution and
drops into debugger
debugger
bytearray(source)returns a new array of bytesuse ArrayBuffer with typed array classes
bytes(source)returns a bytes objectuse ArrayBuffer with typed array classes
callable(x)determines if x is callable (a function)typeof x === 'function'
chr(code_point)returns string representation
of a Unicode code point
String.fromCodePoint(codePoint)
compile(source, filename, mode)compiles source into a code/AST object
which can be passed to exec or eval
not supported
complex(real, imag)creates a complex number
from real and imaginary parts
not supported
delattr(obj, name)deletes an attribute from an objectdelete obj[name]
dict([data])creates a dictionary{} or new Map()
dir([obj])returns a list of defined names
in current scope or an object
Object.keys(obj)
divmod(a, b)return tuple of quotient and remainder
of a divided by b
Math.floor(a / b) and a % b
enumerate(iterable)return list of tuples each containing
an index and value from an iterable
Object.entries(arr)
eval(code)evaluates a single code expressioneval(code)
exec(code)execute any number of lines of codeeval(code)
filter(predicate, iterable)returns iterator over values in iterable
where predicate function returns true
arr.filter(predicate)
float(x)returns floating point number
created from a number or string
parseFloat(x)
format(value, fmt)returns string created by formatting a value
using a format string
use template literals
frozenset(iterable)returns frozenset (immutable set) object
created from iterable
Object.freeze(obj)
geattr(obj, name [, default])returns attribute valueobj[name] || default
globals()returns dictionary containing the
current global symbol table
not supported
hasattr(obj, name)determines if object has a given attributename in obj
hash(obj)returns hash value of objectnot supported
help([topic])invoke the built-in Python help system,
typically in the REPL
not supported
hex(n)converts integer to hexn.toString(16)
id(obj)returns identity of an objectnot supported
input([prompt])read from stdout with optional promptuse the Node readline module
question method
int(x)returns an integer created from
a number or string
parseInt(x[, radix])
isinstance(obj, ClassName)determines if an object is
an instance of a given class
obj instanceof ClassName
issubclass(ClassA, ClassB)determines if ClassB is
a subclass of ClassA
ClassB.prototype instanceof ClassA
iter(collection)returns an iterator over the elements
of a collection (see next)
arr[Symbol.iterator]()
len(obj)returns number of items in a collection
or characters in a string
obj.length
list(iterable)constructs a list from an iterableArray.from(arrayLike)
locals():returns dictionary containing the
current local symbol table
not supported
map(fn, iterable)returns iterator over values returned by
calling function on each iterable element
arr.map(fn)
max(v1, v2, ...) or
max(iterable)
returns largest value of arguments
or in an iterable
Math.max(v1, v2, ...) or
Math.max(...arr)
memoryview(obj)returns a memoryview for an object
that support the buffer protocol
not supported
min(v1, v2, ...) or
min(iterable)
returns largest value of arguments
or in an iterable
Math.min(v1, v2, ...) or
Math.min(...arr)
next(iterator)get next item from an iteratoriterator.next()
object()create an empty, featureless object;
can't add properties; Why is this useful?
{} is similar, but CAN add properties
oct(n)converts integer to octaln.toString(8)
open(file, mode, ...)opens a file for
reading, writing, or appending
see the Node fs module
ord(s)returns the Unicode code point
for a Unicode character
s.charCodeAt([index])
base ** exp or pow(base, exp)return base raised to exp powerbase ** exp or Math.pow(base, exp)
print(v1, v2, ...)print space-separated expression valuesconsole.log(v1, v2, ...)
property(getFn, setFn, delFn, doc)returns a property attribute that encapsulates
get, set and delete functions
not supported
range(stop) or
range(start, stop[, step])
returns a range object
which is an immutable sequence
not supported
repr(obj)returns a string representation
of an object for developers
obj.toString()
reversed(seq)returns an iterator for iterating
over a sequence in reverse order
not supported
round(n[, digits])
returns float or int
returns a number rounded to
some number of decimal points
n.toFixed(digits)
returns string
set([iterable])creates a set objectnew Set()
setattr(obj, name, value)sets an attribute of an objectobj[name] = value
slice(stop) or
slice(start, stop[, step])
returns a slice object that
describes a set of indexes;
used to retrieve data at those indexes
not supported
sorted(iterable[, key])returns a sorted version
of an iterable as a list
arr.sort([compareFn])
sorts in place
str(obj)returns a human-readable string
representation of an object
obj.toString()
sum(iterable)returns the sum of
numbers in an iterable
arr.reduce((acc, n) => acc + n)
super()returns a proxy object for
calling superclass methods
super keyword
tuple([iterable])creates a tuple, optionally
populated from an iterable
not supported
type() returns class objectreturns the type of a valuetypeof v returns string
v.constructor is constructor function
vars(obj)returns a dict view of
the attributes in an object
not supported
zip(iterables)returns an iterator that aggregates
elements from multiple iterables
not built-in;
can use Lodash zip function

JavaScript built-in functionDescriptionClosest Python equivalent
decodeURI(s)decodes a URL (opposite of encodeURI)urllib.unquote(s)
decodeURIComponent(s)decodes a component of a URI
(opposite of encodeURIComponent)
urllib.unquote(s)
encodeURI(s)encodes a URI, replacing certain characters
(not /, #, ?, =, and others)
urllib.quote(s, safe='chars1')
encodeURIComponent(s)encodes a component of a URI,
replacing certain characters
urllib.quote(s, safe='chars2')
eval(code)execute any number of lines of codeexec(code)
isFinite(x)determines if x is a finite numbermath.isfinite(x)
isNaN(x)determines of x in the "not a number" valuemath.isnan(x)
parseFloat(x)returns floating point number
created from a number or string
float(x)
parseInt(x[, radix])returns an integer created from
a number or string
int(x)

The JavaScript parseFloat and parseInt functions can process strings that contain additional characters after those in the number. For example, parseFloat('3.14pi') returns the number 3.14. The Python float and int functions do not support this.

Boolean operations

OperationJavaScriptPython
andb1 && b2b1 and b2
orb1 || b2b1 or b2
not!bnot b
bitwise andb1 & b2same
bitwise orb1 | b2same
bitwise not~bsame
bitwise xorb1 ^ b2same

Numeric operations

OperationJavaScriptPython
basic+, -, *, /same
exponentiation**same
increment++v (pre) or v++ (post)v += 1
decrement--v (pre) or v-- (post)v -= 1
mod (remainder)%same
convert to stringn.toString()str(n)
convert from string to integerNumber(s) or parseInt(s)int(s)
convert from string to floatNumber(s) or parseFloat(s)float(s)
convert to string with fixed decimals (ex. 2)n.toFixed(2)'{:.2f}'.format(n)
convert to hexn.toString(16)hex(n)
convert from hexparseInt(hexString, 16)int(hexString, 16)
constantssee Math and Number global objectssee math module
functionssee Math and Number global objectssee math module

Math operations

Lesser used constants and functions are omitted from the table below.

To use the Python functions, import math.

OperationJavaScriptPython
absolute valueMath.abs(x)math.fabs(x)
arc cosineMath.acos(x)math.acos(x)
arc sineMath.asin(x)math.asin(x)
arc tangentMath.atan(x)math.atan(x)
ceilingMath.ceil(x)math.ceil(x)
closenot built-inmath.isclose(x, y, rel_tol=rt, abs_tol=at)
combinations of k items from nnot built-in; see belowmath.comb(n, k)
convert degrees to radiansdegrees * (Math.PI / 180)math.degrees(radians)
convert radians to degreesradians * (180 / Math.PI)math.radians(degrees)
cosineMath.cos(x)math.cos(x)
cube rootMath.cbrt(x)x ** (1. / 3)
e constantMath.Emath.e
e to powerMath.exp(x)math.exp(x)
factorialnot built-in; see belowmath.factorial(n)
floorMath.floor(x)math.floor(x)
greatest common denominatornot built-inmath.gcd(n1, n2, ...)
hypotenuseMath.hypot(x, y, ...)math.hypot(x, y)
least common multiplenot built-inmath.lcm(n1, n2, ...)
log base 10Math.log10(x)math.log10(x)
logarithm to any basenot built-in; see belowmath.log(x, y)
maximumMath.max(n1, n2, ...)max(n1, n2, ...)
mean (average)not built-in; see belowstatistics.mean(seq)
mediannot built-in; see belowstatistics.median(seq)
maximumMath.max(n1, n2, ...)max(n1, n2, ...)
modenot built-in; see belowstatistics.mode(seq)
natural log (base e)Math.log(x)math.log(x)
not a numberNumber.isNaN(x)math.isnan(x)
not a number constantNumber.NaNmath.nan
permutations of k items from nnot built-in; see belowmath.perm(n, k)
pi constantMath.PImath.pi
power (x to y)Math.pow(x, y)math.pow(x)
productuse Array reduce; see belowmath.prod(iterable)
random [0, 1)Math.random()random.random()
random integer [a, b]not built-in; see belowrandom.randint(a, b)
roundMath.round(x)round(x, decimal_places=0)
sign (-1, 0, or 1)Math.sign(x)0 if x == 0 else math.copysign(1, x)
sineMath.sin(x)math.sin(x)
square rootMath.sqrt(x)math.sqrt(x)
square root of 1/2Math.SQRT1_2math.sqrt(0.5)
square root of 2Math.SQRT2math.sqrt(2)
sumuse Array reduce; see belowmath.fsum(iterable)
tangentMath.tan(x)math.tan(x)
truncateMath.trunc(x)math.trunc(x)

JavaScript can use the following functions to compute some of the values marked as "not built-in" in the table above:

function combinations(n, k) {
// n take k
return factorial(n) / (factorial(k) * factorial(n - k));
}

function factorial(n) {
if (n < 0) return undefined;
let f = 1;
while (n > 1) {
f *= n--;
}
return f;
}

// Compute the logarithm of x using a given base.
const logBase = (x, base) => Math.log(x) / Math.log(base);

const mean = nums => sum(nums) / nums.length;

function median(nums) {
nums.sort(); // may not want to sort in place
const len = nums.length;
const index = Math.floor(len / 2);
return len % 2 === 1 ? nums[index] : (nums[index - 1] + nums[index]) / 2;
}

function mode(nums) {
let result = undefined;
let resultCount = 0;
const counts = nums.reduce((acc, n) => {
if (acc[n] === undefined) {
acc[n] = 1;
} else {
acc[n]++;
}
if (acc[n] > resultCount) {
result = n;
resultCount = acc[n];
}
return acc;
}, {});
return result;
}

function permutations(n, k) {
// n take k
return factorial(n) / factorial(n - k);
}

const product = nums => (nums.length ? nums.reduce((acc, n) => acc * n, 1) : 0);

// Generate a random integer in the range [a, b].
const randint = (a, b) => a + Math.floor(Math.random() * (b - a + 1));

const sum = nums => (nums.length ? nums.reduce((acc, n) => acc + n) : 0);

The Python random module also provides:

String operations

OperationJavaScriptPython
literal single line'text' or "text"same
literal multi-line`text`"""text""" or '''text'''
lengths.lengthlen(s)
concatenates1 + n1s1 + str(n1) or
s1 str(n1) with only a space between them
lowercases.toLowerCase()s.lower()
uppercases.toUpperCase()s.upper()
substrings1.substring(start, end?)s[start:end] or s[start:] or s[:end]
slicelike substring, but supports negative indexessame as above
splits.split(delimiter) returns arrays.split(delimiter) returns list
starts withs.startsWith(sub) returns Booleans.startswith(sub) returns Boolean
ends withs.endsWith(sub) returns Booleans.endswith(sub) returns Boolean
containss.includes(sub) returns Booleansub in s returns Boolean
index ofs.indexOf(sub) returns numbers.index(sub, start?, end?) returns int
last index ofs.lastIndexOf(sub) returns numbers.rindex(sub, start?, end?) returns int
compares1.localeCompare(s2) returns -1, 0, or 1import locale
locale.strcoll(s1, s2)
returns negative, zero, or positive
remove prefixnot supporteds.removeprefix(p)
remove suffixnot supporteds.removesuffix(p)
replace firsts.replace(oldSub, newSub)s.replace(old, new, 1)
replace alls.replaceAll(oldSub, newSub)s.replace(old, new)
trim starts.trimStart()s.lstrip()
trim ends.trimEnd()s.rstrip()
trim both endss.trim()s.strip()
repeat n timess.repeat(n)s * n or n * s

Sequences

JavaScript stores sequences of values in arrays. Python primarily uses the four sequence types list, tuple, range, and set for this purpose.

Python lists are mutable and are typically homogeneous (elements have the same type). Python tuples are immutable and are typically heterogeneous (elements can have different types). Python ranges are immutable sequences of numbers and are often used in for loops. Python sets are mutable sequences that do not allow duplicate values and are typically homogeneous.

To create a JavaScript array:

const myArray = [element1, element2, ...];

To create a Python list:

myList = [element1, element2, ...]

To create a Python tuple:

# Parentheses around a tuple are optional.
myTuple = (element1, element2, ...)

To create a Python range:

myRange = range(end) # 0 to end-1
myRange = range(start, end, step?) # start to end-1 where step defaults to 1

To create a Python set:

mySet = {element1, element2, ...}

All of these types can be nested within each other. For example, the elements of a list can be tuples and the elements of a tuple can be ranges. An exception is that the elements of a range can only be integers.

A named tuple gives a name to a tuple type and supports accessing elements in instances by name and index. For example:

from collections import namedtuple
# Internally, this generate a class named Dog.
Dog = namedtuple('Dog', 'name breed')
dog = Dog('Comet', 'Whippet')
print(dog.name) # Comet
print(dog[0]) # Comet
print(dog.breed) # Whippet
print(dog[1]) # Whippet
print(len(dog)) # 2
OperationJavaScriptPython
is array/sequenceArray.isArray(expr)hasattr(type(expr), '__iter__')
isinstance(expr, list)
isinstance(expr, tuple)
isinstance(expr, range)
isinstance(expr, set)
add to endarr.push(v1, v2, ...);seq.append(v) to add one and
seq.extend(iterable) to add more than one
remove from endconst value = arr.pop();value = seq.pop()
add to startarr.unshift(value);seq.insert(0, value)
remove from startconst value = arr.shift();del seq[0]
insertarr.splice(index, delCount, v1, v2, ...)seq.insert(index, value)
remove item at indexarr.splice(index, 1)del seq[index] - only for lists
remove items at index rangearr.splice(start, count)del seq[start:start+count] - only for lists
remove valuearr.splice(arr.findIndex(value), 1)seq.remove(value) - error if not found
remove allarr = [];seq.clear()
changearr.splice(start, delCount, v1, v2, ...);combine del and insert above
lengtharr.lengthlen(seq)
lookupconst value = arr[index];value = seq[index]
subsetarr.slice(start, end)
can omit end and start and
can use negative indexes to count from end
seq[start:end]
can omit start and/or end and
can use negative indexes to count from end
concatenateconst newArr = arr1.concat(arr2, arr3, ...);newSeq = seq1 + seq2 + seq3
copy (shallow)[...arr] or arr.slice()list.copy() - only for lists
findarr.find(predicate);next(filter(predicate, seq)) - see note below this table
find indexarr.findIndex(predicate);index = seq.index(value, start?, end?) - see note below this table
iterate overfor (const value of arr) or
arr.forEach((value, index) => { ... });
for item in seq: or
for index, item in enumerate(seq):
iterate over in reverseiterate over arr.reverse()for item in reversed(seq):
iterate over in sorted ordercreate a sorted copy and iterate over itfor item in sorted(seq):
includes (Boolean)arr.includes(value)value in seq
not includes (Boolean)!arr.includes(value)value not in seq
index ofarr.indexOf(value[, fromIndex])seq.index(value[, start[, end]])
last index ofarr.lastIndexOf(value[, fromIndex])not built-in; have to reverse list
count occurrencesarr.reduce((acc, v) => v === value ? acc + 1 : acc, 0)seq.count(value)
joinarr.join(delimiter) returns stringdelimiter.join(seq)
mapconst newArr = arr.map(value => newValue);iterator = map(function, seq)
filterconst newArr = arr.filter(predicate);iterator = filter(predicate, seq)
reduceconst value = arr.reduce((acc, value) => { ... });from functools import reduce
value = reduce(lambda acc, item: ..., seq, initial)
some/any (Boolean)arr.some(predicate) - short circuitsany(map(predicate, seq)) - no short circuit
every/all (Boolean)arr.every(predicate) - short circuitsall(map(predicate, seq)) - no short circuit
sortarr.sort(comparator);
comparator is a function that compares two elements
list.sort(key=k, reverse?)
k is an attribute name or a function that takes
an element and returns a value to sort on
reversearr.reverse()list.reverse() - only for lists
destructure/unpackconst [v1, v2, v3] = arr;
# of variables on left can differ from # of array elements
v1, v2, v3 = seq
# of variables on left must match # of sequence elements
which limits usefulness

Python doesn't have a simple, built-in way to find the first item in a list that matches some criteria. This naive approach is probably the most efficient.

def index(predicate, seq):
for index in range(0, len(seq)):
if predicate(seq[index]):
return index
return None

The Python filter and map functions are lazy which means they are not executed until their results are needed. To get values from them, repeatedly pass the result to next or pass the result to a function like list or set to get all the values. For example:

numbers = [1, 2, 3]

iter = map(lambda n: n * 2, numbers) # multiplies each by 2
print(next(iter)) # 2
print(next(iter)) # 4

print(list(map(lambda n: n * 2, numbers))) # [2, 4, 6]

The string join method takes an iterable over strings. To join non-string values, use map and the str function to convert values to strings. For example:

'-'.join(map(str, numbers)) # '1-2-3'

JavaScript can implement lazy functions using generator functions (see the "List comprehension" section), but no built-in generator functions are provided.

Sorting

Suppose we have a sequence of object that represent people and we wish to sort the sequence on their last name following by their first name.

Here is how this can be done in JavaScript:

const people = [
{firstName: 'Tami', lastName: 'Volkmann'},
{firstName: 'Mark', lastName: 'Volkmann'},
{firstName: 'Brendan', lastName: 'Eich'},
{firstName: 'Guido', lastName: 'van Rossum'}
];
people.sort((p1, p2) => {
const compare = p1.lastName.localeCompare(p2.lastName);
return compare ? compare : p1.firstName.localeCompare(p2.firstName);
});
console.log(people);

Here is how this can be done in Python:

from operator import itemgetter

people = [
{'firstName': 'Tami', 'lastName': 'Volkmann'},
{'firstName': 'Mark', 'lastName': 'Volkmann'},
{'firstName': 'Brendan', 'lastName': 'Eich'},
{'firstName': 'Guido', 'lastName': 'van Rossum'}
]

# This sort is case-sensitive.
#people.sort(key=itemgetter('lastName', 'firstName'))
# This sort is case-insensitive.
getter = itemgetter('lastName', 'firstName')
person_key = lambda p: tuple(map(str.casefold, getter(p)))
people.sort(key=person_key)
print(people)

List comprehensions

Python supports list comprehensions that create a list, but JavaScript does not. Here are some examples.

squares = [n**2 for n in range(5)] # [0, 1, 4, 9, 16]

multiplesOf3 = [n for n in range(10) if n % 3 == 0] # [0, 3, 6, 9]

JavaScript generator functions can be used to do the same thing, but some utility generator functions must be written.

function* range(n) {
for (i = 0; i < n; i++) yield i;
}

function* map(fn, iter) {
for (const element of iter) yield fn(element);
}

const squares = map(n => n ** 2, range(5)); // [0, 1, 4, 9, 16 ]

function* filter(predicate, obj) {
for (const element of obj) {
if (predicate(element)) yield element;
}
}

const multiplesOf3 = filter(n => n % 3 === 0, range(10)); // [ 0, 3, 6, 9 ]

Python also supports generator functions and the yield keyword. The JavaScript example above could be implemented as follows in Python:

def map(fn, iter):
for element in iter:
yield fn(element)

squares = map(lambda n: n**2, range(5)) # [ 0, 1, 4, 9, 16 ]

def filter(predicate, seq):
for element in seq:
if predicate(element):
yield element

multiplesOf3 = filter(lambda n: n % 3 == 0, range(10)) # [ 0, 3, 6, 9 ]

Sets

Sets are unordered collections with no duplicate values.

OperationJavaScriptPython
is setexpr instanceof Setisinstance(expr, set)
createconst s = new Set(); - cannot specify elementss = {elements} or s = set(elements)
adds.add(value)same
removes.delete(value);s.remove(value)
remove alls.clear()same
lengths.sizelen(s)
includess.has(value)value in s
iterate overs.forEach(value => { ... });for value in set: ...
convert to array/lista = s.values();l = list(s)

Set comprehensions

Python supports set comprehensions that create a set, but JavaScript does not. Here is an example.

from random import randint

# Pick 10 random integers from 1 to 10
# and keep only the unique values.
# Placing the values in a set enforces unique values.
numbers = {randint(1, 11) for n in range(10)}

Key/value collections

JavaScript uses plain objects or instances of the Map class to store associations between keys and values. Keys in JavaScript objects must be must be strings, integers, or symbols, but keys in Map instances can be any type.

OperationJavaScript ObjectJavaScript Map
is object/dicttypeof expr === 'object'expr instanceof Map
createconst obj = {};
can include initial key/value pairs
const map = new Map();
cannot specify initial key/value pairs
lengthObject.keys(obj).lengthmap.size
set value of keyobj.key = value or obj[key] = valuemap.set(key, value)
get value of keyobj.key or obj[key]
use 2nd form if key contains special characters
map.get(key)
get all keysObject.keys(obj)map.keys()
get all valuesObject.values(obj)map.values()
get all pairsObject.entries(obj)
returns array of arrays containing a key and value
map.entries()
returns the same
test if key presentkey in obj or obj.hasOwnProperty(key)map.has(key)
delete pairdelete obj.key or delete obj[key]map.delete(key)
delete all pairsobj = {}map.clear()
iterate over keysfor (const key in obj) or
for (const key of Object.keys(obj))
map.forEach((value, key) => { ... });

Python uses dictionaries to store associations between keys and values. The keys must be immutable types like strings, numbers, and tuples containing these.

OperationPython
is dictisinstance(expr, dict)
createdict = {}
dict = {k1: v1, k2: v2, ...}
dict([(k1, v1), (k2, v2), ...])
lengthlen(dict)
set value of keydict[key] = value
get value of keydict[key] or dict.get(key)
error if key doesn't exist
get all keysdict.keys() or list(dict) or
sorted(dict) to get keys in sorted order
get all valuesdict.values()
get all pairsdict.items()
returns a live view that provides a
sequence of tuples containing a key and value
test if key presentkey in dict
test if key not presentkey not in dict
delete pairdel dict[key]
delete all pairsdict.clear()
iterate overfor item in dict.items(): ...

Python 3.9 added the | and |= operators for merging dict objects.

Creating a dictionary object

There are four ways to create a Python dictionary:

# 1) Use the literal syntax.
person = {'name': 'Mark', 'hungry': True}
# person = {'name': 'Mark', 'hungry': True}

# 2) Pass keyword arguments to the `dict` function.
# This has the advantage that single word keys
# do not need to be enclosed in quotes.
person = dict(name='Mark', hungry=True)
# person = {'name': 'Mark', 'hungry': True}

# 3) Pass a list of key/value tuples to the `dict` function.
kv_tuples = [('name', 'Mark'), ('hungry', True)]
person = dict(kv_tuples)
# person = {'name': 'Mark', 'hungry': True}

# 4) Use a dictionary comprehension.
def get_initials(name):
return ''.join(map(lambda s: s[0], name.split(' ')))

names = ['Mark Volkmann', 'Dorian Yeager']
my_dict = {name: get_initials(name) for name in names}
# {'Mark Volkmann': 'MV', 'Dorian Yeager': 'DY'}

Regular expressions

In JavaScript, regular expressions are a built-in type. An instance can be created in two ways:

// This pattern matches Canadian postal codes.
const re = /^[A-Z]\d[A-Z] \d[A-Z]\d$/;
// Alternative
//const re = new RegExp('^[A-Z]\\d[A-Z] \\d[A-Z]\\d$');

const pc = 'A1B 2C3';
if (!re.test(pc)) console.log('not a Canadian postal code');

In Python, import the re module to use regular expressions. Those that will be used multiple times should be compiled. Otherwise they can be used inline. The following example demonstrate the two ways in which every regular expression method can be used, calling it on the re module or on a compiled regular expression.

import re

# This pattern matches Canadian postal codes.
# Using the string literal prefix "r" prevents the "\" character
# from being treated as an escape character inside a regular expression.
pattern = r'^[A-Z]\d[A-Z] \d[A-Z]\d$'

pc = 'A1B 2C3'

# For one-time use ...
if (not re.search(pattern, pc)):
print('not a Canadian postal code')

# For repeated usage ...
canadianPostalCode = re.compile(pattern)
if (not canadianPostalCode.search(pc)):
print('not a Canadian postal code')
OperationJavaScriptPython
createconst re = /pattern/flags or
const re = new RegExp(pattern, flags)
import re
regex = re.compile(pattern)
test if a string matchesif (re.test(str))regex.search(str)
returns a match object or None if not matched
get first matchstr.match(re)same as above
get all matchesstr.matchAll(re) or re.exec(str)regex.finditer(str)
returns an iterable over match objects
split string on restr.split(re)
returns an array of strings
regex.split(str)
returns a list of strings

Python match objects support the following methods:

For more information on regular expression support in Python, see the Python Standard Library Documentation.

Error handling

Python refers to errors as exceptions.

OperationJavaScriptPython
throwthrow new Error(message);raise ExClass(args)
catchtry { ... } catch (e) { ... } finally { ... }try: ... except ExClass as e: ... else: ... finally: ...
rethrowthrow e;raise e

In JavaScript:

try {
// code to try executing
} catch (e) {
// code to handle all exceptions
} finally {
// optional
// code to run at end regardless of whether an exception was thrown
}

In Python:

try:
# code to try executing
except ExClass1 as e:
# code to handle a specific exception class
except (ExClass2, ExClass3):
# code to handle other exception classes listed in a tuple
else: # optional
# code to run if no exception was thrown
# Placing code here means that exceptions it throws
# will not be handled by the "except" blocks above.
finally: # optional
# code to run at end regardless of whether an exception was thrown

To ignore an exception in Python, include a pass statement in an except block.

There are many built-in Python exception classes. The base class of all of them is Exception. Names of built-in exception classes end in "Error". For a list of them, see Built-in Exceptions.

Names of custom exception classes should also end in "Error". Here is an example of defining one:

class MyCustomError(Exception):
pass

Exit with status

Both JavaScript programs running in Node.js and Python programs can explicitly exit and set a status code.

In Node.js, the exit method of the process global object is used.

process.exit(statusCode);

In Python, the exit method of the sys module is used.

import sys

sys.exit(status_code)

In both cases if no status code is supplied, it defaults to zero.

JSON

In Python, in order to use JSON methods include import json.

OperationJavaScriptPython
createconst jsonString = JSON.stringify(expr);jsonString = json.dumps(expr)
parseconst value = JSON.parse(jsonString);value = json.loads(jsonString)

Writing and reading Files

Node.js and Python can both read and write files containing text or binary data. For details on how this works in Node.js, see the Node.js File system docs. For details on how this works in Python, see Reading and Writing Files in Python.

One case to consider is when the file can easily fit in memory. We will see an example using JSON that demonstrates this. Another case is when it cannot and therefore must be processed using streams, perhaps one line at a time. We will see an example using CSV that demonstrates this.

Writing and reading small files

Let's write a JSON file and then read it back in to verify that it worked.

Here is a JavaScript version: Note that it uses top-level awaits which requires the code to be in an ES module. One way to satisfy this is to give the file a .mjs file extension.

import fs from 'fs/promises';

const dog = {
breed: 'Whippet',
name: 'Comet'
};
const filePath = 'dog.json';

await fs.writeFile(filePath, JSON.stringify(dog));

const buffer = await fs.readFile(filePath);
const newDog = JSON.parse(buffer.toString());
console.log(newDog);

And here is a Python version:

import json

dog = {
"breed": 'Whippet',
"name": 'Comet'
}
file_path = 'dog.json'

with open(file_path, 'w') as writer:
writer.write(json.dumps(dog))

with open('x' + file_path, 'r') as reader:
new_dog = json.loads(reader.read())
print(new_dog)

Writing and reading large files

Let's write a CSV file and then read it back in to verify that it worked. Rather than write the entire file at once, we will write one line at a time. Likewise we will read the file one line at a time.

Here is a JavaScript version:

import fs from 'fs';
import readline from 'readline';

const filePath = 'dogs.csv';

const ws = fs.createWriteStream(filePath);
ws.write('Maisey,Treeing Walker Coonhound\n');
ws.write('Ramsay,Native American Indian Dog\n');
ws.write('Oscar Wilde,German Shorthaired Pointer\n');
ws.write('Comet,Whippet\n');
ws.close();

const rl = readline.createInterface({
input: fs.createReadStream('dogs.csv')
});

for await (const line of rl) {
console.log(line);
}

rl.close();

And here is a Python version:

file_path = 'dog.csv'

with open(file_path, 'w') as writer:
writer.write('Maisey,Treeing Walker Coonhound\n');
writer.write('Ramsay,Native American Indian Dog\n');
writer.write('Oscar Wilde,German Shorthaired Pointer\n');
writer.write('Comet,Whippet\n');

with open(file_path, 'r') as reader:
while True:
line = reader.readline()
if not line:
break
print(line, end='')

Shell commands

JavaScript code running in Node.js can execute shell commands, provide input to them, and capture output written to stdout and stderr.

In the example code below we execute the ps command to get the status of all currently running processes and then output the process id (pid) and running time of all "node" processes.

import {exec} from 'child_process';
import {promisify} from 'util';
const pexec = promisify(exec);

function node_report(lines) {
for (const line of lines) {
const tokens = line.trimStart().split(/ +/);
if (tokens.length >= 9) {
const command = tokens[7];
if (command == 'node') {
const pid = tokens[1];
const time = tokens[6];
console.log('process id', pid, 'has run for', time);
}
}
}
}

// Approach #1 - using a callback function
exec('ps -ef', (error, stdout, stderr) => {
if (error || stderr) {
console.error(error || stderr);
} else {
node_report(stdout.split('\n'));
}
});

// Approach #2 - awaiting a Promise
const {stdout, stderr} = await pexec('ps -ef');
if (stderr) {
console.error(stderr);
} else {
node_report(stdout.split('\n'));
}

Here is a Python version that does the same:

import os, re, subprocess

# Create a regular expression that matches two or more spaces.
spaces_re = re.compile(r' {2,}')

# Print the process id and running time of all "node" processes.
def node_report(lines):
for line in lines:
# Replaces all occurrences of multiple spaces with one.
line = spaces_re.sub(' ', line.lstrip())
tokens = line.split(' ')
if len(tokens) >= 9:
command = tokens[7]
if command == 'node':
pid = tokens[1]
time = tokens[6]
print('process id', pid, 'has run for', time)

# Approach #1 - reading output into a single string
stream = os.popen('ps -ef')
output = stream.read() # reads all lines into a single string
node_report(output.split('\n'))

# Approach #2 - reading output into an array of strings, one per line
stream = os.popen('ps -ef')
node_report(stream.readlines())

# Approach #3 - using a CompletedProcess instance
process = subprocess.run(['ps', '-ef'], capture_output=True, text=True)
if process.stderr:
print('error:', process.stderr, file=sys.stderr)
else:
node_report(process.stdout.split('\n'))

Decorators

Python supports decorators which are annotations placed before functions and classes to alter their behavior. The TC39 committee that controls the ECMAScript standard for JavaScript has been discussing adding decorators for many years, but they have not yet been added.

Here is a simple example of a decorator that logs the arguments and return value of every invocation value of functions to which it is applied:

import logging
logging.basicConfig(level=logging.DEBUG)

def log(fn):
def wrapper(*args):
result = fn(*args)
logging.debug(
f'{fn.__name__} was passed {str(args)} and returned {result}')
return result

return wrapper

@log
def add(n1, n2):
return n1 + n2

add(1, 2) # DEBUG:root:add was passed (1, 2) and returned 3
add(2, 3) # DEBUG:root:add was passed (2, 3) and returned 5

The built-in Python decorators include:

For more information, see Real Python Primer on Python Decorators.

Check for running as main

Some source files can be used as both the starting point of a script and a module imported by others. To include code that is only run when the file is executed as a script, wrap it in one of the following if statements.

In Node.js, use if (require.main === module) { ... }

In Python, use if __name__ == '__main__': ...

HTTP servers

HTTP servers can be implemented in both Node.js and Python. In Node.js, a popular option is to use the Express package. In Python, popular options include Flask and FastAPI.

To demonstrate these options, we will implement HTTP servers that:

The collection of dogs could be persisted to a database, but we will just hold them in memory in a key/value collection where the keys are dog ids and the values are dog objects that have id, breed, and name properties.

We want the servers to:

JavaScript Express REST server

  1. Create a directory for the project and cd to it.

  2. Create a package.json file for the project by entering npm init and answering the questions it asks.

  3. Install the required dependencies by entering npm install cors express pino-http and npm install -D nodemon.

  4. Replace the "test" script in package.json with "start": "nodemon server.js". The nodemon command provides automatic file watch and server restart.

  5. Create the file server.js containing the following:

    const express = require('express');
    const cors = require('cors');
    const path = require('path');
    const pino = require('pino-http')();

    const dogs = {
    1: {id: 1, breed: 'Whippet', name: 'Comet'}
    };

    const app = express();
    app.use(pino); // for logging
    app.use(cors()); // for cross-origin resource sharing
    app.use(express.json()); // to parse JSON bodies

    // Serve static files found in the public directory.
    app.use(express.static(path.resolve(__dirname, 'public')));

    app.get('/dog', (req, res) => {
    res.end(JSON.stringify(dogs));
    });

    app.get('/dog/:id', (req, res) => {
    const {id} = req.params;
    const dog = dogs[id];
    if (dog) {
    res.end(JSON.stringify(dog));
    } else {
    res.status(404).end('dog not found');
    }
    });

    app.post('/dog', (req, res) => {
    const dog = req.body;
    dog.id = Date.now();
    dogs[dog.id] = dog;
    res.end(String(dog.id));
    });

    app.put('/dog/:id', (req, res) => {
    const {id} = req.params;
    if (dogs[id]) {
    const dog = req.body;
    dog.id = id;
    dogs[id] = dog;
    res.end();
    } else {
    res.status(404).end('dog not found');
    }
    });

    app.delete('/dog/:id', (req, res) => {
    const {id} = req.params;
    if (dogs[id]) {
    delete dogs[id];
    res.end();
    } else {
    res.status(404).end('dog not found');
    }
    });

    const PORT = 1919;
    app.listen(PORT, () => console.log('ready'));
  6. Run the server by entering npm start.

Python Flask REST server

Key benefits of Flask are:

  1. Install the required dependencies by entering pip install flask flask-cors. Flask-CORS supports enabling CORS in Flask servers.

  2. If running in a UNIX environment, create the script file start shown below and make it executable by entering chmod a+x start:

    #!/usr/local/bin/bash
    export FLASK_APP=server.py
    export FLASK_ENV=development
    flask run --port=1919

    Setting FLASK_ENV to development provides automatic file watch and server restart.

    If running in Windows, create a similar start.bat file.

  3. Create the file server.py containing the following:

    from flask import Flask, abort, jsonify, make_response, request
    from flask_cors import CORS

    import time
    import uuid

    # Disable request logging.
    import logging
    log = logging.getLogger('werkzeug')
    log.setLevel(logging.ERROR)

    # Serve static files found in the public directory.
    app = Flask(__name__, static_folder='public', static_url_path='')
    CORS(app) # for cross-origin resource sharing

    id = str(uuid.uuid4())
    dogs = {}
    dogs[id] = {'id': id, 'breed': 'Whippet', 'name': 'Comet'}

    @app.route('/dog')
    def get_dogs():
    return jsonify(list(dogs.values()))

    @app.route('/dog/<id>')
    def get_dog(id):
    if id in dogs:
    return jsonify(dogs[id])
    else:
    abort(404)

    @app.route('/dog', methods=['POST'])
    def create_dog():
    dog = request.get_json() # from body
    id = str(uuid.uuid4())
    dog['id'] = id
    dogs[id] = dog
    return make_response(jsonify(dog), 201)

    @app.route('/dog/<id>', methods=['PUT'])
    def update_dog(id):
    if id in dogs:
    dog = request.get_json() # from body
    dog['id'] = id
    dogs[id] = dog
    return jsonify(dog)
    else:
    abort(404)

    @app.route('/dog/<id>', methods=['DELETE'])
    def delete_dog(id):
    if id in dogs:
    del dogs[id]
    return ''
    else:
    abort(404)
  4. Run the server by entering ./start.

Python FastAPI REST server

Key benefits of FastAPI are:

  1. Install the required dependencies by entering pip install fastapi pydantic uvicorn.

  2. Create the file server.py containing the following:

    from fastapi import FastAPI, Response, status
    from fastapi.middleware.cors import CORSMiddleware
    from pydantic import BaseModel
    from typing import Optional
    import time
    import uuid

    # JSON in request bodies of POST and PUT requests
    # is validated against this type definition.
    # When validation fails, the response status
    # is set to 422 Unprocessable Entity.
    class Dog(BaseModel):
    id: Optional[str] = None
    breed: str
    name: str

    id = str(uuid.uuid4())
    dogs = {}
    dogs[id] = {'id': id, 'breed': 'Whippet', 'name': 'Comet'}

    app = FastAPI()
    app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*'])

    @app.get('/dog')
    def get_dogs():
    return list(dogs.values())

    @app.get('/dog/{id}')
    def get_dog(id: str):
    if id in dogs:
    return dogs[id]
    else:
    return Response(status_code=status.HTTP_404_NOT_FOUND)

    @app.post('/dog', status_code=201)
    def create_dog(dog: Dog):
    id = str(uuid.uuid4())
    # dog['id'] = id # Why can't the dog object be modified?
    dict = dog.dict()
    dict['id'] = id
    dogs[id] = dict
    return dict

    @app.put('/dog/{id}')
    def update_dog(dog: Dog, id: str):
    if id in dogs:
    # dog['id'] = id # Why can't the dog object be modified?
    dict = dog.dict()
    dict['id'] = id
    dogs[id] = dict
    return dict
    else:
    return Response(status_code=status.HTTP_404_NOT_FOUND)

    @app.delete('/dog/{id}')
    def delete_dog(id: str):
    if id in dogs:
    del dogs[id]
    return Response(status_code=status.HTTP_204_NO_CONTENT)
    else:
    return Response(status_code=status.HTTP_404_NOT_FOUND)
  3. Run the server by entering uvicorn server:app --log-level error --port 1919. Include the --reload option to provide automatic file watch and server restart.

  4. Check out the Open API docs that are provided for free! Browse localhost:1919/docs to see API documentation and try each API from the browser.

HTTP clients

JavaScript applications often use the Fetch API to send HTTP requests. This is built into modern web browsers and can be used in Node applications by installing the node-fetch package with npm install node-fetch.

Here is an example were we fetch an image of a given dog breed.

const fetch = require('node-fetch');

const breed = 'whippet';
const url = `https://dog.ceo/api/breed/${breed}/images/random/1`;

async function doIt() {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(await res.text());
const obj = await res.json();
const [imageUrl] = obj.message; // get first array element
console.log('image url =', imageUrl);
} catch (e) {
console.error(e);
}
}

doIt();

Python applications often use the requests package to send HTTP requests. It can be installed by entering pip install requests.

Here is the same example using Python.

import requests
from requests.exceptions import ConnectionError
import sys

breed = 'whippet'
url = f'https://dog.ceo/api/breed/{breed}/images/random/1'

try:
res = requests.get(url)
if res.status_code != 200:
raise Exception('bad status ' + str(res.status_code))

obj = res.json() # a dict
image_url = obj['message'][0] # get first array element
print('image url =', image_url)
except ConnectionError as e:
print('failed to connect to', url)
except Exception as e:
print(e)

Python magic methods

Python magic methods support many operations on classes and class instances. These include operator overloading. The following table provides a categorized, partial list of the magic methods that a Python class can implement.

MethodParametersPurpose
Object Lifecycle
__new__cls, ...creates a new object
__init__self, ...initializes a new object
__del__selfdestroys an object
__getattr__self, namecan be used to implement the "method missing" pattern
(see example below)
String Representation
__repr__selfreturns a string representations useful to developers
__str__selfreturns a string representation useful to users
Comparisons
__eq__self, otherdetermines if this object is equal to another
__ne__self, otherdetermines if this object is not equal to another
__lt__self, otherdetermines if this object is < another
__le__self, otherdetermines if this object is <= to another
__gt__self, otherdetermines if this object is > another
__ge__self, otherdetermines if this object is >= to another
also see functools.total_ordering()
List-like Operations
__getitem__self, keygets an item from a list by index
__setitem__self, key, valuesets an item in a list by index
__delitem__self, keydeletes an item from a list by index
__iter__selfreturns an iterator
__contains__self, itemdetermines if a given item is contained
Dict Operations
__missing__self, keyreturns value to use when key is not present
class must inherit from dict
Math Operations
__add__self, otheradds an object to another
__sub__self, othersubtracts an object from another
__mul__self, othermultiplies an object by another
__div__self, otherdivides an object by another
__mod__self, othermods an object by another
Pickling (serialization)
__getstate__selfpickles an object
__setstate__selfunpickles an object
Other
__call__self, ...treats an object as a function; can change state

The "method missing" pattern supports calling non-existent methods on an object and inferring meaning at runtime. This is frequently used in the "Ruby on Rails" framework in the implementation of "Active Record".

For example, suppose we want to implement a class whose objects support methods whose names begin with "add" and end with a number. These methods accept another number as an argument and return the sum of the numbers. This could be implemented as follows:

class MethodMissingDemo:

def __getattr__(self, method_name):
prefix = 'add'
if method_name.startswith(prefix):
n1 = int(method_name[len(prefix):])
return lambda n2: n1 + n2
else:
class_name = self.__class__.__name__
raise AttributeError(f"{class_name} object has no method '{method_name}'")

demo = MethodMissingDemo()
print(demo.add3(4)) # 7
print(demo.add19(1)) # 20
print(demo.subtract5(7)) # AttributeError: MethodMissingDemo object has no method 'subtract5'

In most cases, using normal methods and parameters instead of the __getattr__ method results in code that is easier to understand and maintain.

JavaScript can do something similar using "proxies".

const demo = new Proxy(
{},
{
get(object, methodName) {
const prefix = 'add';
if (methodName.startsWith(prefix)) {
n1 = Number(methodName.substring(prefix.length));
return n2 => n1 + n2;
} else {
throw new ReferenceError('object has no method ' + methodName);
}
}
}
);

console.log(demo.add3(4)); // 7
console.log(demo.add20(1)); // 20
console.log(demo.subtract5(7)); // ReferenceError: object has no method subtract5

Types

To gain type checking for JavaScript, use the TypeScript compiler. TypeScript is a superset of JavaScript that adds types.

Two popular tools that provide type checking on Python source files are mypy and Pyright.

The remainder of this section focuses on Python type checking.

Python type specifications are referred to as "type hints". The python interpreter ignores type hints, but they make startup time take slightly longer. They are useful as documentation even without using a type checker. IDEs can use them to flag type issues.

The primitive types supported are:

Type NameMeaning
boolBoolean
bytesimmutable sequence of integers from 0 to 255
complexcomplex number with float real and imaginary parts
floatdouble precision floating point number
intunlimited precision integer
strstring

The collection types supported are:

Type NameMeaning
Dict[KT, VT]dict with keys of type KT and values of type VT
List[T]list with elements of type T
Sequence[T]any kind of sequence whose elements are all of type T
Set[T]set with elements of type T
Tuple[T1, T2, ...]tuple whose elements have specified types

Other types supported are:

Type NameMeaning
Anyany value
any class nameinstance of the class or instance of a subclass
Callable[[P1, P2, ...], RT]function that takes parameters of types P1, P2, ... and returns type RT
Callable[..., RT]function that takes any parameters and returns type RT
Generator[YieldType, SendType, ReturnType]generator function;
SendType and ReturnType can be None
NamedType('Name', [('name1', T1), ('name2', T2)])named tuple where elements have types T1, T2, ...
Optional[T]matches None or the type T
same as Union[None, T]
Type[C]matches a class object for class C or a subclass
Union[T1, T2, ...]matches any of the specified types

All types above whose names begin with a capital letter must be imported from the "typing" module. For example, from typing import Any, List. Python 3.9 is supposed to make this unnecessary, but perhaps mypy does not yet support the new type syntax.

The Union type can be used in collection types to allow elements to have a set of types.

Aliases can be defined for long type descriptions. This is useful when the same type description is used in many places. For example, IntToStrMap = Dict[int, str].

To add a "type hint" to a variable or function parameter, follow its name with a colon, a space, and the type.

To add a return type hint to a function, follow the argument list right parenthesis with -> and the type.

For example, if IceCream is a class we have defined:

def order_ice_cream(flavor: str, scoops: int, add_sprinkles: bool) -> IceCream:

The typing module also defines a cast function. Here's an example of using it.

from typing import cast, Optional

Action = str # direction letter

direction_map = {
'D': 'down',
'L': 'left',
'R': 'right',
'U': 'up'
}
directions = cast(List[Action], direction_map.keys())

last_direction: Optional[Action] = None

def get_possible_actions() -> List[Action]:
return list(filter(lambda d: d != last_direction, directions))

mypy

mypy is a Python type checking tool that is implemented in Python. Development began in 2014.

To install mypy, enter pip install mypy. On a Mac, add the following directory to the PATH environment variable: /Library/Frameworks/Python.framework/Versions/3.8/bin.

To run mypy on a source file and all the files it imports, enter mypy {filename}.py.

mypy cannot perform type checking on function arguments that correspond to parameters with default values or parameters that collect variadic arguments in a tuple or dict.

Pyright

Pyright is a Python type checking tool that is implemented in TypeScript. Development began in 2019. It is used by the VS Code extension Pylance and can also be run from the command line.

To install Pyright, install Node.js and enter npm install -g pyright.

To run Pyright on a source file and all the files it imports, enter pyright {filename}.py. To run in watch mode, enter pyright -w. See this issue.

To configure options for Pyright, create a pyrightconfig.json file in the project root directory. For example, the following content configures strict type checking for all files in the current directory.

{
"strict": ["."]
}

In answer to the question "What is the long-term plan for Pyright?" the Pyright FAQ says:

"Pyright is a side project with no dedicated team. There is no guarantee of continued development on the project. If you find it useful, feel free to use it and contribute to the code base."

Stub files

Types can be specified in "stub files" with a .pyi extension instead of directly in .py files.

Stub files for popular Python libraries can be downloaded from typeshed. These are included as a submodule of mypy. See the typeshed link for instructions on installing them.

Note that the number of libraries represented here is currently small and it does not contain stub files for many popular libraries including mathplotlib, numpy, and pandas. Type stub files for matplotlib, numpy, and pandas can be found at data-science-types.

When creating your own stub files, create .pyi files with the same names as the .py files whose types they describe. Stub files can be placed in the same directory as the module definition or in a separate directory with a name like "stubs". If they are in a separate directory, define the MYPYPATH environment variable to point to the directory.

If a stub file for a module is present, its type definitions override any found in the corresponding .py file.

To define the type of a variable in a stub file, use the syntax name: type.

To define types for a function in a stub file, use the syntax def name(p1: type1, p2: type2, ...) -> return_type: .... Note that the ... is actual syntax.

A stub files can be automatically generated from .py files using the stubgen command that is installed with mypy. By default it places the generated stub files in a subdirectory named out, but this can be changes using the -o option. For example, stubgen -o . math.py generates math.pyi in the current directory. Many of the types will be Any, so manual editing of the generated files is desirable to make the types more strict.

Here is a example module in math.py that omits type hints:

PI = 3.1415928

def add(n1, n2):
return n1 + n2

Here is a stub file in math.pyi that provides type hints:

PI: float

def add(n1: float, n2: float) -> float: ...

Here is code that uses this module:

from math import PI, add

print(add('2', PI))

Running the mypy command reports ...

demo.py:3: error: Argument 1 to "add" has incompatible type "str"; expected "float"
Found 1 error in 1 file (checked 1 source file)

Testing

See Python testing.

TopicJavaScriptPython
command lineNode.js node commandpython command
utilitiesLodash, Ramdapydash
web serverExpressFlask, FastAPI
web frameworkReact, Svelte, VueFlask
dates and timesdate.fns, Moment.js, Temporaldatetime (in standard library)
lintingESLintpylint, flake8
unit testsJest, Mocha, Chai, @testing-librarypytest, unittest (in standard library), nose2
end-to-end testsCypresssame
mathmathjsmath (in standard library)
popular editorsVS CodeVS Code, PyCharm (JetBrains)

Linting

To lint JavaScript using ESLint:

To configure the rules used by ESLint, create the file .eslintrc.json in project directories or in a user home directory.

For example:

{
"env": {
"browser": true,
"es6": true,
"jest": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:import/recommended"],
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module"
},
"plugins": ["import"]
}

To lint Python code using pylint:

To configure the rules used by pylint, create the project file .pylintrc or a file in a user home directory (~/.pylintrc or ~/.config/pylintrc). To generate a commented version of this file in order learn about the format and available options, enter pylint --generate-rcfile > {file-path}. This file can then be modified or just used for reference. For example:

[MESSAGES CONTROL]
disable=
invalid-name,
missing-function-docstring,
missing-module-docstring,
redefined-outer-name,
too-few-public-methods

In addition, rules can be disable in source files by adding special comments. For example:

# This rule treats all module-level variables as constants.
# invalid-name: Constant name doesn't conform to UPPER_CASE naming style
# pylint: disable=C0103

# global-statement: Using the global statement
# pylint: disable=W0603

To lint Python code using flake8:

To configure the rules used by flake8, create the project file .flake8 or a file in a user home directory (~/.flake8 for Windows and ~/.config/flake8 for macOS and Linux). For example:

[flake8]
ignore = E261, E265, E302, E305, E731

Formatting

To format JavaScript code, use Prettier.

To format Python code, use autopep8 or Black.

To install and run autopep8:

pip install autopep8
autopep8 --in-place *.py

Some of the changes made by autopep8 include:

The maximum line length can be changed by adding the --max-line-length n option.

To install and run Black:

pip install black
black *.py

Some of the changes made by black include:

The maximum line length can be changed by adding the --line-length n option.

VS Code

The VS Code extension "Python" from Microsoft adds "IntelliSense, linting, debugging, code navigation, code formatting, Jupyter notebook support, refactoring, variable explorer, test explorer, snippets, and more".

Other useful VS Code extensions for Python code include autopep8 and pylint.

Resources

JavaScript resources

Python resources