大家好,日拱一卒,我是梁唐。本文始发于公众号:Coder梁
我们今天继续来肝伯克利CS61A,这一次的内容是作业6和作业7。和之前的作业相比,这次的题量少了很多,所以把它们放在了一起。题目不难,算是休闲Git场吧。
课程视频
原作业说明
Github
Next Fi测试你适合学心理学吗bonaccigithub是什么 Object
在测试抑郁症Fib
类中实现next
函数,vagithub官网lue
属性是斐波那契数列的值。
next
方法返回一个Fib
的实例,这个实例中的值是斐波那契数列下一个值。next
函数的复杂度必须是常数。
提示:可以在next
函数当中赋值value
和previous
我们先来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) + '>'
只要读懂了Link
类github永久回家地址的使用方法,代码并环路复杂度不难写,只是一个简单的迭代:
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)
总体上来说,没有什么难度,就是hasattr
和getattr
这两个方法的常规用法。
好了,关于这两次作业就先聊到这里,感谢大家的阅读。
评论(0)