学习Python第三周的第五天
一、面向对象编程进阶
昨天学习了Python面向对象编程的基础知识,今天来讨论面向对象编程相关的内容。
init —> 初始化方法,在调用构造器语法创建对象的时候会被自动调用
str —> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用
repr —> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用
—> representation
lt —> 在使用 < 运算符比较两个对象大小时会自动调用
如果一个变量的取值只有有限个选项,可以考虑使用枚举类型。
Python中没有定义枚举类型的语法,但是可以通过继承Enum类来实现枚举类型。
结论1:枚举类型是定义符号常量的最佳选择!!!
结论2:符号常量(有意义的名字)总是优于字面常量!!!
经典案例:扑克游戏。
简单起见,我们的扑克只有52张牌(没有大小王),游戏需要将52张牌发到4个玩家的手上,每个玩家手上有13张牌,按照黑桃、红桃、梅花、方块的顺序和点数从小到大排列,暂时不实现其他的功能。
import random
class Card:
"""牌"""
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __repr__(self):
return self.show()
# 魔术方法---> less than---> 小于运算符(<)
def __lt__(self, other):
if self.suite == other.suite:
return self.face < other.face
return ord(self.suite) < ord(other.suite)
def show(self):
"""显示牌"""
suites = {'S': '♠', 'H': '♥', 'C': '♣', 'D': '♦'}
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{suites[self.suite]}{faces[self.face]}'
class Poker:
"""扑克"""
def __init__(self):
self.cards = [Card(suite, face)
for suite in 'SHCD'
for face in range(1, 14)]
self.counter = 0
def shuffle(self):
"""洗牌"""
self.counter = 0
random.shuffle(self.cards)
def deal(self):
"""发牌"""
card = self.cards[self.counter]
self.counter += 1
return card
def has_more(self):
"""是否还有牌"""
return self.counter < len(self.cards)
class Player:
"""玩家"""
def __init__(self, nickname):
self.nickname = nickname
self.cards = []
def get_one_card(self, card):
""""摸一张牌"""
self.cards.append(card)
def arrange(self):
"""整理手上的牌"""
self.cards.sort()
def show(self):
"""显示玩家手上的牌"""
print(self.nickname, end=':')
for card in self.cards:
print(card, end='')
print()
def main():
nicknames = ('黄小仙', '黄大仙', '黄半仙', '周大大')
players = [Player(nickname) for nickname in nicknames]
poker = Poker()
poker.shuffle()
# 将牌发到四个玩家的手上
for _ in range(13):
for player in players:
card = poker.deal()
player.get_one_card(card)
# 显示四个玩家手上的牌
for player in players:
player.arrange()
player.show()
if __name__ == '__main__':
main()
二、继承和多态
继承:对已有的类进行扩展创建出新的类,这个过程就叫继承。
提供继承信息的类叫做父类(超类、基类),得到继承信息的类称为子类(派生类)。
继承是实现代码复用的一种手段,但是千万不要滥用继承。
继承是一种is-a关系。
a student is a person.
a teacher is a person.
a programmer is a person.
子类直接从父类继承公共的属性和行为,再添加自己特有的属性和行为,
所以子类一定是比父类更强大的,任何时候都可以用子类对象去替代父类对象。
Python中的继承允许多重继承,一个类可以有一个或多个父类。
如果不是必须使用多重继承的场景下,请尽量使用单一继承。
2.1两个类之间有哪些关系
~ is-a关系:继承—>从一个类派生出另一个类
a student is a person
~ has-a关系:关联—>把一个类的对象作为另外一个类的对象的属性
a person has an identity card
——(普通)关联
use-a关系:依赖—>一个类的对象作为另外一个类的方法的参数或返回值
a person use a vehicle(交通工具)
3.1面向对象编程的四大支柱
1、抽象(abstraction):提取共性(定义类就是一个抽象过程,需要做数据抽象和行为抽象)
2、封装(encapsulation):把数据和操作数据的函数从逻辑上组成一个整体(对象)
—>隐藏实现细节,暴露简单的调用接口
3、继承(inheritance):扩展已有的类创建新类,实现对已有类的代码复用
4、多态(polymorphism):给不同的对象发出同样的消息,不同的对象执行了不同的行为。
—>方法重写(override):子类对父类已有的方法,重新给出自己的实现版本
在重写方法的过程中,不同的子类可以对父类的同一个方法给出不同的实现版本,
那么该方法在运行时就会表现出多态性
经典例题:
现在由三类员工:
~ 部门经理:固定月薪,15000
~ 程序员:计时结算月薪,
~ 销售员:底薪 + 提成,底薪1800,销售额 %5提成
写一个面向对象的编程实现工资的计算
from abc import abstractmethod
class Employee:
def __init__(self, name):
self.name = name
@abstractmethod
def get_salary(self):
pass
class Manager(Employee):
def get_salary(self):
return 15000
class Programmer(Employee):
def __init__(self, name):
super().__init__(name)
self.working_hour = 0
def get_salary(self):
return 200 * self.working_hour
class Salesman(Employee):
def __init__(self, name):
super().__init__(name)
self.sales = 0
def get_salary(self):
return 1800 + 0.05 * self.sales
def main():
emps = [Manager('刘备'), Programmer('诸葛亮'), Salesman('关羽')]
for emp in emps:
if type(emp) == Programmer:
emp.working_hour = int(input(f'请输入{emp.name}本月工作时长'))
elif type(emp) == Salesman:
emp.sales = int(input(f'请输入{emp.name}本月销售额'))
print(f'{emp.name}本月工资:{emp.get_salary()}元')
if __name__ == '__main__':
main()