This Jupyter Notebook is intended for a live presentation to Pythonistas - links and contact on hozak.info .
Working in the functional programming style feels very similar in both Python and JavaScript. Differences are mostly in the syntax and in the problems being solved (think Selenium). In contrast, Java, C++, TypeScript, or Python full of Abstract Base Classes have a different mindset, despite syntax similarities with JS.
Following is a selection of topics that I found useful, interesting, or new. It's not an introduction to either language nor a complete guide of anything.
Installation of command line interface interpreters is similar:
conda install python=3.8
vs conda install nodejs=14
brew install python@3.8
vs brew install node@14
pyenv install 3.8
vs nvm install 14
docker pull nikolaik/python-nodejs
😀Support of online tools like repl.it, cloud environments like AWS lambdas and many other environments or containers is comparable.
JavaScript is also available natively in browsers, mostly consistent between browsers that are released these days. No such luck if you have to support older browsers (think Python 2 in corporate environments). In the browser, JS code has access to a lot of WebAPIs, e.g. document.getElementById()
, which are NOT part of the language itself. Due to the fact that new browsers need to support old web pages written in old JS, the language is full of historical accidents that cannot be removed from the spec, but no one is forcing developers to use the deprecated features in new projects (think COBOL in corporate environments).
JS console is easily available in desktop browsers' Dev Tools, usually F12 or a right mouse click > Inspect Element > Console tab.
python {topic}
vs js {topic}
%%python
from sys import stderr
print('Hello, world!')
print('Hello, stderr!', file=stderr)
%%script node
console.log('Hello, world!')
console.error('Hello, stderr!')
%%python
log = print
log(1 + 2 * 3)
log(1 + int('2'))
log(0.1 + 0.2)
import math
log(math.pi)
log(1 + 2j)
%%script node
log = console.log
log(1 + 2 * 3)
log(1 + Number('2'))
log(0.1 + 0.2)
log(Math.PI)
// no complex numbers without library, e.g. mathjs.org
%%python
log = print
log('a' + 'b' 'c')
log('abc'.upper())
log(len('abc'))
log('a' * 3)
log('abcd'[0])
log('abcd'[-2])
log('efgh'[1:3])
log('ijkl'[:-1])
log('mnop'[1:])
log('qrst'[-3:][:2])
%%script node
log = console.log
log('a' + 'b' + 'c')
log('abc'.toUpperCase())
log('abc'.length)
log('a'.repeat(3))
log('abc'[0])
log('abcd'['abcd'.length - 2])
log('efgh'.slice(1, 3))
log('ijkl'.slice(0, -1))
log('mnop'.slice(1))
log('qrst'.substr(-3, 2))
%%python
log = print
a = 1
log(f'value was {a + 1}')
log(f'{a=}')
%%script node
log = console.log
let a = 1
log(`value was ${a + 1}`)
log({a})
%%python
log = print
import re
log(re.match(r'b', 'abcb'))
log(re.search(r'b', 'abcb'))
log(re.findall(r'b', 'abcb'))
%%script node
log = console.log
log('abcb'.match(/^b/))
log('abcb'.match(/b/))
log('abcb'.match(/b/g))
%%python
log = print
a, b = [1, 2], [3, 4]
log(a + b + [5])
log(str(a) + str(b) + str(5))
second_a = a
second_a.append('mutable')
copied_a = a.copy()
copied_a.append('different')
log(a)
%%script node
log = console.log
let [a, b] = [[1, 2], [3, 4]]
log([...a, ...b, 5])
log(a + b + 5)
let secondA = a
secondA.push('mutable')
let copiedA = [...a]
copiedA.push('different')
log(a)
%%python
log = print
log( list('abc') )
log( [c.upper() for c in 'abc'] )
log( [i + 1 for i in [1,2,3]] )
log( [i for i in [1,2,3] if i % 2] )
log( ';'.join(str(i) for i in [1,2,3]))
%%script node
log = console.log
log( Array.from('abc') )
log( Array.from('abc').map(c => c.toUpperCase()) )
log( [1,2,3].map(i => i + 1) )
log( [1,2,3].filter(i => i % 2) )
log( [1,2,3].join(';') )
%%python
log = print
a = {'b': 2, 'c': 'b'}
log(a)
log(a['b'])
log(a[a['c']])
log(a.get('f', None))
log(a.get('f', {}).get('g', 'default'))
%%script node
log = console.log
let a = {b: 2, c: 'b'}
log(a)
log(a.b)
log(a[a.c])
log(a.f)
log(a.f?.g ?? 'default')
%%python
log = print
a = {'inner': 1}
b = {'a': a}
log(b)
b['a'][2] = 3
log(a)
%%script node
log = console.log
let a = {'inner': 1}
let b = {a}
log(b)
b.a[2] = 3
log(a)
%%python
log = print
a, b, c, d = 1, 2, 2, False
if a == b and a == c or not d:
log('yes')
else:
log('no')
log('yes' if a == b else 'no')
%%script node
log = console.log
let a = 1, b = 2, c = 2, d = false
if (a === b && a === c || !d) {
log('yes')
} else {
log('no')
}
log(a == b ? 'yes' : 'no')
%%python
log = print
for i in range(2, 6, 2):
log(i)
out = ''
for item in ['a', 1, 'b']:
if type(item) == str: out += item
out += '.'
log(out)
%%script node
log = console.log
for (let i = 2; i < 6; i += 2) {
log(i)
}
let out = ''
for (let item of ['a', 1, 'b']) {
if (typeof item === 'string') out += item
out += '.'
}
log(out)
%%python
log = print
def first(a, b="b", c=None, *args):
second(a)
def second(b):
log(b)
first(1)
%%script node
log = console.log
function first(a, b="b", c, ...rest) {
second(a)
}
const second = function second(b) {
log(b)
}
first(1)
%%python
log = print
def f(a, **kwargs):
log(kwargs)
c = {'d': 3}
f(a=1, b=2, **c)
%%script node
log = console.log
function f({a, ...spread}) {
log(spread)
}
c = {d: 3}
f({a: 1, b: 2, ...c})
%%python
log = print
points = [(1, 2), (2, 1)]
points.sort(key=lambda point: point[1])
log(points)
%%script node
log = console.log
const points = [{x: 1, y: 2}, {x: 2, y: 1}]
points.sort((a, b) => a.y - b.y)
log(points)
%%python
log = print
a = 1
b = 2
def nasty():
a = 5 # different 'a'
global b
b = 6
nasty()
log(a, b)
%%script node
log = console.log
var a = 1 // function scope
b = 2 // global scope
let c = 3 // block scope reassignable
const d = 4 // block non-reassignable (may be mutable)
function nasty() {
var a = 5
b = 6
c = 7
}
nasty()
log(a, b, c, d)
%%python
log = print
def outer(a):
return lambda b: log(a, b)
inner = outer(1)
outer(2)(3)
inner(4)
%%script node
log = console.log
function outer(a) {
return (b) => log(a, b)
}
const inner = outer(1)
outer(2)(3)
inner(4)
%%python
log = print
def my_generator():
yield 'header'
yield from [1, 2, 3]
my_iterator = my_generator()
log(next(my_iterator))
for record in my_iterator:
log(record)
%%script node
log = console.log
function* myGenerator() {
yield 'header'
yield* [1, 2, 3]
}
let myIterator = myGenerator()
log(myIterator.next().value)
for (const record of myIterator) {
log(record)
}
%%python
log = print
from asyncio import sleep, gather, run
from random import random
async def race_condition(n):
await sleep(random())
log(n)
async def main():
await gather(race_condition(1),
race_condition(2),
race_condition(3))
run(main())
%%script node
log = console.log
const sleep = (t) => new Promise(resolve =>
setTimeout(resolve, t * 1000))
async function raceCondition(n) {
await sleep(Math.random())
log(n)
}
raceCondition(1)
raceCondition(2)
raceCondition(3)
%%python
log = print
a = {"b": 1}
try:
a["c"]
raise NotImplementedError('TODO later')
except KeyError as err:
log(err)
finally:
log('be happy')
%%script node
log = console.log
const a = {b: 1}
try {
a.c.d
throw new Error('TODO later')
} catch (err) {
if (!err instanceof TypeError) throw err
log(err.message)
} finally {
log('be happy')
}
pep8
vs eslint
%%sh
exit 0
virtualenv venv
source ./venv/bin/activate
touch requirements.txt
pip install -r requirements.txt
pip freeze > requirements-lock.txt
%%sh
exit 0
npm init # or `touch package.json`
npm install # or `yarn`
%%writefile utils.py
log = print
def hello(): log('hello')
%%writefile utils.mjs
const log = console.log
export const hello = () => log('hello')
%%writefile app.py
from utils import hello
hello()
%%writefile app.mjs
import {hello} from './utils.mjs'
hello()
%%sh
python app.py
%%sh
node app.mjs
%%html
<style>
@media (min-width: 1000px) {
#notebook-container {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
#notebook-container {
width: 100%;
max-width: 1200px;
padding-left: 0;
}
div.text_cell {
grid-column: 1 / span 2;
margin-bottom: 1em;
}
.prompt {
min-width: 60px;
font-size: 10px;
}
div.input_area {
background:
linear-gradient(to bottom, #eef 3em, #f7f7f7 3em);
}
</style>
%%js
require(['notebook/js/codecell'], (codecell) => {
codecell.CodeCell.options_default.highlight_modes
.magic_javascript =
{reg: [/^%%(?:js|javascript|script node)/]}
Jupyter.notebook.events.one('kernel_ready.Kernel', () => {
Jupyter.notebook.get_cells().map((cell) => {
if (cell.cell_type == 'code'){
cell.auto_highlight()
}})
})
})