大家好,日拱一卒,我是梁唐。本文始发于公众号:Coder梁

我们今天继续来肝伯克利CS61A,这一次的内容是作业6和作业7。和之前的作业相比,这次的题量少了很多,所以把它们放在了一起。题目不难,算是休闲Git场吧。

课程视频

原作业说明

Github

Next Fi测试你适合学心理学吗bonaccigithub是什么 Object

测试抑郁症Fib类中实现next函数,vagithub官网lue属性是斐波那契数列的值。

next方法返回一个Fib的实例,这个实例中的值是斐波那契数列下一个值。next函数的复杂度必须是常数。

提示:可以在next函数当中赋值valueprevious

我们先来gitee看一下它给的样例:

    >>> start = Fib()
    >>> start
    0
    >>> start.next()
    1
    >>> start.next().next()
    1
    >>> start.next().next().next()
    2
    >>> start.next().next().next().next()
    3
    >>> start.next().next().next().next().next()
    5
    >>> start.next().next().next().next().next().next()
    8
    >>> start.next().next().next().next().next().next() # Ensure start isn't changed
    8

也就是说调用next之后返回的还是一个同样的对象,只不过这个对象当中的值不同。

斐波那契数列本身并不复杂,无论是通过迭代计算还是通过递归实现,都很简单。棘手的点通过函数返回实例的形式比较新颖,我们之前没见过。

再来看一下给我们提供的框架代码:

class Fib():
    """A Fibonacci number.
    """
    def __init__(self, value=0):
        self.value = value
    def next(self):
        "*** YOUR CODE HERE ***"
    def __repr__(self):
        return str(self.value)

我们可github汤姆以看到,在Fib这个定义当中,目前只有value这个属性,根本没有previous属性,显然这个属性需测试抑郁症的20道题要我们自己加。但老师又不让我们修改构造函数,所以就只能加在next函数里了。

不考虑边界情况的话,代码应该是这样的:

def next(self):
    ret = Fib(self.value + self.previous)
    self.previous = self.value
    return ret

这个思路是OK的,但实现肯定是错的,因为self.previous并没有定义。进一步思考可以测试抑郁症发现,self.previous测试仪赖上一次迭代,我们只空间复杂度需要把第一次迭代特殊处理,就可以解决这个问题。

所以最后的代码为:

class Fib():
    """A Fibonacci number.
    """
    def __init__(self, value=0):
        self.value = value
    def next(self):
        "*** YOUR CODE HERE ***"
        if self.value == 0:
            ret = Fib(1)
        else:
            ret = Fib(self.previous + self.value)
        self.previous = self.value
        return ret
    def __repr__(self):
        return str(self.value)

Vending Machine

创建一个自动贩卖机的类,可以模拟自动贩卖机的功github中文官网网页能。注意自动贩卖机会返回一个字符串,描述当前的情况。

我们可以来看下测试样例:

>>> v = VendingMachine('candy', 10)
>>> v.vend()
'Machine is out of stock.'
>>> v.deposit(15)
'Machine is out of stock. Here is your $15.'
>>> v.restock(2)
'Current candy stock: 2'
>>> v.vend()
'You must deposit $10 more.'
>>> v.deposit(7)
'Current balance: $7'
>>> v.vend()
'You must deposit $3 more.'
>>> v.deposit(5)
'Current balance: $12'
>>> v.vend()
'Here is your candy and $2 change.'
>>> v.deposit(10)
'Current balance: $10'
>>> v.vend()
'Here is your candy.'
>>> v.deposit(15)
'Machine is out of stock. Here is your $15.'
>>> w = VendingMachine('soda', 2)
>>> w.restock(3)
'Current soda stock: 3'
>>> w.restock(3)
'Current soda stock: 6'
>>> w.deposit(2)
'Current balance: $2'
>>> w.vend()
'Here is your soda.'

观察样例,可以发现一个点:

当贩卖机没有库存时,除了restock操作都会返回没有库存的提示,并且充值的话还会提示钱被返还。

除了这个特殊的点之外,其余就是一个简单的贩卖机的模拟。如果前面的作业都搞定了,到这里基本上可以说是小菜一碟了。

class VendingMachine:
    """A vending machine that vends some product for some price.
    """
    "*** YOUR CODE HERE ***"
    def __init__(self, item, price):
        self.item = item
        self.price = price
        self.stock = 0
        self.balance = 0
    def restock(self, amount):
        self.stock += amount
        return 'Current {} stock: {}'.format(self.item, self.stock)
    def deposit(self, amount):
        if self.stock == 0:
            return 'Machine is out of stock. Here is your ${}.'.format(amount)
        self.balance += amount
        return 'Current balance: ${}'.format(self.balance)
    def vend(self):
        if self.stock == 0:
            return 'Machine is out of stock.'
        if self.balance < self.price:
            return 'You must deposit ${} more.'.format(self.price - self.balance)
        else:
            ret = 'Here is your {}{}'.format(self.item, '.' if self.balance == self.price else ' and ${} change.'.format(self.balance - self.price))
            self.balance = 0
            self.stock -= 1
            return ret

Digits

实现digits类,能够以链表的形式展示n

我们来看这两个样例:

    >>> digits(0) is Link.empty
    True
    >>> digits(543)
    Link(5, Link(4, Link(3)))

这里的Link实现的是链表的功能,链表的定义在课程当中曾经讲过。没有看过视频也没有关系,作业当中给出了完整的代码:

