One of the basic changes from Python 2 to Python 3 was making print
a function - which, to me, makes perfect sense given its structure. Why aren't the raise
and del
statements also functions? Especially in the case of raise
it seems like it is taking an argument and doing something with it, just like a function does.

- 115,751
- 26
- 228
- 437

- 17,795
- 22
- 77
- 119
2 Answers
raise
and del
are definitely distinct from functions, each for different reasons:
raise
exits the current flow of execution; the normal flow of byte-code interpretation is interrupted and the stack is unwound until the next exception handler is found. Functions can't do this, they create a new stack frame instead.del
can't be a function, because you must specify a specific target; you can't use just any expression, and what is deleted depends on the syntax given; if you use subscription, then deletion takes place for a given element in a container, or a name is removed from the current namespace. The right namespace to delete to is also dependent on the scope of the name deleted. See thedel
statement grammar definition:del_stmt ::= "del" target_list
A function can't remove items from a parent namespace, nor can they distinguish between the result of a subscription expression or a direct reference. You pass objects to the function, but to a
del
statement you pass a name and a context (perhaps by the interpreter when deleting a local or global name).
print
on the other hand, requires no special relationship with the current namespace or stack frame, and needs no special syntax constraints to do it's work. It is purely functionality at the application level. The global sys.stdout
reference can be accessed by functions just as much as by the interpreter. As such it didn't need to be a statement, and by moving it to a function, additional benefits were made available, such as being able to override it's behaviour and to innovate on it quicker across Python releases.
Do note that part of the raise
statement was moved to application-level code instead; in Python 2 you can attach a traceback to the raised exception with:
raise ExceptionClass, exception_value, traceback_object
In Python 3, attaching a traceback to an exception has been moved to the exception itself:
raise Exception("foo occurred").with_traceback(tracebackobj)

- 1,048,767
- 296
- 4,058
- 3,343
https://www.python.org/dev/peps/pep-3105/ has a list of rationals why print
is made function. Of the five reasons, (IMO) the most relevant one is:
print is the only application-level functionality that has a statement dedicated to it.
As explained by Alex Martelli here https://stackoverflow.com/a/1054062:
Python statements are things the Python compiler must be specifically aware of -- they may alter the binding of names, may alter control flow, and/or may need to be entirely removed from the generated bytecode in certain conditions (the latter applies to assert). print was the only exception to this assertion in Python 2; by removing it from the roster of statements, Python 3 removes an exception, makes the general assertion "just hold", and therefore is a more regular language.
del
and raise
obviously alter the binding of names/alter the control flow, thus they both are okay.