[CS61A]Lecture #8:Design and Exceptions

仅用作个人学习记录
Reference:https://inst.eecs.berkeley.edu/~cs61a
http://composingprograms.com/pages/33-exceptions.html

汉诺塔问题

起初,所有的圆盘都在第一柱,目标是将所有的圆盘移到第三柱。

每次只能移动最上面的圆盘,圆盘必须移到空闲柱或当前顶部圆盘大于移动盘的柱子。

在这里插入图片描述

移动策略

  • 当只有一个圆盘需要移动,直接移到第三柱即可。
  • 当有 N 个圆盘(N > 1)需要移动:
    • 先将上面的 N - 1 个圆盘移到空闲柱;
    • 再将底部最大的圆盘移到第三柱;
    • 最后将剩余的 N - 1 个圆盘移到第三柱。

在这里插入图片描述

上述策略几乎可以直接转化为递归函数。

def move_tower(n, start_peg, end_peg):
    """Perform moves that transfer an ordered tower of N>0 disks in the
    Towers of Hanoi puzzle from peg START PEG to peg END PEG, where
    1 <= START PEG, END PEG <= 3, and START PEG != END PEG. Assumes
    the disks to be moved are all smaller than those on the other pegs."""
    
    if n == 1:
   		move_disk(start_peg, end_peg)
    else:
        spare_peg = 6 - start_peg - end_peg
        move_tower(n - 1, start_peg, spare_peg)
        move_disk(start_peg, end_peg)
        move_tower(n - 1, spare_peg, end_peg)

异常

异常是编程语言中内置的一种机制,用来定义和解决一些异常的情况。

例如,提供给函数的参数不符合先决条件,如给move_tower提供的 n 小于 0,这是我们不希望看到的。

对异常的操作包括终止计算的控制语句,并允许程序员采取纠正措施。

raise

为了表示一个异常,程序会抛出一个异常(raises an exception),在 Python 中,这意味着创建一个异常值并对其应用 raise 语句。

raise <expression>
if N <= 0:
	raise ValueError("Number of disks must be positive")

raise 之后的表达式创建了一种异常值(ValueError 类型通常用于指示不正确的值。)

>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
    
>>> raise ValueError('sss')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: sss
    
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

>>> raise AssertionError
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

raise 与 assert: assert 在没有给出真值时,会执行 raise。assert 就像 raise 的外包装。用 assert 检查内部的编程逻辑,用异常处理输入。

try

>>> def f();
  File "<stdin>", line 1
    def f();
           ^
SyntaxError: invalid syntax
>>> def f():
...     g()
...     print('after call g')
>>> def g():
...     raise ValueError
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
  File "<stdin>", line 2, in g
ValueError

注意到,进入 g 函数后程序抛出了一个异常,g 结束返回 f 导致 f 也直接终止,print 语句没有执行。无论异常出现在哪里,它会不断向上传递直到顶部。

但是,我们大多情况下不希望这样。当预计可能会发生异常并且有比终止程序更有用的响应(告知用户、处理异常)时,可以使用 try 语句捕获引发的异常。

try:
    <try suite>
except <exception class> as <name>:
    <except suite>
...

<try suite> 始终在执行 try 语句时立即执行。 except 子句组仅在执行 <try suite> 过程中出现异常时执行。每个 except 子句指定要处理的特定异常类。例如,如果 <exception class> 是 AssertionError,那么在执行 <try suite> 过程中引发的任何继承自 AssertionError 的类的实例都将由以下 <except suite> 处理。在 <except suite> 中,标识符 <name> 绑定到引发的异常对象,但此绑定不会在 <except suite> 之外持续存在。except 后要是没有异常类,则捕获所有类型的异常。

例如,我们可以使用 try 语句处理 ZeroDivisionError 异常,该语句在引发异常时将名称 x 绑定到 0。

>>> try:
        x = 1/0
    except ZeroDivisionError as e:
        print('handling a', type(e))
        x = 0
handling a <class 'ZeroDivisionError'>
>>> x
0

当异常产生时,控制流会直接跳到最近的try语句的能够处理该异常类型的<except suite>的主体中。一旦异常被捕获了,就不会在向上传递了。

>>> def invert(x):
        result = 1/x  # Raises a ZeroDivisionError if x is 0
        print('Never printed if x is 0')
        print(result)
>>> def invert_safe(x):
        try:
            invert(x)
        except ZeroDivisionError as e:
            print(e)
>>> invert_safe(2)
Never printed if x is 0
0.5
>>> invert_safe(0)
division by zero
>>> try:
        invert_safe(0)
    except ZeroDivisionError:
        print('more exteral exception')
division by zero

Exercise: Removing Digits

问题:定义一个函数,从给定数字中删除特定数字 (0–9),并返回。

def remove_digit(n, digit):
    """Assuming N>=0, 0 <= DIGIT <= 9, return a number whose
    base-10 representation is the same as N, but with all instances of
    DIGIT removed.  If all digits removed, return 0.
    >>> remove_digit(123, 3)
    12
    >>> remove_digit(1234, 5)
    1234
    >>> remove_digit(1234, 1)
    234
    >>> remove_digit(111111, 1)
    0
    """
    if n == 0:
        return 0
    if n % 10 == digit:
        return remove_digit(n // 10, digit)
    return n % 10 + remove_digit(n // 10, digit) * 10
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值