多态
其他语言的所谓多态,指的是一个方法多种实现。在继承前提下,父类规定了子类的接口,使得可以相同的方式调用子类的方法,但会获得不同功能。
Python崇尚的是“鸭子类型”,这个概念的名字来源于由James
Whitcomb Riley提出的鸭⼦测试,“鸭⼦测试”可以这样表述:“当看到⼀只⻦⾛起
来像鸭⼦、游泳起来像鸭⼦、叫起来也像鸭⼦,那么这只⻦就可以被称为鸭
⼦。”。“鸭子类型”不关心对象的类型,只关心对象的行为。
“鸭子类型 ”是动态类型的一种风格,在这种风格中,一个对象的有效语义,不是由继承自特定的类或特定的接口实现,而是由“当前方法和属性的集合”决定。
class Duck:
def walk(self):
print("Walk")
def swim(self):
print("Swim")
class Cat(Animal):
def walk(self):
print("猫walk")
def swim(self):
print("猫Swim")
def catch(self):
print("猫catch mice")
class Dog:
def bark(self):
print("barking")
def swim(self):
print("swimming")
def show(obj): # 只要具有定义的walk和swim方法的对象就是鸭子,不管其继承自哪个基类,
obj.walk() # 也不管有没有新的方法,是否重定义方法,都是鸭子。某个对象是否鸭子,只看该对象是否包含指定的方法和属性
obj.swim()
duck = Duck()
cat = Cat()
animal = Animal()
dog = Dog()
show(duck) # duck是鸭子
show(cat) # cat是鸭子
show(animal) # animal也是鸭子
# show(dog) # dog没有swim,walk方法,因此不是鸭子
上例可以看出来,对于基于继承和重写、父类引用指向子类应用的其他语言多态(如java)并不存在,廖雪峰的教材:“你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。”上例中即使非Animal的子类的dog也能在show函数中运行,也就没有所谓的多态的土壤了。因此Python用鸭子类型体现多态的概念,也不像其他语言有相应的多态语法。
类的信息
- name 通过类名访问,得到的结果为字符串(与每个py文件的__name__属性不是一个东西) (查看类名)
class Cat(Animal):
def walk(self):
print("猫walk")
def swim(self):
print("猫Swim")
print(Cat.__name__) # Cat
print(__name__) # __main__ 当前py文件的__name__
print(__name__)
- dict 类名.dict,通过类名访问,获取类的信息,包括类⽅法,静态⽅法,成员⽅法,以字典的形式返回;(查看类的属性方法)
通过对象名访问,获取的是该对象的属性名和值
print(Cat.__dict__)
#{'__module__': 'cat', 'walk': <function Cat.walk at #0x0000019C799AC048>, 'swim': <function Cat.swim at #0x0000019C799AC0D0>, 'catch': <classmethod object at #0x0000019C79997CF8>, '__doc__': None}
-
doc 通过类.方法名,或者函数名访问,如print(a.doc),获取帮助文档字符串DocString (查看方法帮助)
-
bases 通过类名访问,返回父类,并不返回所有祖先类(查看父类是谁)
-
module 通过类名或对象名访问,返回类、对象所在的模块名,即没有py后缀的文件名。 (查看所在文件名)
-
mro 通过类名访问,返回该类继承父类方法的顺序表 (查看所有父类和继承顺序)
对象的信息
- dir(object) 查看对象的信息
# 对象信息列表
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
在对象信息列表中__class__是对象继承的类,__dict__是对象属性字典,__module__对象模块名等。
常用函数
issubclass(sub,sup) 判断sub类是不是sup类的子类
isinstance(obj,class) 判断obj是不是class或子类的对象 type只能判断对象的直接父类
hasattr(obj,name) 判断对象有无某属性
getattr(obj,name) 获取对象的属性值
setattr(obj,name,value) 设置对象的属性值,该属性必须存在
callable(object) 判断⼀个对象是否可调⽤。对于函数、方法、lambda 函式、 类以及实现了 call 方法的类实例, 它都返回 True。
异常处理
错误指的是代码有语法问题,无法解释运行,必须改正后才能运行。
如果代码没有语法问题,可以运行,但会出运行时的错误,例如除零错误,下标越界问题,这种在运行期检测到的错误叫异常,出现了异常必须处理否则程序会终止执行,用户体验很差。
try excetion:
语法:
try:
print(1/0) # 可能出现异常的语句写在此处
except SyntaxError: # 共有3种异常捕获,从上到下进行捕获。1.本行是语法错误,捕获
print(SyntaxError) # 不成功,进入下一种
except ZeroDivisionError as e: # 2. 除零错误,捕获成功,不进入第三种异常
print("error:",e ) # 进入finally后的语句,如果没有finally,
except Exception as e: # 则进入try-except之后的程序
print("Exception:",e)
else: # 如果以上捕获都不成功,则执行else后语句
print("elseelseelse")
finally: # 无论捕获是否成功,都执行finally后语句
print("fin")
print("_______") # 如果捕获不成功,就报错,不再执行try-except后
#的语句
多个exception时,要将更精确异常的放在前面,将范围更大的放在后面,如
except ZeroDivisionError as e: 放在 except Exception as e前面。参考《内建异常类的层次》,将层次低的放在前面,层次高的放在后面。
也可以使用元组的方式表达多种异常:
except (SyntaxError,ZeroDivisionError,Exception) as e:
print(e)
抛出异常
⼿动抛出⼀个指定类型的异常,⽆论是哪种异常类都可以带⼀个字符串参数,对异
常进⾏描述。
raise不带参数会把错误原样抛出。
=当抛出异常后,就终止程序执行,转而进行异常处理=
- 手动抛出异常是为了在产品或组织内统一处理出现的异常
try:
raise ZeroDivisionError("不能为零")
finally:
print('a')
print("__________")
异常嵌套
try里抛出异常,except捕获并处理完了又收到异常2,继续捕获与处理……
try:
print("女神,一起看日出吧?") # 要检测的语句1
raise Exception("不去,有事要去逛街!") # 遭遇异常1
except Exception as e: # 捕获异常1
print("我也要买东西,一起去") # 处理1
try:
print("——————") #要检测的语句2
raise Exception("累了,回家去") # 遭遇异常2
except Exception as e: # 捕获异常2
print("前面有咖啡馆,坐坐") # 处理2
try:
print("要拿铁吧?") # 要检测的语句3
raise Exception("不要!要凉粉") #检测到异常3
except Exception as e: # 捕获异常3
print("肯定要吃凉粉,等我买回来") # 处理3
assert断言
语法:assert 条件[,异常描述字符串]
执⾏流程:如果条件为假,则抛出AssertionError,条件为真,就当assert不存在
主要用于问题排查,一般用print排查问题,但assert断言更规范,在排除完问题后可以不删除而不影响用户的使用,但print语句若忘了删除,就会出现不合理的输出。
a = 5
assert a > 6, "a<=0" # 如果assert后的条件不满足,就会抛出AssertError:a<=0。如果条件满足则执行后面的语句
print(5)
# AssertionError: a<=0
自定义异常类
class Custom(Exception): # 1.自定义类必须继承自Exception或BaseException
def __init__(self, msg):
super().__init__() # 2.调用父类构造方法
self.msg = msg
def __str__(self): # 3、重写__str__
return self.msg
def handle(self): # 4、编写异常处理方法
print("标准处理方式")
try:
raise Custom("除零异常") # 1、抛出异常
except Custom as e: # 2、捕获异常
e.handle() # 3、调用异常处理方法
作业
# ---coding:utf-8----
# 文件名: 作业.py
# @Time:2020/3/9 10:51
'''
初级
1.利利⽤用封装和继承的特性完成如下操作:
小学生:
属性:姓名、学号、年年龄、性别
行为:
学习
打架
中学⽣:
属性:姓名、学号、年龄、性别
行为:
学习
谈恋爱
⼤学生:
属性:姓名、学号、年年龄、性别
⾏为:
学习
打游戏
测试类:
创建小学生对象
调用学习的方法
打印内容为:xx 学习的内容为:语⽂ 数学 英语
创建中学生对象
调用学习的⽅法
打印内容为:xx 学习的内容为:语数外 生物化 史地政
创建⼤学⽣对象
调用学习的方法:
打印内容为:逃课中。。。。。。
'''
class Student:
def __init__(self, name, id, age, gender):
self.name = name
self.id = id
self.age = age
self.gender = gender
def study(self):
print(self.name)
class Pupil(Student):
def study(self):
print(self.name + '学习的内容为:语文 数学 英语')
def fight(self):
print(self.name + "打架")
class MiddleSchoolStudent(Student):
def study(self):
print(self.name + '学习的内容为:语数外 生物化 史地政')
def love(self):
print(self.name + "谈恋爱")
class CollegeStudent(Student):
def study(self):
print('逃课中')
def game(self):
print(self.name + "打游戏")
pupil1 = Pupil("小李子", "20100524", 10, "男")
mstudent = MiddleSchoolStudent("中李子", "200502434", 15, "男")
cStudnet = CollegeStudent("大李子", "2017829234", 21, "男")
pupil1.study()
mstudent.study()
cStudnet.study()
#
"""
2.主⼈人杨夫⼈人向客⼈人李李⼩小姐介绍⾃自⼰己家的宠物狗和宠物猫
宠物狗:
昵称是:贝贝
年龄是:2
性别:雌
会两条腿行走的才艺
宠物猫
昵称是:花花
年龄是1
性别是:雄
会装死的才艺
"""
class Pet:
def __init__(self, nickname, age, gender):
self.nickname = nickname
self.age = age
self.gender = gender
def talent(self):
print(self.nickname + "会什么才艺呢")
class Dog(Pet):
def talent(self):
print(self.nickname + "会两条腿走路")
class Cat(Pet):
def talent(self):
print(self.nickname + "会装死")
beibei = Dog("贝贝", 2, "雌")
huahua = Cat("花花", 1, "雄")
beibei.talent()
huahua.talent()
##################################################
'''
中级
1.设计⼀一个Person,包含姓名、年年龄和性别三个私有成员属性,另外Person类还包含males和females两个私有类属性,⽤用来记录男
生和女生的数量,可以通过number_male和number_female两个公有类方法获取males和females两个私有类属性的值。自己完成Person类
的设计,然后实例例化多个Person的对象,分别统计男⼥女女的⼈数
'''
class Person:
__males = 0
__females = 0
def __init__(self, name, age, gender):
self.__name = name
self.__age = age
self.gender = gender
if self.gender == "女":
Person.__females += 1
else:
Person.__males += 1
@classmethod
def number_male(cls):
return "共有男生:"+str(cls.__males)
@classmethod
def number_female(cls):
return "共有女生:"+str(cls.__females)
p1 = Person("张三", 18, "男")
p2 = Person("李四", 19, "男")
p3 = Person("王红", 18, "女")
p4 = Person("王红一", 19, "女")
p5 = Person("赵丽", 17, "女")
print(Person.number_female())
print(Person.number_male())
'''2.编写⼀一个简单的⼯工资管理理程序,系统可以管理理以下四类⼈人:工⼈(worker)、销售员(salesman)、经理(manager)、
销售经理(salemanager)。所有的员工都具有员工号,姓名,工资等属性,有设置姓名,获取姓名,获取员工号,计算工资等
方法。1)工⼈:工⼈具有工作小时数和时薪的属性,工资计算方法为工作小时数*时薪。2)销售员:具有销售额和提成比例的属性,
工资计算方法为销售额提成*比例。3)经理:具有固定月薪的属性,工资计算方法为固定月薪。4)销售经理:工资计算方法为销售额*提成
比例+固定月薪。请根据以上要求设计合理理的类,完成以下功能:1)添加所有类型的⼈员2)计算月薪 3)显示所有⼈工资情况
'''
class Employee:
nameList = []
def __init__(self, id, name):
self.id = id
self.name = name
# self.salary = salary
self.type = type
def setName(self, name):
self.name = name
def getName(self):
print(self.name)
def getId(self):
print(self.id)
@classmethod
def salary(cls, id):
for employee in cls.nameList:
if employee["id"] == id:
print("{}本月收入是{}元:".format(employee["name"],employee['salary']))
@classmethod
def display_all_salary(cls):
print("{:>2}\t \t{:>8}".format("姓名", "收入"))
for employee in cls.nameList:
print("{:>2}\t \t{:>8}元".format(employee["name"],employee['salary']))
class Worker(Employee):
def __init__(self, id, name, hours, hourWage):
super().__init__(id, name)
self.hours = hours
self.hourWage = hourWage
def calSalary(self):
print("你的工资是时薪*小时数:时薪{}元*小时数{}={}元".format(self.hourWage, self.hours, self.hourWage * self.hours))
def __str__(self):
return self.name
# 1, 张三, 100, 50
@classmethod
def add_information(cls,inputTypes): # 有一个参数,由用户输入如worker
information = input("请输入人员id,name,小时数,时薪,如输入:1,张三,100,50:").split(",")
for id in super().nameList:
if id["id"] == information[0]:
print("已有该人员存在")
break
else:
super().nameList.append({"id": information[0],
"name":information[1],
"type": inputTypes,
"hours": int(information[2]),
"hourWage": int(information[3]),
"salary": int(information[2])*int(information[3])
})
print(super().nameList)
class Salesman(Employee):
# salesvolume销售额,royalty提成
def __init__(self, id, name, salesvolume,royalty):
super().__init__(id, name)
self.salesvolume = salesvolume
self.royalty = royalty
def calSalary(self):
print("你的工资是销售额*提成率:销售额{}元*提成率{}={}元".format(self.salesvolume, self.royalty, self.salesvolumee * self.royalty))
def __str__(self):
return self.name
# 2,李四,100000,10%
@classmethod
def add_information(cls,inputTypes):
information = input("请输入人员id,name,销售额,提成率,如输入2,李四,100000,10%:").split(",")
for employee in super().nameList:
if employee["id"] == information[0]:
print("已有该人员存在")
break
else:
information[3] = int(information[3].split("%")[0])/100
super().nameList.append({
"id": information[0],
"name": information[1],
"type": inputTypes,
"salesvolume": int(information[2]),
"royalty": information[3],
"salary": int(information[2])*information[3]
})
print(super().nameList)
class SaleManager(Salesman):
# salesvolume销售额,royalty提成,baseSalary底薪
def __init__(self, id, name, salesvolume, royalty,baseSalary):
super().__init__(id, name,salesvolume,royalty)
self.baseSalary = baseSalary
self.royalty = int(royalty.split("%")[0])/100
def calSalary(self):
print("你的工资是底薪+销售额*提成率:底薪{} + 销售额{}元*提成率{}={}元".format(self.baseSalary,\
self.salesvolume, self.royalty, self.salesvolume + self.salesvolume * self.royalty))
def __str__(self):
return self.name
# 2,李四,100000,10%
@classmethod
def add_information(cls,inputTypes):
information = input("请输入人员id,name,销售额,提成率,如输入4,赵四,100000,10%:").split(",")
information[3] = int(information[3].split("%")[0])/100
for employee in super().nameList:
if employee["id"] == information[0]:
print("已有该人员存在")
break
else:
super().nameList.append({
"id": information[0],
"name": information[1],
"type": inputTypes,
"salesvolume": int(information[2]),
"royalty": information[3],
"salary": int(information[2])*information[3]
})
print(super().nameList)
class Manager(Employee):
# salesvolume销售额,royalty提成
def __init__(self, id, name, salary):
super().__init__(id, name)
self.salary = salary
def calSalary(self):
print("你的工资是{}".format(self.salary))
def __str__(self):
return self.name
# 3,王五,12000
@classmethod
def add_information(cls,inputTypes):
information = input("请输入人员id,name,工资(3,王五,12000),按n退出").split(",")
for employee in super().nameList:
if employee["id"] == information[0]:
print("已有该人员存在")
break
else:
super().nameList.append({
"id": information[0],
"name": information[1],
"type": inputTypes,
"salary": information[2]
})
print(super().nameList)
type_list = ("worker", "salesman", "salemanager", "manager")
def menu():
print(
'''
1.添加用户
2.计算月薪
3.显示所有人工资
0.退出
''')
print("*" * 50)
def input_number():
number = None
while number not in ["0", "1", "2", "3"]:
number = input("请输入数字0,1,2,3:")
return number
def exit_app():
print("再见了")
exit()
def add_types():
types = None
while types not in type_list:
types = input("请输入人员类型(worker,salesman, salemanager,manager),按n按出:")
return types
def main():
while True:
menu() # 显示菜单
number = input_number() # 选择0,1,2,4进入以下处理:
if number == "0": # "0":退出
exit_app()
if number == "1": # "1"录入数据
types = add_types() # 先确定人员类型
if types == "worker": # 如果要输入的人员信息是worker类型:
Worker.add_information(types) #调用Worker类方法add_information
elif types == "salesman": # 如果是Saleman类型:
Salesman.add_information(types) # 调用Salesman类方法add_information
elif types == "manager":
Manager.add_information(types)
elif types == "salemanager":
SaleManager.add_information(types)
else: # 如果输入其他,就表示退出
break
if number == "2": # 计算月薪
id = input("请输入id:")
Employee.salary(id)
if number == "3": # 显示所有人的工资
Employee.display_all_salary()
worker = Worker("1","张三",100,50)
salesman = Salesman("2","李四",100000,"10%")
manager = Manager("3","王五",12000)
salemanager = SaleManager("4","赵四",1300000,"1%",10000)
worker.calSalary()
salemanager.calSalary()
manager.calSalary()
salemanager.calSalary()
worker.getId()
worker.getName()
worker.setName("张三丰")
worker.getName()