JavaScript (ES2026) Module 1 – Start here: what JavaScript is and how to run it
JavaScript for Python developers
For Python developers: how JavaScript differs in numbers, truthiness, dicts and Map, sorting, defaults, this and async, both languages run side by side.
What you will learn
- Map Python habits (truthiness, integers, dicts, comprehensions, exceptions, asyncio) to JavaScript
- Avoid the traps that bite Python developers first, such as ==, number precision, sort order, in and this
- Choose the JavaScript equivalent for common Python idioms
Before you start
What you’ll learn · Before you start
What you will learn
- Map Python habits (truthiness, integers, dicts, comprehensions, exceptions, asyncio) to JavaScript
- Avoid the traps that bite Python developers first, such as ==, number precision, sort order, in and this
- Choose the JavaScript equivalent for common Python idioms
Before you start
On this page
If you write Python, most of JavaScript will feel familiar: functions are values, closures work the same way,
exceptions are thrown and caught, async and await look the same, and f-strings have a close cousin in template
literals. The differences are in the details, and they are the kind that let code run without an error and still
give a wrong answer. JavaScript has one number type for whole and fractional numbers, so integers stop being exact
after 2⁵³. Empty lists are truthy, and sort() compares numbers as text. Objects reorder number-like keys, and
in checks keys, not values. A method taken off its object forgets the object, and an async function starts
running the moment you call it. This lesson runs the same programs in Python 3.14.8 and Node.js 24.21.0, so you can
see each difference in recorded output rather than take it on trust.
The same jobs in both languages
Here are three jobs you do every day in Python: counting words, sorting records by two keys, and reading a dictionary that may lack a key, written in both languages:
Python · side_by_side.py
# Three everyday jobs in Python: count words, sort records by two keys, read a dict safely.
from collections import Counter
text = "the cat sat on the mat by the door"
counts = Counter(text.split())
print("top three:", counts.most_common(3))
people = [{"name": "Ravi", "age": 31}, {"name": "Asha", "age": 31}, {"name": "Meera", "age": 27}]
oldest_first = sorted(people, key=lambda p: (-p["age"], p["name"]))
print("oldest first:", [p["name"] for p in oldest_first])
prices = {"tea": 20, "coffee": 35}
print("samosa, with a default:", prices.get("samosa", 0))
try:
prices["samosa"]
except KeyError as error:
print("samosa, without one: KeyError", error) Output
top three: [('the', 3), ('cat', 1), ('sat', 1)]
oldest first: ['Asha', 'Ravi', 'Meera']
samosa, with a default: 0
samosa, without one: KeyError 'samosa'
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 side_by_side.py
JavaScript · side-by-side.mjs
// The same three jobs in JavaScript: count words, sort records by two keys, read a map safely.
const text = 'the cat sat on the mat by the door';
const counts = new Map();
for (const word of text.split(' ')) counts.set(word, (counts.get(word) ?? 0) + 1);
const topThree = [...counts].sort((a, b) => b[1] - a[1]).slice(0, 3);
console.log('top three:', topThree);
const people = [{ name: 'Ravi', age: 31 }, { name: 'Asha', age: 31 }, { name: 'Meera', age: 27 }];
const byName = (a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
const oldestFirst = people.toSorted((a, b) => b.age - a.age || byName(a, b));
console.log('oldest first:', oldestFirst.map((p) => p.name));
const prices = new Map([['tea', 20], ['coffee', 35]]);
console.log('samosa, with a default:', prices.get('samosa') ?? 0);
console.log('samosa, without one:', prices.get('samosa')); Output
top three: [ [ 'the', 3 ], [ 'cat', 1 ], [ 'sat', 1 ] ] oldest first: [ 'Asha', 'Ravi', 'Meera' ] samosa, with a default: 0 samosa, without one: undefined
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node side-by-side.mjs
Runs on this device, in your browser. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
The two outputs say the same thing in two notations, and the code shows how the idioms map:
Counterbecomes aMap. JavaScript has noCounter; the patterncounts.set(word, (counts.get(word) ?? 0) + 1)does its job, and??supplies 0 for a word not seen yet. Python’smost_commonkeeps words with equal counts in the order it first met them, and so did the JavaScript version: aMapremembers insertion order, andsortis stable, so equal elements keep their order.- A key tuple becomes a comparator. Python sorts by a key,
(-age, name). JavaScript’ssorttakes a comparator instead: a function given two items, whose result below zero, zero or above zero says which comes first.b.age - a.age || byName(a, b)sorts by age, oldest first, and by name when the ages are equal.toSortedreturns a sorted copy, likesorted;sortsorts in place, likelist.sort. - A missing key is not an error.
prices.get('samosa')isundefined, where Python’sprices["samosa"]raisesKeyError.prices.get('samosa') ?? 0matchesdict.getwith a default. The quietundefinedis convenient and dangerous at once: a typo in a key gives youundefinedinstead of an exception, and the problem shows up later.
Nine questions, two different sets of answers
The next two programs ask both languages the same nine questions. Each line prints a question and its answer:
Python · gotchas.py
# Nine expressions whose answers a Python developer knows. gotchas.mjs asks JavaScript the same questions.
def add(item, items=[]):
items.append(item)
return items
add(1)
rows = [
("2 ** 53 + 1 equals 2 ** 53", 2 ** 53 + 1 == 2 ** 53),
("-7 % 3", -7 % 3),
("7 divided by 2, rounded down", 7 // 2),
("an empty list is truthy", bool([])),
("[10, 9, 1] sorted by default", sorted([10, 9, 1])),
("'a' is in ['a']", "a" in ["a"]),
("[1, 2] equals [1, 2]", [1, 2] == [1, 2]),
("add(2) after add(1)", add(2)),
("keys of {b: 1, 10: 1, 2: 1}", list({"b": 1, 10: 1, 2: 1})),
]
for label, value in rows:
print(f"{label:31} {value!r}") Output
2 ** 53 + 1 equals 2 ** 53 False
-7 % 3 2
7 divided by 2, rounded down 3
an empty list is truthy False
[10, 9, 1] sorted by default [1, 9, 10]
'a' is in ['a'] True
[1, 2] equals [1, 2] True
add(2) after add(1) [1, 2]
keys of {b: 1, 10: 1, 2: 1} ['b', 10, 2]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 gotchas.py
JavaScript · gotchas.mjs
// The questions of gotchas.py, asked of JavaScript. Several answers differ.
function add(item, items = []) {
items.push(item);
return items;
}
add(1);
const rows = [
['2 ** 53 + 1 equals 2 ** 53', 2 ** 53 + 1 === 2 ** 53],
['-7 % 3', -7 % 3],
['7 divided by 2, rounded down', Math.floor(7 / 2)],
['an empty list is truthy', Boolean([])],
['[10, 9, 1] sorted by default', [10, 9, 1].sort()],
["'a' is in ['a']", 'a' in ['a']],
['[1, 2] equals [1, 2]', [1, 2] === [1, 2]],
['add(2) after add(1)', add(2)],
['keys of {b: 1, 10: 1, 2: 1}', Object.keys({ b: 1, 10: 1, 2: 1 })],
];
for (const [label, value] of rows) console.log(label.padEnd(31), value); Output
2 ** 53 + 1 equals 2 ** 53 true
-7 % 3 -1
7 divided by 2, rounded down 3
an empty list is truthy true
[10, 9, 1] sorted by default [ 1, 10, 9 ]
'a' is in ['a'] false
[1, 2] equals [1, 2] false
add(2) after add(1) [ 2 ]
keys of {b: 1, 10: 1, 2: 1} [ '2', '10', 'b' ]
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node gotchas.mjs
Runs on this device, in your browser. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
Side by side, from the two outputs:
| Question | Python 3.14.8 | Node.js 24.21.0 |
|---|---|---|
2 ** 53 + 1 equals 2 ** 53 |
False |
true |
-7 % 3 |
2 |
-1 |
| 7 divided by 2, rounded down | 3 |
3 |
| An empty list is truthy | False |
true |
[10, 9, 1] sorted by default |
[1, 9, 10] |
[ 1, 10, 9 ] |
'a' is in ['a'] |
True |
false |
[1, 2] equals [1, 2] |
True |
false |
add(2) after add(1), with a list as the default |
[1, 2] |
[ 2 ] |
Keys of {b: 1, 10: 1, 2: 1} |
['b', 10, 2] |
[ '2', '10', 'b' ] |
Eight of the nine answers differ. Here is why, row by row.
Numbers. Python’s int has unlimited precision. JavaScript has one number type for everything, the 64-bit
floating-point double that Python uses for float, so whole numbers are exact only up to Number.MAX_SAFE_INTEGER,
2⁵³ − 1, which is 9,007,199,254,740,991. Past it, 2 ** 53 + 1 rounds to 2 ** 53. For larger exact integers
JavaScript has a second type, BigInt, written with an n suffix: 2n ** 53n + 1n is exact. Money is safest as a
whole number of the smallest unit, cents or paise, which stays exact to over 90 trillion rupees or dollars.
Remainder and division. % takes the sign of the dividend in JavaScript, so -7 % 3 is -1; Python’s takes the
sign of the divisor and gives 2. Python’s // has no operator in JavaScript, where // starts a comment, so
7 // 2 silently means 7. Write Math.floor(7 / 2), which matches Python for negative numbers too, or
Math.trunc, which rounds towards zero.
Truthiness. Python treats empty collections as false. In JavaScript only eight values are falsy: false, 0,
-0, 0n, "", null, undefined and NaN. An empty array or an empty object is truthy, so if (items) is
true for []; write if (items.length > 0).
Sorting. Without a comparator, sort turns the elements into strings and compares those, so 10 comes before
9 because "1" comes before "9". Sorting numbers always needs (a, b) => a - b.
in and equality. JavaScript’s in asks whether an object has a property with that key. For an array the keys
are indices, so 0 in ['a'] is true and 'a' in ['a'] is false. Use includes for membership:
['a'].includes('a'). Equality has its own twist. JavaScript’s === compares objects by identity, like Python’s
is, so two equal-looking arrays are not ===; compare their contents yourself. And == converts types before it
compares ('1' == 1 is true), which is why JavaScript code uses ===.
Default arguments. Python evaluates a default once, when the function is defined, so the same list is shared by
every call. JavaScript evaluates a default at every call that needs it, so add(2) gets a fresh [], and the famous
mutable-default bug does not exist.
Key order. A Python dict keeps insertion order for every key. A JavaScript object lists keys that look like
array indices first, in numeric order, and then the other keys in insertion order, which ECMA-262 specifies. Object
keys are also always strings or symbols: obj[1] and obj['1'] are the same entry. A Map keeps insertion order
and the type of every key, so a Map is the true counterpart of a dict whose keys are not plain words.
Python idioms, translated
| Python | JavaScript |
|---|---|
[x * 2 for x in xs if x > 0] |
xs.filter((x) => x > 0).map((x) => x * 2) |
{k: v for k, v in pairs} |
Object.fromEntries(pairs), or new Map(pairs) |
for i, x in enumerate(xs): |
for (const [i, x] of xs.entries()) |
for k, v in d.items(): |
for (const [k, v] of map), or Object.entries(obj) for an object |
len(xs), len(d) |
xs.length, map.size |
range(5) |
for (let i = 0; i < 5; i++), or Array.from({ length: 5 }, (_, i) => i) |
f"{name} owes {amount}" |
`${name} owes ${amount}` |
None |
null for “no value on purpose”; undefined is what missing properties and arguments give you |
x is None |
x === null, or x == null to accept undefined too |
set(xs), a | b, a & b |
new Set(xs), a.union(b), a.intersection(b) (ECMAScript 2025) |
raise ValueError("…") |
throw new RangeError('…'), or TypeError for a wrong kind of value |
try: … except ValueError as e: … |
try { … } catch (e) { if (!(e instanceof RangeError)) throw e; … } |
isinstance(x, list) |
Array.isArray(x); typeof x === 'string' for primitives; x instanceof Map for objects |
| A tuple | An array; Object.freeze stops changes, but there is no tuple type |
Two Python tools have no direct counterpart in Node.js 24: zip (an Iterator.zip is planned for ECMAScript 2027)
and math.fsum, whose counterpart Math.sumPrecise is part of ECMAScript 2026 but not yet in Node.js 24. A short
loop does the job of either.
Methods and this
In Python a method taken off its object stays bound to it. In JavaScript it does not: the object a method works on,
this, is decided by how the function is called, not where it was defined.
Python · bound.py
# A method taken off its object still knows the object in Python: it is a bound method.
class Counter:
def __init__(self):
self.n = 0
def tick(self):
self.n += 1
return self.n
counter = Counter()
tick = counter.tick
print("tick() twice:", tick(), tick()) Output
tick() twice: 1 2
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bound.py
JavaScript · bound.mjs
// The same move in JavaScript: a method taken off its object forgets the object.
class Counter {
n = 0;
tick() {
this.n += 1;
return this.n;
}
}
const counter = new Counter();
const tick = counter.tick;
try {
tick();
} catch (error) {
console.log('tick() on its own:', error.name, '(this is undefined)');
}
const bound = counter.tick.bind(counter);
console.log('bound tick() twice:', bound(), bound()); Output
tick() on its own: TypeError (this is undefined) bound tick() twice: 1 2
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node bound.mjs
Runs on this device, in your browser. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
Called as tick(), the function has no object in front of it, so this is undefined (modules are strict) and
reading this.n throws. Passing counter.tick to setTimeout or map loses the object in the same way, and an
event listener calls it with the element as this instead.
counter.tick.bind(counter) makes a copy with this fixed, and an arrow function, () => counter.tick(), keeps the
call in the form counter.tick(). The Java lesson of this module looks at this from another side.
async and await: the same words, another start
Both languages write async def or async function and await, but they start the work at different times:
Python · async_start.py
# When does an async function start? In Python, only once it is awaited or scheduled.
import asyncio
async def fetch_data():
print("fetch_data starts")
await asyncio.sleep(0)
print("fetch_data resumes")
return 42
async def main():
print("before the call")
pending = fetch_data()
print("after the call, before await")
print("result:", await pending)
asyncio.run(main()) Output
before the call after the call, before await fetch_data starts fetch_data resumes result: 42
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 async_start.py
JavaScript · async-start.mjs
// When does an async function start? In JavaScript, at once: it runs until its first await.
async function fetchData() {
console.log('fetchData starts');
await null;
console.log('fetchData resumes');
return 42;
}
console.log('before the call');
const pending = fetchData();
console.log('after the call, before await');
console.log('result:', await pending); Output
before the call fetchData starts after the call, before await fetchData resumes result: 42
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node async-start.mjs
Runs on this device, in your browser. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
In Python, calling fetch_data() only creates a coroutine object, and the asyncio documentation stresses that
calling a coroutine does not schedule it; its body starts when it is awaited. In JavaScript, calling fetchData()
runs its body at once, up to the first await, and returns a promise for the rest. Three consequences matter when
you port code:
- There is no
asyncio.run. Browsers and Node.js run an event loop all the time, so you call anasyncfunction andawaitits promise, at the top level of a module if you like. - Work starts when you call, not when you await.
const a = load(1); const b = load(2);starts both loads at once, andawait Promise.all([a, b])collects them, much likeasyncio.gather. - A promise that fails while nobody waits for it is not silent. Since Node.js 15 an unhandled rejection ends the process with an error by default, so every promise you start must eventually be awaited or handled.
Exercise: port an expense report
This is a small Python function that totals a trip’s expenses per category, in paise so that no rounding creeps in. It runs on Python 3.14.8:
# The function to port: total a trip's expenses per category, in paise (whole numbers, so no rounding errors).
def totals_by_category(expenses):
"""Returns (category, total) pairs, largest total first, then by category name."""
totals = {}
for expense in expenses:
amount = expense["amount_paise"]
if not isinstance(amount, int) or isinstance(amount, bool):
raise TypeError(f"amount must be a whole number of paise, got {amount!r}")
category = expense.get("category") or "other"
totals[category] = totals.get(category, 0) + amount
return sorted(totals.items(), key=lambda pair: (-pair[1], pair[0]))
trip = [
{"category": "food", "amount_paise": 45000},
{"category": "travel", "amount_paise": 120000},
{"category": "food", "amount_paise": 18050},
{"category": "", "amount_paise": 9900},
{"category": "travel", "amount_paise": -20000},
]
print(totals_by_category(trip))
print(totals_by_category([]))
try:
totals_by_category([{"category": "food", "amount_paise": 12.5}])
except TypeError as error:
print("TypeError:", error) Output
[('travel', 100000), ('food', 63050), ('other', 9900)]
[]
TypeError: amount must be a whole number of paise, got 12.5
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 totals.py
Port it to JavaScript. The sample tests check the cases where a word-for-word port goes wrong: the comparator, the empty category, refunds and an amount that is not a whole number.
Exercise · Medium · JavaScript
Port a Python expense report to JavaScript
Port totals_by_category from the lesson's totals.py to JavaScript as totalsByCategory(expenses). Each expense is an object { category, amountPaise }; the function returns [category, total] pairs, largest total first, and pairs with the same total in alphabetical order of their category, exactly as the Python version does:
- a missing or empty category counts as
"other"; - negative amounts are refunds and are added like the others;
- an amount that is not a whole number throws a
TypeErrorwhose message starts withamount must be a whole number of paise; - no expenses give an empty array.
Watch the three places where a word-for-word port goes wrong: what sort does without a comparator, which values count as false, and how to recognise a whole number when JavaScript has one number type.
Starter code · totals.mjs
/**
* A trip's expenses totalled per category, in paise.
* @param {{ category?: string, amountPaise: number }[]} expenses
* @returns {[string, number][]} pairs, largest total first, then by category name
*/
export function totalsByCategory(expenses) {
return [];
} The sample tests · totals.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { totalsByCategory } from './totals.mjs';
test('totals each category and puts the largest first', () => {
const trip = [
{ category: 'food', amountPaise: 45000 },
{ category: 'travel', amountPaise: 120000 },
{ category: 'food', amountPaise: 18050 },
];
assert.deepEqual(totalsByCategory(trip), [['travel', 120000], ['food', 63050]]);
});
test('sorts by the number, not by its digits', () => {
const trip = [{ category: 'a', amountPaise: 900 }, { category: 'b', amountPaise: 10000 }];
assert.deepEqual(totalsByCategory(trip), [['b', 10000], ['a', 900]]);
});
test('three categories come out by total, not in the order they were added', () => {
const trip = [
{ category: 'stay', amountPaise: 500 },
{ category: 'food', amountPaise: 900 },
{ category: 'travel', amountPaise: 100 },
];
assert.deepEqual(totalsByCategory(trip), [['food', 900], ['stay', 500], ['travel', 100]]);
});
test('equal totals are in alphabetical order of the category', () => {
const two = [{ category: 'stay', amountPaise: 500 }, { category: 'food', amountPaise: 500 }];
assert.deepEqual(totalsByCategory(two), [['food', 500], ['stay', 500]]);
const three = [
{ category: 'stay', amountPaise: 500 },
{ category: 'food', amountPaise: 500 },
{ category: 'misc', amountPaise: 500 },
];
assert.deepEqual(totalsByCategory(three), [['food', 500], ['misc', 500], ['stay', 500]]);
});
test('refunds subtract, and a missing or empty category is "other"', () => {
const trip = [
{ category: 'travel', amountPaise: 120000 },
{ category: 'travel', amountPaise: -20000 },
{ amountPaise: 700 },
{ category: '', amountPaise: 300 },
];
assert.deepEqual(totalsByCategory(trip), [['travel', 100000], ['other', 1000]]);
});
test('no expenses give an empty array', () => {
assert.deepEqual(totalsByCategory([]), []);
});
test('an amount with paise fractions is rejected with a TypeError', () => {
assert.throws(() => totalsByCategory([{ category: 'food', amountPaise: 12.5 }]), TypeError);
}); A hint
A Map keeps your categories in a dictionary the way Python's dict does: totals.get(key) ?? 0 plays the part of totals.get(key, 0), and [...totals] gives the pairs. Number.isInteger(x) is the test for a whole number. And sort needs a comparator that returns a number: (a, b) => b[1] - a[1] for the totals, then a second key for ties.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Check yourself
7 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.
Interview questions
Fresher · Why does [10, 9, 1].sort() return [1, 10, 9] in JavaScript?
Because without a comparator sort turns each element into a string and orders those strings by their UTF-16
code units, the way a dictionary orders words. "1" comes first, then "10", because a shorter prefix sorts before
a longer string, and "9" last: the numbers are never compared as numbers. Give it a comparator whose result says
which item goes first, below zero, zero or above zero: [10, 9, 1].sort((a, b) => a - b) gives [1, 9, 10], and
(a, b) => b - a sorts from largest to smallest. Two details complete the answer. sort reorders the array itself,
while toSorted returns a sorted copy. And since ECMAScript 2019 the specification requires a stable sort, so items
that compare as equal stay in their original order. A Python developer expects numeric order because Python compares
the values themselves.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Mid to senior
You are porting a Python service to Node.js. It totals invoice amounts and counts items in dicts keyed by integer product ids, which arrive as JSON. Which differences in numbers and dictionaries can silently change its results, and how do you guard against each one?
-
Fresher to mid
An asyncio script is ported to Node.js line by line. Some async functions were called without await, which did nothing in Python, and the port now runs them, in another order, and sometimes crashes with an unhandled rejection. Explain what happens and how to port the script correctly.
Key takeaways
- Numbers are doubles: integers are exact only up to 2⁵³ − 1. Use BigInt for larger exact integers and whole paise or cents for money.
%keeps the sign of the dividend,//is a comment, and empty arrays and objects are truthy.sort()compares as strings unless you pass a comparator;inchecks keys and indices;===compares objects by identity.- Defaults are evaluated at each call, objects put number-like keys first, and a
Mapis the counterpart of adict. - A detached method loses
this, anasyncfunction starts when called, and an unhandled rejection ends a Node.js process.
References
- ECMAScript 2026 Language Specification: The Number type (Ecma International)
- ECMAScript 2026 Language Specification: ToBoolean (Ecma International)
- ECMAScript 2026 Language Specification: OrdinaryOwnPropertyKeys (the order of keys) (Ecma International)
- JavaScript language overview (MDN Web Docs)
- Array.prototype.sort() (MDN Web Docs)
- Remainder (%) (MDN Web Docs)
- The in operator (MDN Web Docs)
- Default parameters (MDN Web Docs)
- async function (MDN Web Docs)
- Truthy (MDN glossary) (MDN Web Docs)
- Node.js 24 documentation: --unhandled-rejections (OpenJS Foundation (Node.js))
- The Python Tutorial (Python Software Foundation)
- The Python Tutorial: default argument values (Python Software Foundation)
- Python built-in types: numeric types and truth value testing (Python Software Foundation)
- The Python Language Reference: binary arithmetic operations (Python Software Foundation)
- asyncio: coroutines and tasks (Python Software Foundation)
- collections.Counter (Python Software Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress