Why Python programmers might want to look at Elixir (despite the Rubyish syntax that will probably initially repulse them)

Concurrency

Macros

Elixir has built-in support for transforming code at compile time using macros. Here is a dead-simple macro that transforms a filename string into the contents of that file:

defmacro content(filename) do
  File.read!(filename)
end

This ensures that the file is included in the compiled BEAM code, so that it does not need to be shipped along with the application.

Protocols

Elixir, like Clojure, supports protocols, which allow you to define a protocol and then implement it for multiple types. When calling a function on a protocol, Elixir dispatches to the correct implementation based on the type. You can also implement an existing protocol like Enumerable on your own data types.

Protocols may look similar to Python's double-underscore methods like __iter__, but these methods in Python are reserved for the language itself. Because these methods are not namespaced, when a library invents its own double-underscore method, it risks conflicting with another library that has a different idea about what the method should do. It is also impossible to add a new __method__ to built-in objects like str.

Atoms

Atoms ("symbols" in Ruby, "keywords" in Clojure) are very useful as ad-hoc symbols. In Python, I've often had to use strings, unique integers, or object() to achieve the same ends, all of which are worse than atoms: integers and object() don't repr to something reasonable, and symbols should not look like strings or support string operations.

Structs

Elixir has structs, and they work properly: unlike namedtuple, different types with the same values are unequal. They can have default values and required keys.

Immutable data structures

Elixir, like Clojure, has immutable maps and sets based on hash array mapped tries. You can share them without worrying about mutation, or keep many similar versions around with less copying and wastage of memory.

Language syntax

Elixir has some weird-looking syntax that is easy to get fixated on: do and end everywhere, \\ for default arguments, and fun.() for calling anonymous function fun. But there are other things that may be immediately appealing:

Standard library

ExUnit / mix test

Hiding your precious codes

If you ship your code in closed-source desktop software or onto untrusted cloud servers, in some cases you may want to increase the effort required to decompile and reverse-engineer your software. Python 2 and 3 bytecode is relatively easy to decompile, using existing tools, into source code that looks similar to the original code. BEAM code (compiled without debug_info) should be much harder to turn back into source code, and there seem to be no publicly-available tools to do so. This is not a complete roadblock to reverse-engineering because the virtual machine can be debugged, and because the area of interest may be small enough that more tedious reverse-engineering still makes economic sense.

Elixir compiles projects with debug_info by default, so projects that do not want it need elixirc_options: [debug_info: false] in mix.exs.)