题目一:Python类的基本使用(1)
下面的类封装了一组 set/get/keys 接口
# -*- coding: UTF-8 -*-
class KeyValueSet:
def __init__(self) -> None:
self.dict = {}def set(self, key, value):
self.dict[key] = valuedef get(self, key):
return self.dict.get(key)def keys(self):
return self.dict.keys()
请你使用类 KeyValueSet 完成一个交互式命令行你想我猜游戏。支持:
- 装载N个句子对
- 你猜我想 闯关,输出上半句,等待用户猜测下半句
- 如果猜中就累加10分,否则扣2分
- 全部结束输出用户本次得分
我们编写一个新的class,内部通过组合KeyValueSet来支持上述功能,程序框架如下:
# -*- coding: UTF-8 -*-
class GuessSentenceGame:
def __init__(self):
self.kv = KeyValueSet()
self.score = 0def setup(self, sentences):
# TODO(You): 请在此编写装载逻辑
def guess(self, first_word):
# TODO(You): 请在此编写猜测结果,返回 err, value
def run(self):
self.score = 0
for first_word in self.kv.keys():
ret = input("猜一猜下半句是什么? {} -> :".format(first_word))
err, value = self.guess(first_word)
if err==0:
print('你太厉害了,这都能猜得到!+10分!')
self.score += 10
else:
self.score -= 2
print('哈哈,肯定猜不到得啦:{}->{},扣除2分!'.format(first_word, value))
print('游戏结束,你本次游戏得分:', self.score)if __name__ == '__main__':
sentences = [
"hello world",
'monkey king',
'tomorrow is another day',
"good bye"
]game = GuessSentenceGame()
game.setup(sentences)
game.run()
示例输出:
一个示例输出是:
猜一猜下半句是什么? hello -> :world
你太厉害了,这都能猜得到!+10分!
猜一猜下半句是什么? monkey -> :king
你太厉害了,这都能猜得到!+10分!
猜一猜下半句是什么? tomorrow -> :is another day
你太厉害了,这都能猜得到!+10分!
猜一猜下半句是什么? good -> :a
哈哈,肯定猜不到得啦:good->bye,扣除2分!
游戏结束,你本次游戏得分: 28请选出下面的实现代码中,错误 的选项。
实现
# 第一种方法 class GuessSentenceGame: ... def setup(self, sentences): for sentence in sentences: cut_pos = sentence.find(' ') first_word, rest = sentence[0:cut_pos], sentence[cut_pos+1:].strip() self.kv.set(first_word, rest) def guess(self, first_word): value = self.kv.get(first_word) err = 0 if value else 1 return err, value # 第二种方法 class GuessSentenceGame: ... def setup(self, sentences): for sentence in sentences: self.append(sentence) def append(self, sentence): cut_pos = sentence.find(' ') first_word, rest = sentence[0:cut_pos], sentence[cut_pos+1:].strip() self.kv.set(first_word, rest) def guess(self, first_word): ret = self.kv.get(first_word) if ret is None: return 1, None else: return 0, ret # 第三种方法 class GuessSentenceGame: ... def setup(self, sentences): for sentence in sentences: first_word, rest = self.parse_sentence(sentence) self.kv.set(first_word, rest) def parse_sentence(self, sentence): cut_pos = sentence.find(' ') return sentence[0:cut_pos], sentence[cut_pos+1:].strip() def guess(self, first_word): value = self.kv.get(first_word) return 0, value if value else 1, None
主要是代码结构和责任划分不同:
- 方法一:直接设置键值对。在setup方法中,直接遍历句子列表,对每个句子执行分割操作,然后将分割得到的第一个单词和剩余部分设置为键值对。职责集中:所有操作(包括分割句子和设置键值对)都在setup方法内部完成,没有额外的方法调用。
- 方法二:通过额外的方法处理句子。在setup方法中,通过调用append方法来处理每个句子。这种设计提供了更好的模块化。职责分离:append方法负责处理单个句子的分割和键值对设置,而
setup
仅负责遍历句子列表。- 方法三:进一步模块化。通过
parse_sentence
方法专门处理句子的解析。职责高度分离:parse_sentence
负责句子的分割和格式化,setup
方法则只负责调用parse_sentence
和设置键值对。改进:guess
方法中的返回结构似乎有笔误,应该是return 0, value if value else (1, None)
,这样就统一了返回格式和清晰地处理了空值情况。
错误答案分析
class GuessSentenceGame:
...def setup(sentences):
for sentence in sentences:
cut_pos = sentence.find(' ')
self.kv.set(sentence[0:cut_pos], sentence[cut_pos+1:].strip())
def guess(first_word):
self.kv.get(first_word)
return 0, value if value else 1, None# 定义缺少'self'参数
# 在guess方法中,变量value未定义
# 返回值格式问题
更改后代码:
class GuessSentenceGame:
...def setup(self,sentences):
for sentence in sentences:
cut_pos = sentence.find(' ')
self.kv.set(sentence[0:cut_pos], sentence[cut_pos+1:].strip())
def guess(self,first_word):value = self.kv.get(first_word)
return (0, value) if value else (1, None)
题目二:Python类的基本使用(2)
在上一题的基础上。通过类的集成,可以扩展原有的类。例如继承KeyValueSet容器类,扩展功能,支持类似redis的 hset/hget/hkeys 扩展接口
基本代码框架如下
# -*- coding: UTF-8 -*-
from key_value_set import KeyValueSetclass HashKeyValueSet(KeyValueSet):
def __init__(self) -> None:
super().__init__()def hset(self, hash_key, key, value):
# TODO(You): 请在此实现 hset 方法def hget(self, hash_key, key):
hash_set = self.get(hash_key)
if hash_set is None:
return None
else:
return hash_set.get(key)def hkeys(self, hash_key):
hash_set = self.get(hash_key)
if hash_set is None:
return []
else:
return hash_set.keys()
用例如下:
# -*- coding: UTF-8 -*-
if __name__ == '__main__':
hashset = HashKeyValueSet()hashset.hset('puzzle', 'hello', 'world!')
hashset.hset('puzzle', 'monkey', 'king!')
hashset.hset('puzzle', 'tomorrow', 'is another day')
hashset.hset('puzzle', 'good', 'bye!')keys = hashset.hkeys('puzzle')
for key in keys:
ret = input("猜一猜下半句是什么? {} -> :".format(key))
value = hashset.hget('puzzle', key)
if ret == value:
print('你太厉害了,这都能猜得到!')
else:
print('哈哈,肯定猜不到得啦:{}->{}'.format(key, value))
实现
# 第一种方法 self.set(hash_key, {key:value}) # 第二种方法 hash_set = self.get(hash_key) if hash_set is None: hash_set = {key:value} else: hash_set[key] = value self.set(hash_key, hash_set) # 第三种方法 hash_set = self.get(hash_key) if hash_set is None: hash_set = {key:value} self.set(hash_key, hash_set) else: hash_set[key] = value self.set(hash_key, hash_set)
- 方法一:直接设置给定的
hash_key
到一个新的字典,其中只包含单一的键值对{key: value}
。如果该hash_key
之前已经存在且包含其他键值对,那么这些键值对将被新的字典覆盖。这种方法会导致数据丢失,除非每次只想维持一个键值对。- 方法二(最优):首先检查
hash_key
是否已经存在,如果不存在,创建一个新的字典并设置该键值对。如果存在,就在已有的字典中添加或更新键值对,并重新设置到hash_key
。保证了数据的完整性,并能正确地更新或添加键值对。- 方法三:与第二种类似,但在每个条件分支中都调用了
self.set
。效果与第二种方法相同,但稍微增加了代码的冗余,因为在hash_set
已经存在的情况下,可以仅更新字典而不是每次都调用self.set
。
错误答案分析
hash_set = self.get(hash_key,{key:value})
self.set(hash_key, hash_set)# 不能正确地处理键值对的更新,还可能导致混淆,看起来像是在尝试更新或设置值,实际上并没有这么做。正确的做法是明确检查
hash_key
是否存在,如方法二所示,然后根据情况更新或添加键值对,并确保这些更改反映到存储结构中。
题目三:Python类的基本使用(3)
基于第1题,还可以通过类的组合,使用组合而非继承实现类的扩展,支持类似 redis 的 hset/hget/hkeys 扩展接口。
相比于本节第2题,下面代码使用组合的方式复合KeyValueSet的功能,从而实现HashKeyValueSet。
# -*- coding: UTF-8 -*-
from key_value_set import KeyValueSetclass HashKeyValueSet:
def __init__(self, kvset) -> None:
super().__init__()
self.kvset = kvsetdef hset(self, hash_key, key, value):
# TODO(You): 请在此添加代码def hget(self, hash_key, key):
hash_set = self.kvset.get(hash_key)
if hash_set is None:
return None
else:
return hash_set.get(key)def hkeys(self, hash_key):
hash_set = self.kvset.get(hash_key)
if hash_set is None:
return []
else:
return hash_set.keys()
类HashKeyValueSet的用例如下:
def test():
hashset = HashKeyValueSet(KeyValueSet())hashset.hset('puzzle', 'hello', 'world!')
hashset.hset('puzzle', 'monkey', 'king!')
hashset.hset('puzzle', 'tomorrow', 'is another day')
hashset.hset('puzzle', 'good', 'bye!')keys = hashset.hkeys('puzzle')
for key in keys:
ret = input("猜一猜下半句是什么? {} -> :".format(key))
value = hashset.hget('puzzle', key)
if ret == value:
print('你太厉害了,这都能猜得到!')
else:
print('哈哈,肯定猜不到得啦:{}->{}'.format(key, value))if __name__ == '__main__':
test()
实现
# 第一种方法 hash_set = self.kvset.get(hash_key) if hash_set is None: hash_set = {} hash_set[key] = value self.kvset.set(hash_key, hash_set) else: hash_set[key] = value self.kvset.set(hash_key, hash_set) # 第二种方法 self.kvset.set(hash_key, {key: value}) # 第三种方法 hash_set = self.kvset.get(hash_key) if hash_set is None: hash_set = {key: value} else: hash_set[key] = value self.kvset.set(hash_key, hash_set)
在处理数据更新和键值对保存的方式上有所不同:
- 方法一:首先检查
hash_key
是否已存在。如果不存在,则创建一个新的字典,并添加键值对,然后保存。如果存在,则在现有的字典中添加或更新键值对,并重新保存。这种方法保证了数据的完整性,并且正确处理了新旧键值对的添加和更新。- 方法二:每次调用时都会创建一个只包含单个键值对的新字典,并将其设置为
hash_key
的值。这会导致hash_key
原有的数据被覆盖,如果hash_key
下已经存储了其他键值对,那么这些数据将丢失。这种方法适用性有限,只有在确定不需要旧数据时才适用。- 方法三(最优):与第一种方法类似,但更简洁。它检查
hash_key
是否存在,然后相应地创建新字典或更新现有字典,最后保存。这种方法既保留了数据完整性,也有效地管理了新旧数据的更新。。
错误答案分析
self.set(hash_key, {key: value})
# 主要问题在于它不考虑已存在的数据,直接覆盖整个值