大家好,日拱一卒,我是梁唐。本文始发于公众号: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
这两个方法的常规用法。
好了,关于这两次作业就先聊到这里,感谢大家的阅读。