Macros #
In Scheme, everything is a list. For example, (quotient 1 2)
can also be seen as a Scheme list with the elements quotient
, 1
, and 2
. What the '
operator lets us do in Scheme is create a list without evaluating certain options, then delay the evaluation until you need it later. For example:
>>> (define lst (list 'quotient 1 2))
lst
>>> lst
(quotient 1 2)
>>> (eval lst)
0.5
>>> (eval (list 'quotient 1 2))
0.5
Quoting #
There are two ways to quote an expression:
- Quoting
- Quasiquoting
Quasiquotes are different because they allow certain elements to be unquoted
using ,
. This means that names can be bound directly:
(define a 2)
(define b 3)
'(+ ,a b) ; (+ (unquote (a)) b)
`(+ ,a b) ; (+ 2 b)
When you call eval
on the quasiquoted expression, it saves the value of a
directly into the macro which can be very powerful.
If you try to call (eval '(+ ,a b))
you will get an error because ,
does not work unless it is in a quasiquote because Scheme.
Exceptions #
Exceptions in Python are used to handle errors. In Python, you most likely would have seen quite a few exceptions (for example ZeroDivisionError
, StopIteration
, etc.) - there is a way to handle these exceptions.
try
…except
#
To handle an exception (which keeps the program running - it doesn’t make the program stop the moment an error appears), you can use Python’s built-in exception handling.
try:
<body>
except <exception> as <variable>:
<body>
[except <exception> as <variable> [...]]
[else]
First, the body in the try
suite is executed first, then if an error is thrown that matches any <exception>
that you put in, the body corresponding to that suite will be run with <variable>
bound to the exception.
Example #
try:
val = 10/0
except ZeroDivisionError as e:
print(f'handling {type(e)}') # handling <class 'ZeroDivisionError'>
val = 0
Example inside a function #
def div(a, b):
try:
result = a / b
except ZeroDivisionError:
result = float('inf')
return result
div(10, 1) # 10
div(10, 0) # inf
div(10, -1) # -10
What Would Python Do? #
Taken from CS61A Fall 2021 Exceptions slides:
def invert(x):
inverse = 1/x # Raises a ZeroDivisionError if x is 0
print('Never printed if x is 0')
return inverse
def invert_safe(x):
try:
return invert(x)
except ZeroDivisionError as e:
print('ben')
return 0
invert_safe(1/0) # Error
try:
invert_safe(0)
except ZeroDivisionError as e:
print('tao')
# ben
# this is because the place where the error occurs is in the try except block where 'ben' is printed
Raising Exceptions #
Assert Statements #
assert
statements that fail raise an exception of type AssertionError
Raise Statement #
You can raise any type of exception by using the raise
statement:
raise <expression>
<exception>
must evaluate to a subclass of BaseException
(or an instance of one). Exceptions are constructed in the same way as do other classes:
raise ZeroDivisionError("lol wtf u doing")