3

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.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
DilithiumMatrix
  • 17,795
  • 22
  • 77
  • 119

2 Answers2

5

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 the del 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)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

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.

Community
  • 1
  • 1
zw324
  • 26,764
  • 16
  • 85
  • 118