class Link:
    """A linked list.
    >>> s = Link(1)
    >>> s.first
    1
    >>> s.rest is Link.empty
    True
    >>> s = Link(2, Link(3, Link(4)))
    >>> s.second
    3
    >>> s.first = 5
    >>> s.second = 6
    >>> s.rest.rest = Link.empty
    >>> s                                    # Displays the contents of repr(s)
    Link(5, Link(6))
    >>> s.rest = Link(7, Link(Link(8, Link(9))))
    >>> s
    Link(5, Link(7, Link(Link(8, Link(9)))))
    >>> print(s)                             # Prints str(s)
    <5 7 <8 9>>
    """
    empty = ()
    def __init__(self, first, rest=empty):
        assert rest is Link.empty or isinstance(rest, Link)
        self.first = first
        self.rest = rest
    @property
    def second(self):
        return self.rest.first
    @second.setter
    def second(self, value):
        self.rest.first = value
    def __repr__(self):
        if self.rest is not Link.empty:
            rest_repr = ', ' + repr(self.rest)
        else:
            rest_repr = ''
        return 'Link(' + repr(self.first) + rest_repr + ')'
    def __str__(self):
        string = '<'
        while self.rest is not Link.empty:
            string += str(self.first) + ' '
            self = self.rest
        return string + str(self.first) + '>'

只要读懂了Linkgithub永久回家地址的使用方法,代码并环路复杂度不难写,只是一个简单的迭代:

def digits(n):
    """Return the digits of n as a linked list.
    >>> digits(0) is Link.empty
    True
    >>> digits(543)
    Link(5, Link(4, Link(3)))
    """
    s = Link.empty
    while n > 0:
        n, last = n // 10, n % 10
        "*** YOUR CODE HERE ***"
        s = Link(last, s)
    return s

Miss Manners

创建一个类叫做MissManners,它能够提升我们对象的礼貌程度。

MissManners对象的构造函数接受另外一个对象object,它有一个github中文社区函数,叫做ask。通github开放私库ask函数可以调用object中的方法,但前提是必须在调用之前用上please表示礼貌。

我们还链表数据结构可以将多个MissManners对象合成在一起,这样的话我们必须要加上多个please才能调用到底层的对象。具体可以参考样例。

提示

使用getattr函数和hasattr函数来以字符串的形式获取对象中的函数,你可以上网搜索相关的样例

在你的实现算法复杂度当中,需要用到*args,它表示接收任意多个参数,我们在之前的作业当中曾经用过

我们可以先来看一下样例:

>>> v = VendingMachine('teaspoon', 10)
>>> v.restock(2)
'Current teaspoon stock: 2'
>>> m = MissManners(v)
>>> m.ask('vend')
'You must learn to say please first.'
>>> m.ask('please vend')
'You must deposit $10 more.'
>>> m.ask('please deposit', 20)
'Current balance: $20'
>>> m.ask('now will you vend?')
'You must learn to say please first.'
>>> m.ask('please hand over a teaspoon')
'Thanks for asking, but I know not how to hand over a teaspoon.'
>>> m.ask('please vend')
'Here is your teaspoon and $10 change.'
>>> double_fussy = MissManners(m) # Composed MissManners objects
>>> double_fussy.ask('deposit', 10)
'You must learn to say please first.'
>>> double_fussy.ask('please deposit', 10)
'Thanks for asking, but I know not how to deposit.'
>>> double_fussy.ask('please please deposit', 10)
'Thanks for asking, but I know not how to please deposit.'
>>> double_fussy.ask('please ask', 'please deposit', 10)
'Current balance: $10'

其实整个的逻辑并不复杂,我们在创建MissManners时需要传入一个对象。之后我们通过字符串的形式调用对象,但必须要加上敬语please

所以我们可github中文社区以先来判断字符串的开头是否包含ple测试仪ase,如果不包含,直接返回。如果包含,解析出please之后的内容github中文官网网页,它就是我们要调用的object中的函数名。可以通过hasattr函数来判github开放私库object中是否有这个函github汤姆数,如果存在,即返回调用结果,否则返环路复杂度回提示语。

VendingMachine类也在之前的作业当中出现过,如果不清楚原理,下面也给出了完整代码。

class VendingMachine:
    """A vending machine that vends some product for some price.
    """
    def __init__(self, product, price):
        self.product = product
        self.price = price
        self.stock = 0
        self.balance = 0
    def restock(self, n):
        self.stock += n
        return 'Current {0} stock: {1}'.format(self.product, self.stock)
    def deposit(self, n):
        if self.stock == 0:
            return 'Machine is out of stock. Here is your ${0}.'.format(n)
        self.balance += n
        return 'Current balance: ${0}'.format(self.balance)
    def vend(self):
        if self.stock == 0:
            return 'Machine is out of stock.'
        difference = self.price - self.balance
        if difference > 0:
            return 'You must deposit ${0} more.'.format(difference)
        message = 'Here is your {0}'.format(self.product)
        if difference != 0:
            message += ' and ${0} change'.format(-difference)
        self.balance = 0
        self.stock -= 1
        return message + '.'
class MissManners:
    """A container class that only forwards messages that say please.
    """
    def __init__(self, obj):
        self.obj = obj
    def ask(self, message, *args):
        magic_word = 'please '
        if not message.startswith(magic_word):
            return 'You must learn to say please first.'
        "*** YOUR CODE HERE ***"
        left_message = message[len(magic_word):]
        if hasattr(self.obj, left_message):
            return getattr(self.obj, left_message)(*args)
        else:
            return 'Thanks for asking, but I know not how to {}.'.format(left_message)

总体上来说,没有什么难度,就是hasattrgetattr这两个方法的常规用法。

好了,关于这两次作业就先聊到这里,感谢大家的阅读。