Introduction
JavaScript and Python are two very important languages today. Too many programmers, however, work in both languages, but know just one of them well. This means they end up writing code in one language in the same style as the other, unaware of some of the more subtle differences between the two. If you know JavaScript or Python well, and you want to improve your skills and knowledge of the other, I wrote this article for you.
Disclaimer: I know Python (slightly) better than I know JavaScript, and I’ve not done any JavaScript outside of the browser, so I tried to keep the bits about JavaScript agnostic to the host environment, but, fair warning, there may be subtle differences in server-side JavaScript that are not mentioned here because I don’t know them.
Introductory Concepts
Mutability
Python’s data types include the concept of “mutability”. Some data types are immutable, which means they cannot be modified; any modification returns a new value, but does not modify the value in the original variable. Other types, like list
s, can be modified in place. In general, it’s not necessarry to think about this distinction when writing Python code; the various types behave as one would intuitively expect. JavaScript, on the other hand, has no primitive concept of mutable vs. immutable.
Variable declaration
In JavaScript, there are a two ways to create a new identifier. The keyword function foo(...) {}
declares a new function. And the var
keyword declares a new variable. Variable declarations do not need initial values: var foo;
means foo
gets the initial value of undefined
. More on this later.
JavaScript will also implicitly create new variables if the code assigns to an unknown variable: foo = 1;
. Warning: JavaScript handles this by looking up through the parent (lexical) scopes, until it reaches the top scope (which, in a browser, is window
). If it does find a matching identifier in some parent scope, it overwrites that variable. If it doesn’t find a matching identifier, in any parent scope, it creates a variable with this name on that uppermost scope, and it effectively becomes a global variable. As a Python programmer new to JavaScript, forgetting var
will be the source of many bugs that you write. Especially if you are using short variable names, it’s very easy overwrite important values in parent scopes and collide with other accidental global variables. Always use var
, and when you are seeing a bug, one of the first things you should check is whether you remembered to use var
.
In Python, there are three ways to declare a new identifier. First, there are the def
and class
keywords, which create functions/methods, or classes, respectively. Simple assignment also creates a variable: foo = 1
, and that variable is always local. Python also supports global (and in Python 3, non-local) variables, but these are almost never necessary. Unlike JavaScript, there is no way to define a variable in Python without giving it an initial value. This might seem problematic to a JavaScript programmer who is used to declaring all their variables at the top of a function, but it will be easy to get accustomed to.
More later on scoping rules in JavaScript and Python. First, let’s look at how the languages differ in data types.
Data types
Truthiness
JavaScript has true
and false
. Python has True
and False
. Aside from the capitalization, they are the same.
Strings
JavaScript source code should be encoded as UTF–16, and quoted strings are sequences of unicode characters. There is no built-in support for manipulating raw bytes; in general, this is not necessary as it is handled by the browser (or other host environment).
In Python, source code is ASCII unless you specify a different encoding with a comment. Python supports sequences of bytes as well as sequences of unicode characters, and you must use encode
and decode
methods to convert between them. In Python 2, a bare quoted string is a sequence of bytes, and if you prefix it with a u
you get a unicode string instead. In Python 3, a bare quoted string is a sequence of unicode characters, and if you prefix your string with a b
you get a byte-string instead.
In both languages, there is no difference between single and double quotes, and you escape a quote character inside a string with \
.
Numbers
In JavaScript, there is one numeric type, implemented as a double-precision 64-bit IEEE floating-point number. This means JavaScript has all the problems associated with floating point numbers. This also means JavaScript has the “numbers” +Infinity
, -Infinity
, and NaN
.
Python has several numeric types. It has integers with int
(in Python 2, dividing int
s triggers “floor division” unless you use from __future__ import division
). And it has floating points with float
, which use the same 64-bit IEEE standard as JavaScript does. Python also has the very useful fixed-point Decimal
type, for representing numbers with decimal points without the dangers of floating points. And it has complex
numbers which are really cool but rarely useful. Python does not have any values expressing infinity, and there is no not-a-number value: operations like division by zero raise exceptions (like ZeroDivisionError
).
All the basic mathematical operators are the same in both languages, with the exception of exponentiation, 2**3
in Python is Math.pow(2,3)
in JavaScript. More on Math
later.
Nothingness
JavaScript has two values that convey nothingness: undefined
and null
. Python just has one: None
. Understanding why goes to the heart of differences in the languages.
In JavaScript, you can define a local variable without giving it a value: var foo;
. When you do this, foo
has the value undefined
. Also, when you try to access a property on an object that has not been defined, you get the same undefined
value. On the other hand, null
in JavaScript is used for values that exist and are explicitly set to null or empty. In other words, undefined
is for variables or properties that do not exist or have not yet been assigned a value, and null
represents the intentional absence of any value.
Python defines a new variable as soon as you assign to it, and not before. If you use a variable that doesn’t exist, you get NameError
, and when you try to access an attribute on an object or a value in a dictionary that does not exist, you get AttributeError
or KeyError
. Because Python has no way to declare a variable without giving it a value, and because it uses exceptions for cases where a variable, attribute, or dictionary key is not present, it has no need for anything like JavaScript’s undefined
. It only needs None
, which roughly corresponds to JavaScript’s null
.
Arrays vs. list/tuple
JavaScript has a built-in Array
type. Square brackets are syntactic sugar for creating Array
s: ['one', 2, 'six']
.
Python has two similar data types, list
and tuple
. list
s are created with the same square bracket syntactic sugar as JavaScript. They are intended to contain arbitrarily long sequences of similar items, and they are mutable. tuples
are created with a bare comma, ‘,’, with the exception of the empty tuple, which is created with ()
. tuple
s are meant to be more like vectors, containing short sequences of possibly different kinds of items, or positionally relevant values. tuple
s are immutable.
Since JavaScript has no mutable/immutable distinction, there is no JavaScript type corresponding to Python’s tuple
. Python’s list
and JavaScript’s Array
are quite similar. Some of the more common operations have slightly different names. JavaScript cribbed from Perl here, so for fun the Perl analogues are included too.
JavaScript | Python | Perl |
---|---|---|
a.length | len(l) | $#a (don’t ask) |
a.push(item) | l.append(item) | push(@a.push, $item) |
a.pop() | l.pop() | pop(@a) |
a.shift() | l.pop(0) | shift(@a) |
a.unshift(item) | l.insert(0, item) | unshift(@a, $item) |
a.slice(start, end) | l[start:end] | splice(@a, start, howMany) |
a.splice(start, howMany, […]) | l[start:end] = […] | splice(@a, start, howMany, […]) |
In the Python analogs for JavaScript’s slice
and splice
, you see a glimpse of Python’s extremely powerful slice operator.
Objects vs. dict/set
JavaScript has no built-in hash-table support. Curly brackets in JavaScript are syntactic sugar for creating a new object. JavaScript code that builds objects with curly brackets looks very similar to Python dictionaries, but what’s going on behind the scenes is completely different. We’ll get to objects in JavaScript later on.
Python has built-in hash-tables, called dict
s. Curly brackets and colons together are syntactic sugar for creating a new dictionary: {"key": value, "otherkey": othervalue}
. Keys in dict
s must be “hashable,” and all immutable types are hashable, so dictionary keys can be integers, strings, unicode, floats, and many other things besides.
Python also has a built-in set
type. You can think of a set as a hash with only keys and no values. A key is either in the set or not. set
s can be created with similar syntactic sugar, just by listing the elements inside curly brackets: {1, "two", 3.0}
.
We see here a glimpse of how Python leverages the mutable/immutable distinction: assume you could define a list, use that list as a key in a hash, and then modify the list in place. What would happen if you accessed the value with that list as the key? Do you get a KeyError
because the list is now different? Or do you get the same value back even though you are providing a different key? Python avoids this problem entirely by not allowing the mutable dict
, list
and set
types as keys in dicts or as members of a set.
Python’s set
type is extremely useful, not least because it supports various set-theoretic operations like union, intersection, difference, and symmetric difference.
Type Coercion
JavaScript is much more promiscuous than Python when you mix types in an operation. It will happily try to convert strings, numbers, true
, false
, null
, undefined
, and yes, even arrays and objects, when, for example, adding them together, or passing them to Math.min
and friends. I’m not sure if it’s possible to ever get an error from JavaScript when combining un-like types, but at the very least it’s very rare.
This is the source of many of the really funny snippets on wtfjs, as objects and lists turn into strings and numbers in unexpected ways.
This means that passing a variable like [0]
or {v:0}
into JavaScript code which expects something like 0
will sometimes quietly coerce that value into a number or string. Assigning the wrong type to a variable may not cause an error at all, or may fail much later in unexpected ways, or may just produce strange output.
Python is much more conservative when mixing types in operations. It will try to coerce between numeric values of different types, and even provides the coerce()
builtin for that. And Python 2 will try to convert string values to unicode when combining them with unicode values, and vice versa (although if this is happening you’re going to see bugs once you start handling non-ASCII data, and this coercion is widely considered a design flaw in Python 2). There is no type coercion for Decimal
, list
, tuple
, dict
, or set
types.
Syntax
JavaScript and Python share a lot of syntax in common. But there are some important differences.
Code Blocks
JavaScript uses curly brackets to denote code blocks. Python uses indentation. Get over it.
JavaScript | Python |
---|---|
|
|
Statement Terminators
JavaScript uses semicolons ;
to terminate statements. Python uses newlines. Get over it.
JavaScript interpreters perform something called automatic semicolon insertion when they encounter syntax errors near newlines without semicolons. This means that omitting semicolons won’t always cause broken code, but, since the automatic semicolon insertion isn’t being done by a human who understands the code, omitting semicolons could conceivably cause the interpreter to change your code in strange ways. Remember your semicolons.
Python will silently ignore semicolons at the end of lines, and allows multiple statements on a single line, separated by semicolons. But using semicolons in Python is considered poor practice.
Assignment
In JavaScript, as in many other languages (like C/C++), a variable assignment is also an expression that returns the value being assigned. This means, in JavaScript, expressions like this are valid: foo = (bar = baz) * 2;
That’s doing two things: first, it’s assigning the value of baz
to the variable bar
; then it takes the result of the inner assignment, multiplies it by two, and assigns the result to foo
.
One of the early insights in Python’s design was that other languages (like C/C++) often suffered from bugs stemming from programmers confusing a test for equality using ==
and an assignment using =
. So variable assignment in Python is a statement, which means it cannot be used as part of an expression, and therefore it’s impossible to write code that confuses =
for ==
.
Function Declarations
In JavaScript, function declarations are also expressions. Functions can also be anonymous; the function name can be omitted. This allows a few interesting uses that Python does not have. Functions can be defined and then assigned to a variable:
var foo = function (...) {
// some stuff
};
This is equivalent to the more traditional style:
function foo(...) {
// some stuff
}
Note that only the first function declaration needs a semicolon at the end, because while a function declaration itself is a statement, a variable assigment expression needs to be terminated with a semicolon to become a statement.
Ad-hoc functions can also be defined and passed as arguments to another function. This is a common pattern for declaring callbacks:
do_something().add_callback(function (args) {
// some stuff
});
And finally, an anonymous function can be created and called immediately, creating a closure and preventing leakage into parent namespaces:
(function (..) {
// do stuff
})();
None of this is possible in Python. Functions in Python cannot be anonymous, and function declarations are not expressions, so they cannot be defined and used on the same line. Working with closures and callbacks is slightly more unwieldy in Python, but there are tools (monocle, Twisted, Tulip) and other patterns (coroutines with yield
) that are good ways to achieve the same patterns in Python.
Update 30-July-2014: lambdas are not functions
Several people have emailed me, claiming that Python does, in fact, have anonymous functions, via Python’s lambda
. A lambda is a way of taking an expression, pulling one or more variables out of that expression, and returning something that is call-able, like a function, which takes those variables like arguments. For example, in the example below, a
and b
are pulled out of the expression foo(2*a + b)
, and you can then call the lambda multiple times with different arguments and get different results.
doit = lambda a, b: math.sqrt(2*a + b)
doit(1,2) # 2.0
doit(2,5) # 3.0
doit(5,6) # 4.0
But it is wrong to think of lambdas as functions: they cannot contain statements, only expressions; they do not create their own scope; they cannot raise or catch exceptions, have if blocks or loops, they cannot have multiple return points, the list goes on. All of this is possible in JavaScript functions, anonymous or named.
Function Arguments
JavaScript functions do not care whether they are called with the arguments they are expecting or not. Any missing arguments get the value undefined
, and any extra arguments end up in the special arguments
object. The arguments
object is an Array
-like object that is available locally within each function. You can access arguments by position and ask for the number of arguments with arguments.length
. Implementing a variable number of arguments or optional arguments is possible in JavaScript via the arguments
object.
It’s important to remember that arguments
is not a real JavaScript Array
—it does not have all of the array methods, such as pop
.
Python, on the other hand, will raise an exception if a function is called with the wrong number of parameters. And Python supports some additional parameter passing syntax. A function can accept optional key-word parameters by supplying default values:
def foo(arg, use_thing=True, default_width=1):
# some stuff
A function can also accept an arbitrary number of positional parameters by prefixing an iterable parameter (a list or a tuple) with an asterisk *
:
def foo(*args):
# args is a tuple
And a function can accept an arbitrary number of key-word parameters by prefixing a dict parameter with two asterisks **
:
def foo(**kwargs):
# kwargs is a dictionary
The details of how keyword parameters and arbitrary numbers of parameters are interpreted when used together is changing in Python 3.
The same patterns and flexibility can ultimately be achieved with JavaScript’s arguments
or with Python’s key-word parameters and *
and **
operators.
with Statements
Both languages have a with
statement. They are completely different.
JavaScript’s with
modifies the current scope for the following block. It’s a shortcut, allowing you to leave off a long object name when accessing properties of that object:
|
|
Python’s with
starts something called a “context manager”. It allows you to ensure that clean-up code is always run, regardless of any errors that might occur:
|
|
Decorators
A decorator is a function that takes another function, or a class, as its argument, and returns a modified function or class.
def decorate(func):
def decorated(*a, **kw):
# Do something right before every call to func
return func(*a, **kw)
# Do something right after every call to func
return decorated
def foo(*a, **kw):
# do something
foo = decorate(foo)
Python has syntactic sugar to call decorators in-line, just prefix the decorator with an @
and put it above the def
:
def decorate(func):
def decorated(*a, **kw):
# Do something right before every call to func
return func(*a, **kw)
# Do something right after every call to func
return decorated
@decorate
def foo(*a, **kw):
# do something
When creating decorators in Python, remember to use functools.wraps to preserve the function name.
Class decorators are similar; they take a class and return a modified class.
List Comprehensions
Python has syntactic sugar for list comprehensions, and JavaScript is introducing a very similar syntax in JavaScript 1.7.
Iterators & Generators
Python has support for generator functions with the yield
keyword, and JavaScript is introducing a very similar yield
keyword in JavaScript 1.7.
Scope
JavaScript and Python both use lexical scope, but there are some subtle differences.
JavaScript has one way to create a new scope; a function call. Recall that there are two ways to create new identifiers in JavaScript: var
and function
. Variables defined inside that function with var
, and functions defined inside that function with function
, are only available within that scope, and to child scopes created inside that scope. Note that different .js
files do not get their own scopes by default. This is why most JavaScript libraries are wrapped in an anonymous function that is called as soon as it is defined, it protects the contents of the library from interference by other .js
files:
/* Fancy JavaScript library that fixes all Internet Explorer 6 bugs */
(function () {
// module contents
})();
Python has three ways to create a new namespace; functions, classes, and modules. Modules are basically .py
files. And recall there are three ways to create new identifiers in Python: variable assignment, plus class
and function
declarations. All three kinds of identifiers are only available in the namespace they are defined in, and in child namespaces.
Identifiers in other Python modules can be imported into the current namespace with the import
keyword. And variables in child modules, classes, and objects can be accessed with dot notation. More on that in a moment.
Variable Hoisting
JavaScript interpreters do something called variable hoisting. Roughly, this means variables can be defined anywhere in your code, and the interpreter automatically “hoists” their initial declaration to the top of the current scope, but leaves the actual value assignment where it is. For a Python programmer, this can lead to some very unexpected behavior. An example might be more useful. The following two snippets of JavaScript are functionally identical.
|
|
Recall that a variable declaration assigns the value undefined
if no value is supplied. When called, both f
s generate the same two lines in the console:
undefined
1
Defining all variables at the top of a JavaScript function is a good way to remember that the JavaScript interpreter is basically modifying the code in this way when it runs.
In Python, there is no variable hoisting. An identifier does not exist until the interpreter reaches the line of code where it is defined. A corresponding Python version of the first example above would not work at all; the interpreter would raise a NameError
when it reached the first use of a
, before a
was defined.
Objects and Inheritance
The difference surrounding objects and inheritance in JavaScript and Python is probably the biggest difference, and the most difficult to understand. On a very-high level, Python uses what is often called “classical” inheritance, and JavaScript uses “prototypical” inheritance. In Python’s classical inheritance, there are two basic concepts, a “class” and an “instance”. In JavaScript’s prototypical inheritance, there’s only one basic concept, that of an “object”.
In Python, a class generally contains a constructor, named __init__
, and a collection of methods. When you call a class, a new instance of that class is created; you generally pass some initial data when instantiating that class, and the constructor adds that data to the newly created instance. From then on, the methods on the class can be used to perform operations on the data in the instance.
class Frob(object):
def __init__(self, args):
self.args = args
def frobulate(self):
# do something to self.args
f = Frob(data)
f.frobulate()
In JavaScript, there’s no class keyword. Instead, any function can serve as a constructor, by putting new
in front of the function call. Methods can be assigned to the object’s prototype by accessing the .prototype
property of the constructor, and then they will be available to every object created by this constructor.
function Frob(args) {
this.args = args;
}
Frob.prototype.frobulate = function () {
// do something to this.args
};
f = new Frob(data);
f.frobulate();
We saw already that JavaScript is really permissive about function calls with the wrong number of arguments, and about operations on dissimilar types. That same permissibility is present here too. If you leave off the new
when calling a constructor, JavaScript will happily call the function anyway, and any modifications to this
will get performed on a different this
than you were expecting. This is another way that Python programmers new to JavaScript can get tripped up; it’s easy to forget new
when calling a constructor.
JavaScript will also let you just call a method directly from the constructor’s prototype, and again the code will get executed with a different this
than expected. Python doesn’t allow this sort of flexibility. In the example above, calling the instance method frobulate
directly on the class Frob
raises a TypeError
.
this versus self
In the examples above, Python has a self
argument as the first argument of each method, representing the instance. JavaScript, on the other hand, accesses the object using this
.
This looks like a simple naming difference, but it is actually fundamental. In Python, self
is a variable name; each method receives the current instance as the first parameter when it is called. You could actually name it anything you want, but self
is the name that’s normally used.
In JavaScript, this
is not a variable, it is a keyword, which gives you the object on which a method was called. Usually this object is whatever preceeded the .
when calling the method, although there are other ways to change the value of this
, such as apply
and call
.
Methods versus functions
This brings us to another difference between JavaScript and Python. In JavaScript, since this
is a keyword, merely attaching a function to an object and calling it there effectively turns that function into a method:
f = new Frob();
f.frobulate = function () {
console.log(this == f); // true
};
f.frobulate();
Python doesn’t allow this; methods and functions are actually different types, so attaching a function to an existing instance has no effect on the arguments that function receives when it’s called; it doesn’t magically become a method, it’s still just the same old function.
class Frob(object):
pass
def frobulate(*a):
print a
f = Frob()
f.frobulate = frobulate
f.frobulate() # prints ()
Inheritance
In JavaScript, objects inherit from other objects. This is done by setting a constructor function’s prototype property to a base object. This means the derived object inherits both methods and data defined on the base object.
function BaseFrob() {
// ...
}
function DerivedFrob() {
// ...
}
DerivedFrob.prototype = new BaseFrob();
In Python, it’s the classes that inherit from each other, and this is done by specifying the base class or classes when defining the derived class.
class BaseFrob(object):
pass
class DerivedFrob(BaseFrob):
pass
Unlike JavaScript, there is no way to inherit from instances in Python. And it’s not necessary.
All the previous examples show Python classes inheriting from object
; if you are working in Python 2, this is necessary. If you leave out object
and define a class without any base class, you’ll get legacy behavior from Python 2.2. Don’t do that.
In JavaScript, a constructor can only ever have one prototype, therefore JavaScript doesn’t support multiple inheritance.
Python, on the other hand, supports multiple inheritance, by allowing you to specify more than one base class in the class definition. When you call a method that’s not defined on the derived class, Python searches the base classes for a method with that name. The exact technique it uses is quite subtle, but in actual practice, you can just think of it as searching the base classes from left to right.
call, apply and calling base methods
Recall that this
in JavaScript is a keyword which returns the object upon which a method was called. Normally, this object is whatever preceded the .
between the object and its method. But there are two methods attached to every function which can also change the value of this
when calling the function, call
and apply
. They both take the object to call the function on as a first argument. For call
, the remaining arguments are passed to the function as normal arguments, and apply
expects an array of arguments to use as the function arguments.
base_frob = new Frob();
derived_frob = new Frob();
derived_frob.prototype = base_frob;
base_frob.frobulate.call(derived_frob, arg, arg, arg)
base_frob.frobulate.apply(derived_frob, [arg, arg, arg])
Python provides a different way to bypass a method and use a base-class’s method instead: you just call the base method directly, and pass in the derived class as the first argument. Inside the function call, that derived class gets passed in for self
.
class DerivedFrob(BaseFrob):
def method(self, args):
pass
derived_frob = DerivedFrob()
BaseFrob.method(derived_frob, args)
Properties and Attributes
Many languages allow you to define an element on an object which appears to access a single piece of data on that object, but actually masks a function call or another more complex data access pattern. JavaScript and Python both support this.
JavaScript objects have properties, which can themselves be composed of underlying attributes. Python classes and instances have attributes, which can actually be implemented as properties. The concepts are similar, it’s just that the names are switched around.
JavaScript lets you define a property with Object.defineProperty
. The first argument is the object to define the property on, the second argument is the name of the property, and the third is a descriptor, whose attributes allow you to define whether the property is configurable, writable, enumerable, and allow you to define getter and setter functions or pass through to an underlying value on the object.
Python, on the other hand, lets you define an attribute using the descriptor protocol, where you can define getter, setter, deleter, and documentation functions. Or you can use the helpful @property
decorator shorthand, which is enough for most cases.
Modules
JavaScript comes with very few modules, just Math
, Date
, RegExp
, and JSON
. It may also have other functionality available through the host environment: the web browser, node.js, or some other environment.
Python, on the other hand, calls itself a “Batteries Included” language, and comes standard with a wide range of modules.
Conclusion
We’ve come to the end of our tour of differences between JavaScript and Python. Hopefully you’ve learned something new about one or both of them.
There are many things the languages share; they are both interpreted, lexically-scoped, and garbage-collected. Both have a mix of imperative, functional, and object-oriented paradigms. This article focuses on the differences, and most importantly on the differences that will affect everyday users who know one language well and are wondering if the other language works the same. I also tried to stay away from any value judgements between the languages; there are things I prefer about each, but in the end, they both get the job done. And most of the time one programmer’s beautiful syntactic sugar is another programmers’s pet peeve, so value judgements really only matter if you’re writing your own language.
Hopefully you have a little bit better understanding of one, or both, of these languages. Both are very elegant, powerful languages, and both are here to stay. Happy hacking!
P.S. The only other language I know even half as well as these two is Perl, which should give you an idea of how prehistoric a programmer dinosaur I am. That’s why I didn’t include Perl/Ruby/PHP/lisp/Scala/Clojure/Groovy/Go/Erlang/ObjectiveC#++/insert-your-favorite-language-here in this comparison. If you want to see a comparison with your favorite language, you will have to write it yourself.