Python idioms for JavaScript developers.
In JavaScript you'd import a helper for these. In Python they are a slice, a comprehension or one call. The proof under each row is a doctest, run on Python 3.11–3.14.
Lists
JavaScript helperPython
head(items) / last(items)from head, lastitems[0] / items[-1]Negative indexes count from the end. Both raise IndexError on an empty list.>>> items = [1, 2, 3]passed on Python 3.11 to 3.14: >>> items[0], items[-1](1, 3)
tail(items) / initial(items)from tail, initialitems[1:] / items[:-1]Slices never raise; on an empty list they return an empty list.>>> items = [1, 2, 3]passed on Python 3.11 to 3.14: >>> items[1:], items[:-1], [][1:]([2, 3], [1, 2], [])
take(items, n) / take_right(items, n)from take, take-rightitems[:n] / items[len(items) - n:]Careful: items[-n:] returns everything when n is 0.>>> items, n = [1, 2, 3, 4], 0passed on Python 3.11 to 3.14: >>> items[:2], items[-n:], items[len(items) - n:]([1, 2], [1, 2, 3, 4], [])
drop(items, n) / drop_right(items, n)from drop, drop-rightitems[n:] / items[:len(items) - n]The same zero trap applies to items[:-n].>>> items = [1, 2, 3, 4]passed on Python 3.11 to 3.14: >>> items[1:], items[:len(items) - 1], items[:-0]([2, 3, 4], [1, 2, 3], [])
initialize_list_with_range(...) / initialize_list_with_values(n, v)from initialize-list-with-range, initialize-list-with-valueslist(range(start, stop, step)) / [value] * n[[]] * 3 repeats one list three times; build mutable items with a comprehension.passed on Python 3.11 to 3.14: >>> list(range(0, 10, 3)), [0] * 3([0, 3, 6, 9], [0, 0, 0])>>> shared = [[]] * 2>>> shared[0].append(1)passed on Python 3.11 to 3.14: >>> shared, [[] for _ in range(2)]([[1], [1]], [[], []])
cast_list(value)from cast-listvalue if isinstance(value, list) else [value]>>> def as_list(value):... return value if isinstance(value, list) else [value]passed on Python 3.11 to 3.14: >>> as_list(1), as_list([1])([1], [1])
spread(lists) / [...a, ...b]from spread[*a, *b]Unpacking works with any iterables, and in calls too.>>> a, b = [1, 2], (3,)passed on Python 3.11 to 3.14: >>> [*a, *b, 4][1, 2, 3, 4]
merge(*lists)from mergeitertools.zip_longest(*lists)zip stops at the shortest; zip_longest pads with fillvalue.>>> from itertools import zip_longestpassed on Python 3.11 to 3.14: >>> list(zip_longest([1, 2], ["a"], fillvalue="-"))[(1, 'a'), (2, '-')]
sample(items) / shuffle(items)from sample, shufflerandom.choice(items) / random.sample(items, k=len(items))random.shuffle works in place; sample returns a new list.>>> import random>>> items = [1, 2, 3, 4]passed on Python 3.11 to 3.14: >>> random.choice(items) in items, sorted(random.sample(items, k=len(items)))(True, [1, 2, 3, 4])
symmetric_difference(a, b)from symmetric-differenceset(a) ^ set(b)For an order-keeping version, see the difference_by snippet.passed on Python 3.11 to 3.14: >>> sorted({1, 2, 3} ^ {1, 2, 4})[3, 4]Checks
JavaScript helperPython
every(items, fn) / some(items, fn) / none(items, fn)from every, some, noneall(...) / any(...) / not any(...)All three stop early, and take a generator expression.>>> nums = [2, 4, 5]passed on Python 3.11 to 3.14: >>> all(n > 0 for n in nums), any(n % 2 for n in nums), not any(n > 9 for n in nums)(True, True, True)
is_empty(value)from is-emptynot valueEmpty containers, 0, "" and None are all falsy.passed on Python 3.11 to 3.14: >>> not [], not {}, not "", not [0](True, True, True, False)all_equal(items)from all-equallen(set(items)) <= 1Needs hashable items; otherwise use all(x == items[0] for x in items).passed on Python 3.11 to 3.14: >>> len(set([3, 3, 3])) <= 1, len(set([3, 1])) <= 1(True, False)includes_all(a, b) / includes_any(a, b)from includes-all, includes-anyset(b) <= set(a) / not set(a).isdisjoint(b)>>> a = [1, 2, 3, 4]passed on Python 3.11 to 3.14: >>> set([1, 4]) <= set(a), not set(a).isdisjoint([4, 9])(True, True)
is_even(n) / is_odd(n) / is_divisible(n, d)from is-even, is-odd, is-divisiblen % 2 == 0 / n % 2 == 1 / n % d == 0In Python, -3 % 2 is 1, so the odd check is safe for negatives.passed on Python 3.11 to 3.14: >>> 4 % 2 == 0, -3 % 2 == 1, 12 % 4 == 0(True, True, True)Searching
JavaScript helperPython
find(items, fn) / find_last(items, fn)from find, find-lastnext((x for x in items if fn(x)), None)Stops at the first match. Search reversed(items) for the last one.>>> items = [1, 2, 3, 4]passed on Python 3.11 to 3.14: >>> next((x for x in items if x % 2 == 0), None), next((x for x in reversed(items) if x % 2), None)(2, 3)
find_index(items, fn) / find_last_index(items, fn)from find-index, find-last-indexnext((i for i, x in enumerate(items) if fn(x)), -1)For an exact value, items.index(value) is simpler, but raises ValueError if it's missing.>>> items = [1, 2, 3, 4]passed on Python 3.11 to 3.14: >>> next((i for i, x in enumerate(items) if x > 2), -1), items.index(4)(2, 3)
Dicts
JavaScript helperPython
key_in_dict(d, key)from key-in-dictkey in d>>> d = {"a": 1}passed on Python 3.11 to 3.14: >>> "a" in d, "z" in d(True, False)
keys_only(d) / values_only(d) / dict_to_list(d)from keys-only, values-only, dict-to-listlist(d) / list(d.values()) / list(d.items())Iterating a dict yields its keys; you rarely need the list at all.>>> d = {"a": 1, "b": 2}passed on Python 3.11 to 3.14: >>> list(d), list(d.values()), list(d.items())(['a', 'b'], [1, 2], [('a', 1), ('b', 2)])
to_dictionary(keys, values)from to-dictionarydict(zip(keys, values, strict=True))strict=True catches lists of different lengths.passed on Python 3.11 to 3.14: >>> dict(zip(["a", "b"], [1, 2], strict=True)){'a': 1, 'b': 2}Functions
JavaScript helperPython
check_prop(fn, prop)from check-proplambda d: fn(d[prop])A lambda reads better than a factory; operator.itemgetter covers plain lookups.>>> is_adult = lambda user: user["age"] >= 18passed on Python 3.11 to 3.14: >>> is_adult({"age": 20}), is_adult({"age": 9})(True, False)
for_each(items, fn) / for_each_right(items, fn)from for-each, for-each-rightfor x in items / for x in reversed(items)A comprehension is for building a list, not for side effects.passed on Python 3.11 to 3.14: >>> for x in reversed([1, 2, 3]):... print(x)321curry(fn, *args)from curryfunctools.partial(fn, *args)>>> from functools import partial>>> int_from_binary = partial(int, base=2)passed on Python 3.11 to 3.14: >>> int_from_binary("1010")10
when(predicate, fn)(x)from whenfn(x) if predicate(x) else x>>> x = 3passed on Python 3.11 to 3.14: >>> x * 2 if x % 2 else x6
delay(fn, ms, *args)from delaythreading.Timer(seconds, fn, args).start()Takes seconds, not milliseconds. In async code, use await asyncio.sleep().>>> import threading>>> calls = []>>> timer = threading.Timer(0.01, calls.append, ["done"])>>> timer.start(); timer.join()passed on Python 3.11 to 3.14: >>> calls['done']
Strings and numbers
JavaScript helperPython
capitalize(s) / decapitalize(s)from capitalize, decapitalizes[:1].upper() + s[1:]str.capitalize() also lowercases the rest of the string.>>> s = "fooBar"passed on Python 3.11 to 3.14: >>> s[:1].upper() + s[1:], s.capitalize(), s[:1].lower() + s[1:]('FooBar', 'Foobar', 'fooBar')
n_times_string(s, n)from n-times-strings * npassed on Python 3.11 to 3.14: >>> "ab" * 3'ababab'pad_number(n, width)from pad-numberf"{n:0{width}d}" / str(n).zfill(width)>>> n, width = 42, 5passed on Python 3.11 to 3.14: >>> f"{n:0{width}d}", str(-42).zfill(5)('00042', '-0042')
reverse_number(n)from reverse-numberint(str(abs(n))[::-1])Reverse the text, then put the sign back yourself.>>> n = -1230passed on Python 3.11 to 3.14: >>> int(str(abs(n))[::-1]) * (-1 if n < 0 else 1)-321
celsius_to_fahrenheit(c) / km_to_miles(km) / ...from celsius-to-fahrenheit, fahrenheit-to-celsius, km-to-miles, miles-to-kmc * 9 / 5 + 32A named constant beats a one-line function.>>> KM_PER_MILE = 1.609344passed on Python 3.11 to 3.14: >>> 100 * 9 / 5 + 32, (212 - 32) * 5 / 9, round(10 / KM_PER_MILE, 3), 5 * KM_PER_MILE(212.0, 100.0, 6.214, 8.04672)
Dates
JavaScript helperPython
from_iso_date(s) / to_iso_date(d)from from-iso-date, to-iso-datedate.fromisoformat(s) / d.isoformat()Since 3.11, fromisoformat accepts most ISO 8601 formats.>>> from datetime import date>>> d = date.fromisoformat("2024-06-15")passed on Python 3.11 to 3.14: >>> d.isoformat(), d.year('2024-06-15', 2024)
The JavaScript-style names come from 30-seconds-of-python by the 30 seconds of code contributors,CC BY 4.0, where each was a separate snippet. Not affiliated with 30 seconds of code.