头歌python通关:面向对象程序设计
第1关:工资结算系统
本关任务:某公司有三种类型的员工 分别是部门经理、程序员和销售员,需要设计一个工资结算系统 根据提供的员工信息来计算月薪,部门经理的月薪是每月固定15000元,程序员的月薪按本月工作时间计算每小时150元,销售员的月薪是1200元的底薪加上销售额5%的提成。你需要编写不同职位的工资结算方法。
相关知识
为了完成本关任务,你需要掌握:1.类和对象,2.装饰器。
编程要求
根据提示,在右侧编辑器补充代码,根据提示,完成经理
,程序员
,销售员
三个类别的相关内容。
测试说明
根据程序中的提示,完成相应类代码的编写。 提示:在本题测试脚本中,初始数据为``` Manager('刘备'), Programmer('诸葛亮'), Manager('曹操'), Salesman('荀彧'), Salesman('吕布'), Programmer('张辽'), Programmer('赵云') 且工作时长默认为7,销售额默认为100
```
"""
某公司有三种类型的员工 分别是部门经理、程序员和销售员
需要设计一个工资结算系统 根据提供的员工信息来计算月薪
部门经理的月薪是每月固定15000元
程序员的月薪按本月工作时间计算 每小时150元
销售员的月薪是1200元的底薪加上销售额5%的提成
"""
from abc import ABCMeta, abstractmethod
class Employee(object, metaclass=ABCMeta):
"""员工"""
def __init__(self, name):
"""
初始化方法
:param name: 姓名
"""
# 请在此处添加代码 #
# *************begin************#
self.__name=name
# **************end*************#
@property
def name(self):
'''返回姓名'''
# 请在此处添加代码 #
# *************begin************#
return self.__name
# **************end*************#
@abstractmethod
def get_salary(self):
"""
获得月薪
:return: 月薪
"""
pass
class Manager(Employee):
"""部门经理"""
def get_salary(self):
return 15000.0
class Programmer(Employee):
"""程序员"""
def __init__(self, name, working_hour=0):
"""
初始化方法
:param name: 姓名
:param working_hour:工作时长
"""
# 请在此处添加代码 #
# *************begin************#
super().__init__(name)
self.__working_hour=working_hour
# **************end*************#
@property
def working_hour(self):
'''返回工作时长'''
# 请在此处添加代码 #
# *************begin************#
return self.__working_hour
# **************end*************#
@working_hour.setter
def working_hour(self, working_hour):
'''
设置工作时长
:param working_hour:工作时长
'''
# 请在此处添加代码 #
# *************begin************#
self.__working_hour=working_hour
# **************end*************#
def get_salary(self):
'''返回程序员所得工资'''
# 请在此处添加代码 #
# *************begin************#
return self.__working_hour*150.0
# **************end*************#
class Salesman(Employee):
"""销售员"""
def __init__(self, name, sales=0):
"""
初始化方法
:param name: 姓名
:param sales:销售额
"""
# 请在此处添加代码 #
# *************begin************#
super().__init__(name)
self.__sales=sales
# **************end*************#
@property
def sales(self):
'''返回销售额'''
# 请在此处添加代码 #
# *************begin************#
return self.__sales
# **************end*************#
@sales.setter
def sales(self, sales):
'''
设置销售额
:param sales:销售额
'''
# 请在此处添加代码 #
# *************begin************#
self.__sales=100
# **************end*************#
def get_salary(self):
'''返回销售员所得工资'''
# 请在此处添加代码 #
# *************begin************#
return self.__sales*0.05+1200
# **************end*************#
第2关:设计LFU缓存类
本关任务:编写一个具有put,get功能的LFU Cache类
根据提示,在右侧编辑器补充代码,实现完整的LFU Cache类
测试说明
平台会对你编写的代码进行测试:
测试输入: ["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]] 预期输出: [None, None, 1, None, -1, 3, None, -1, 3, 4]
from operator import methodcaller
class Node(object):
"""
双链表中的链表节点对象
"""
def __init__(self, key=None, value=None, freq=0):
"""
Args:
key:对应输入的key
value:对应输入的value
freq:被访问的频率
pre:指向前一个节点的指针
next:指向后一个节点的指针
"""
self.key = key
self.value = value
self.freq = freq
self.pre = None
self.next = None
class LinkedList(object):
"""
自定义的双向链表
"""
def __init__(self):
"""
Args:
__head:双向链表的头结点
__tail:双向链表的尾节点
"""
self.__head = Node()
self.__tail = Node()
self.__head.next = self.__tail
self.__tail.pre = self.__head
def insertFirst(self, node):
"""
将指定的节点插入到链表的第一个位置
Args:
node:将要插入的节点
"""
node.next = self.__head.next
self.__head.next.pre = node
self.__head.next = node
node.pre = self.__head
def delete(self, node):
"""
从链表中删除指定的节点
Args:
node:将要删除的节点
"""
if self.__head.next == self.__tail:
return
node.pre.next = node.next
node.next.pre = node.pre
node.next = None
node.pre = None
def getLast(self):
"""
从链表中获取最后一个节点
Returns:
双向链表中的最后一个节点,如果是空链表则返回None
"""
if self.__head.next == self.__tail:
return None
return self.__tail.pre
def isEmpty(self):
"""
判断链表是否为空,除了head和tail没有其他节点即为空链表
Returns:
链表不空返回True,否则返回False
"""
return self.__head.next == self.__tail
class LFUCache(object):
"""
自定义的LFU缓存
"""
def __init__(self, capacity):
"""
Args:
__capacity:缓存的最大容量
__keyMap: key->Node 这种结构的字典
__freqMap:freq->LinkedList 这种结构的字典
__minFreq:记录缓存中最低频率
"""
self.__capacity = capacity
self.__keyMap = dict()
self.__freqMap = dict()
self.__minFreq = 0
def get(self, key):
"""
获取一个元素,如果key不存在则返回-1,否则返回对应的value
同时更新被访问元素的频率
Args:
key:要查找的关键字
Returns:
如果没找到则返回-1,否则返回对应的value
"""
#你的代码在这里#
if key not in self.__keyMap:
return -1
node=self.__keyMap[key]
self.__increment(node)
return node.value
def put(self, key, value):
"""
插入指定的key和value,如果key存在则更新value,同时更新频率
如果key不存并且缓存满了,则删除频率最低的元素,并插入新元素
否则,直接插入新元素
Args:
key:要插入的关键字
value:要插入的值
"""
#你的代码在这里#
if key in self.__keyMap:
return -1
node=self.__keyMap[key]
node.value=value
self.__increment(node)
else:
if self.__capacity==0:
return
if len(self.__keyMap)==self.__capacity:
self.__removeMinFreqElement()
node=Node(key,value,1)
self.__increment(node,True)
self.__keyMap[key]=node
def __increment(self, node, is_new_node=False):
"""
更新节点的访问频率
Args:
node:要更新的节点
is_new_node:是否是新节点,新插入的节点和非新插入节点更新逻辑不同
"""
if is_new_node:
self.__minFreq = 1
self.__setDefaultLinkedList(node)
else:
self.__deleteNode(node)
node.freq += 1
self.__setDefaultLinkedList(node)
if self.__minFreq not in self.__freqMap:
self.__minFreq += 1
def __setDefaultLinkedList(self, node):
"""
根据节点的频率,插入到对应的LinkedList中,如果LinkedList不存在则创建
Args:
node:将要插入到LinkedList的节点
"""
if node.freq not in self.__freqMap:
self.__freqMap[node.freq] = LinkedList()
linkedList = self.__freqMap[node.freq]
linkedList.insertFirst(node)
def __deleteNode(self, node):
"""
删除指定的节点,如果节点删除后,对应的双链表为空,则从__freqMap中删除这个链表
Args:
node:将要删除的节点
"""
if node.freq not in self.__freqMap:
return
linkedList = self.__freqMap[node.freq]
freq = node.freq
linkedList.delete(node)
if linkedList.isEmpty():
del self.__freqMap[freq]
def __removeMinFreqElement(self):
"""
删除频率最低的元素,从__freqMap和__keyMap中都要删除这个节点,
如果节点删除后对应的链表为空,则要从__freqMap中删除这个链表
"""
linkedList = self.__freqMap[self.__minFreq]
node = linkedList.getLast()
linkedList.delete(node)
del self.__keyMap[node.key]
if linkedList.isEmpty():
del self.__freqMap[node.freq]
if __name__ == '__main__':
operation = eval(input())
data = eval(input())
cache = eval("{}({})".format(operation.pop(0), data.pop(0)[0]))
output = []
for i, j in zip(operation, data):
if i == 'put':
methodcaller('put', j[0], j[1])(cache)
output.append(None)
elif i == 'get':
output.append(methodcaller('get', j[0])(cache))
print(output)
第3关:定义银行柜员类BankTeller
本关任务:编写一个银行柜员类BankTeller,继承BankEmployee类,要求: 1.完善BankEmployee类,对私有属性name和num添加set方法和get方法以实现对私有属性的设置和获取 2.对工号的合法性进行检验,要求工号以字母s开头,如s678是合法工号,678不是合法工号 3.继承BankEmployee类,定义银行柜员类BankTeller类,其name属性和num属性和父类BankEmployee类相同,属性salary默认参数为2000
平台会对你编写的代码进行测试:
测试输入: 张飞 007 预期输出: 工号以s开头 张飞领到这个月工资2000 工号以s开头 张飞 None
测试输入: 赵云 s009 预期输出: 赵云领到这个月工资2000 赵云 s009
class BankEmployee():
# 请在此处添加代码 #
# *************begin************#
def __init__(self,name,num,salary=3000):
self.__name=name
self.__num=num
self.salary=salary
def get_salary(self):
print(f'{self.__name}领到这个月工资{self.salary}')
# **************end*************#
def main():
name = input()
num = input()
bankemployee = BankEmployee(name,num)
bankemployee.get_salary()
if __name__=="__main__":
main()
第4关:定义银行柜员类BankTeller
本关任务:编写一个银行柜员类BankTeller,继承BankEmployee类,要求: 1.完善BankEmployee类,对私有属性name和num添加set方法和get方法以实现对私有属性的设置和获取 2.对工号的合法性进行检验,要求工号以字母s开头,如s678是合法工号,678不是合法工号 3.继承BankEmployee类,定义银行柜员类BankTeller类,其name属性和num属性和父类BankEmployee类相同,属性salary默认参数为2000
测试说明
平台会对你编写的代码进行测试:
测试输入: 张飞 007 预期输出: 工号以s开头 张飞领到这个月工资2000 工号以s开头 张飞 None
测试输入: 赵云 s009 预期输出: 赵云领到这个月工资2000 赵云 s009
class BankEmployee():
def __init__(self,name="",num="",salary=2000):
self.__name = name
self.__num = num
self.salary = salary
def get_salary(self): #定义领工资方法get_salary()
print("%s领到这个月工资%d"%(self.__name,self.salary))
# 请在此处添加代码对name和num设置set/get方法 #
# ************* begin ************#
def get_name(self):
return self.__name
def set_name(self,name):
self.__name=name
def get_num(self):
return self.__num
def set_num(self,num):
self.__num=num
# ************** end *************#
class BankTeller(BankEmployee):
# 请在此处添加代码 #
# *************begin************#
def set_num(self,num):
if num[0]!='s':
print("工号以s开头")
self.__num=''
else:
self.__num=num
def get_num(self):
if self.__num=='' or self.__num[0]!='s':
print("工号以s开头")
return None
return self.__num
# **************end*************#
def main():
bankteller = BankTeller()
name = input()
num = input()
bankteller.set_name(name)
bankteller.set_num(num)
bankteller.get_salary()
print(bankteller.get_name(),bankteller.get_num())
if __name__=="__main__":
main()
第5关:定义银行员工类BankEmployee
本关任务:编写银行员工类BankEmployee,要求: 1.银行员工类的属性包括姓名name,工号num,工资salary 2.姓名name和工号num设置为私有属性,并将salay设置为默认参数300
平台会对你编写的代码进行测试:
测试输入: 张飞 007 预期输出: 张飞领到这个月工资3000
class BankEmployee():
# 请在此处添加代码 #
# *************begin************#
def __init__(self,name,num,salary=3000):
self.__name=name
self.__num=num
self.salary=salary
def get_salary(self):
print(f'{self.__name}领到这个月工资{self.salary}')
# **************end*************#
def main():
name = input()
num = input()
bankemployee = BankEmployee(name,num)
bankemployee.get_salary()
if __name__=="__main__":
main()
第6关:数字时钟走字
本关任务:本题中已给出一个时钟类的定义,请模拟数字时钟走字过程。
根据提示,在右侧编辑器补充代码,模拟数字时钟走字,只需输出60次走字。
平台会对你编写的代码进行测试:
测试输入:23
,59
,58
; 说明:输入格式为23,59,58,其中23为时,59为分,58为秒; 预期输出:
23:59:58
23:59:59
00:00:00
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05
00:00:06
00:00:07
00:00:08
00:00:09
00:00:10
00:00:11
00:00:12
00:00:13
00:00:14
00:00:15
00:00:16
00:00:17
00:00:18
00:00:19
00:00:20
00:00:21
00:00:22
00:00:23
00:00:24
00:00:25
00:00:26
00:00:27
00:00:28
00:00:29
00:00:30
00:00:31
00:00:32
00:00:33
00:00:34
00:00:35
00:00:36
00:00:37
00:00:38
00:00:39
00:00:40
00:00:41
00:00:42
00:00:43
00:00:44
00:00:45
00:00:46
00:00:47
00:00:48
00:00:49
00:00:50
00:00:51
00:00:52
00:00:53
00:00:54
00:00:55
00:00:56
00:00:57
from time import sleep
class Clock(object):
"""数字时钟"""
def __init__(self, hour=0, minute=0, second=0):
"""初始化方法
:param hour: 时
:param minute: 分
:param second: 秒
"""
self._hour = hour
self._minute = minute
self._second = second
def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
def show(self):
"""显示时间"""
return '%02d:%02d:%02d' % \
(self._hour, self._minute, self._second)
def main():
#h为时,m为分,s为秒
h,m,s = input().split(',')
h = int(h)
m = int(m)
s = int(s)
# 请在此处添加代码 #
# *************begin************#
clock=Clock(h,m,s)
i=60
while i>0:
print(clock.show())
clock.run()
i=i-1
# **************end*************#
if __name__ == '__main__':
main()
第2关:定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法
本关任务:定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法。
from math import sqrt
class Point(object):
def __init__(self, x=0, y=0):
"""初始化方法
:param x: 横坐标
:param y: 纵坐标
"""
self.x = x
self.y = y
def move_to(self, x, y):
"""移动到指定位置
:param x: 新的横坐标
"param y: 新的纵坐标
:return : 无返回值
"""
# 请在此处添加代码 #
# *************begin************#
self.x=x
self.y=y
# **************end*************#
def move_by(self, dx, dy):
"""移动指定的增量
:param dx: 横坐标的增量
"param dy: 纵坐标的增量
:return : 无返回值
"""
# 请在此处添加代码 #
# *************begin************#
self.x+=dx
self.y+=dy
# **************end*************#
def distance_to(self, other):
"""计算与另一个点的距离
:param other: 另一个点,坐标为(other.x,other.y)
:return :返回两点之间的距离
"""
# 请在此处添加代码 #
# *************begin************#
dx=self.x-other.x
dy=self.y-other.y
temp=dx*dx+dy*dy
return sqrt(temp)
# **************end*************#
def __str__(self):
return '(%s, %s)' % (str(self.x), str(self.y))