Lua for Python Programmers

Variables and Expressions

Use of undefined variables

In Lua and Python, variables donít have types but values do, and variables can hold values with different types over their lifetime. Both languages allow a variable to be defined when it is assigned to for the first time. Using an undefined variable in Python causes a runtime error whereas undefined variables in Lua contain the value nil.

Testing if a variable is defined

Since in Lua only nil and the boolean value false evaluate to false in a boolean expression, you can use a kind of ternary expression to test if a variable has been defined in Lua. Both Lua and Python use short-circuit evaluation of a boolean expression with the result of the expression being the last expression that needed to be evaluated. Therefore, in Lua, you can determine if a variable is defined by seeing if it evaluates to true or false.

Python does not have a built-in function to test if a variable is defined, but it does have the "in" keyword to test if a value is in a collection. Well guess what: there is a function to get a collection of all current local and global variables.

The following code illustrates how Lua and Python can and canít check for undefined variables:

PythonLua

>>> ('x' in locals() or 'x' in globals()) and 'defined' or 'undef'
'undef'

>>> "name" in x

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

>>> x["name"] = "Andy"

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

>>> x = {}
>>> "name" in x
False
>>> x["name"] = "Andy"
>>> "name" in x
True
>>> 0 or "" or {} or [] or False
False
>>> None or False
False
> = x and "defined" or "undef"
undef
> = x.name and "defined" or "undef"
stdin:1: attempt to index global 'x' (a nil value)
stack traceback:
        stdin:1: in main chunk

> x.name = "Andy"
stdin:1: attempt to index global 'x' (a nil value)
stack traceback:
        stdin:1: in main chunk

> x = {}
> = x.name and "defined" or "undef"
undef
> x.name = "Andy"
> = x.name and "defined" or "undef"
defined
> = 0 and "" and {} and true
true
> = nil or false
false
> x.name = false -- ut oh . . . 
> = x.name and "defined" or "undef"
undef

The first Lua line demonstrates how to test if a variable is defined in Lua. Then, shown in both languages, there is a test if a key exists in a non-existent table. This causes an error in both languages. Another error arises in both languages when both a table and a pair in that table are defined in a single illegal statement. You must create a table before adding keys to it. For the examples in both languages, the table is then created, a test is performed to see if a key exists yet, the key-value pair is created, and the test is performed again. The last lines show the important difference in which values are equivalent to true and false.

Boolean Expressions, Ternary Operator

In case it was confusion when I first explained it, I'll try to explain the evaluation of an expression that contains boolean operators again. Just because an expression contains boolean operators, it does not necessarily evaluate to either true or false. Rather, in both Lua and Python, it is the value of the last sub-expression that needed to be evaluated, keeping in mind that the boolean operators are short-circuiting in both Lua and Python. This means that we can pretend that Lua has a ternary operator and that there is an alternative form of the ternary operator in Python. Also, in both languages, if you really need an expression to become either true or false, you could use the not operator twice before a value. Is that not not a great idea?

Many expressions in Lua are also valid expressions in Python. Those operators which are different in Lua are not oddball; they are arguably just as readable and writable. See for yourself:

PythonLua
>>> 5 + 6 % 7 * 2 ** 3 - 4 / 2
51.0
>>> 1 < 1
False
>>> 2 <= 2
True
>>> 3 == 3
True
>>> 4 != 4
False
>>> 5 > 5
False
>>> 6 >= 6
True
> = 5 + 6 % 7 * 2 ^ 3 - 4 / 2
51
> = 1 < 1
false
> = 2 <= 2
true
> = 3 == 3
true
> = 4 ~= 4
false
> = 5 > 5
false
> = 6 >= 6
true