1.派生
派生指的是子类继承父类属性,并且派生出自己的属性。
在进行属性查找时,子类中的属性名会优先于父类被查找。
对象中的的属性有相同的,可以将代码提出来建一个父类。
在子类派生方法内使用使用父类的功能,有两种方式:
1.指定名称
2.super()
# 案例
class Student():
school = '桂电'
def __init__(self, name, age, gender, course):
self.name = name
self.age = age
self.gender = gender
self.course = course
class Teacher():
school = '桂电'
def __init__(self, name, age, gender, title):
self.name = name
self.age = age
self.gender = gender
self.title = title
class GLIET:
school = '桂电'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
1.1指定名称
指定类的名称调用这个类中的属性。这种方式任何类都可以访问得到。
将类名称括号和父类名称删除断开继承关系,也可以访问得到这个功能。
不依赖于继承关系,使用时必须严格按照函数的要求传入值,这个self不能省略,否则缺少参数。
类名.__init__(self, 参数1, 参数2 ···)
class GLIET:
school = '桂电'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(GLIET):
def __init__(self, name, age, gender, course):
GLIET.__init__(self, name, age, gender)
self.course = course
class Teacher(GLIET):
def __init__(self, name, age, gender, title):
GLIET.__init__(self, name, age, gender)
self.title = title
stu1 = Student('kid', 18, 'male', 'python')
tea1 = Teacher('qz', 30, 'male', 'python')
print(stu1.__dict__)
print(tea1.__dict__)
1.2 super
调用super()会返回一个特殊的对象,该对象专门用来引用父类的属性,依赖于继承的关系,严格按照MRO的规定顺序向后查找。使用时会自动传入self参数,不能在写,否则参数多了。
Python 2 中: super(自己的类名, self).__init__( 参数1, 参数2 ···) 完整写法。
Python 3 中: super().__init__( 参数1, 参数2 ···) 简写。
class GLIET:
school = '桂电'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(GLIET):
def __init__(self, name, age, gender, course):
super().__init__(name, age, gender)
self.course = course
class Teacher(GLIET):
def __init__(self, name, age, gender, title):
super().__init__( name, age, gender)
self.title = title
stu1 = Student('kid', 18, 'male', 'python') # {'name': 'kid', 'age': 18, 'gender': 'male', 'course': 'python'}
tea1 = Teacher('qz', 30, 'male', 'python') # {'name': 'qz', 'age': 30, 'gender': 'male', 'title': 'python'}
print(stu1.__dict__)
print(tea1.__dict__)
# 查找顺序
class A:
def test(self):
print("A----text")
print(super())
super().aaa()
print(111)
def aaa(self):
print('B----aaa')
def aaa(self):
print('B----aaa')
class B:
def test(self):
print("B----text")
def aaa(self):
print("B----aaa")
class C(A, B):
def aaa(self):
print('C----->aaa')
super()只会按照MRO列表的顺序查找,不会在回头查找。
A----text
<super: <class 'A'>, <C object>> # A.aaa() 从下面的MRO列表可以看出
B----aaa # 往前查找
A----aaa # 回头
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
2.组合
在一个类中以另外一个类的对象作为数据属性,称为类的组合。
代码复用:在编程过程中为了提高代码效率,将重复的代码提炼成可复用的代码,而降低代码的复写。子类通过继承父类,而复用父类代码。
解决类与类之间的冗余问题:
1.继承:是一种什么是什么的关系,两个类中有共同的属性。
2.组合:是一种什么有什么的关系,不需要依赖什么相关联的。
在类与类有关系用的情况使用继承,在没有关系的情况下用组合。
# 例1
class Foo():
def __init__(self, x):
self.x = x
def func1(self):
return self.x
class Bar():
def __init__(self, y):
self.y = y
def func1(self):
return self.y
obj1 = Foo(10)
obj2 = Bar(20)
obj1.z = obj2 # 对象的属性是另一个对象
print(obj1.z.y) # 20
# 例2
class GLIET(): # 派生属性
school = '桂电'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Course(): # 课程信息
def __init__(self, course_name, course_period, course_price):
self.course_name = course_name
self.course_period = course_period
self.course_price = course_price
class Student(GLIET): # 学生
def __init__(self, name, age, gender, courses=None):
if courses == None:
courses = []
self.courses = courses
super().__init__(name, age, gender)
def choose_course(self, course): # 学生能选课
self.courses.append(course)
print("%s 选课成功%s" % (self.name, course.course_name))
class Teacher(GLIET): # 老师
def __init__(self, name, age, gender, teach):
super().__init__(name, age, gender)
self.teach = teach
def performance(self, stu_obj, num): # 老师给成绩
stu_obj.num = num
print("%s老师给%s学生打分%s." % (self.name, stu_obj.name, num))
python = Course('Python', '6month', 21000) # 课程 六个月 学费
stu1 = Student('kid', 18, 'male') # 使用继承派生出自己的属性
stu1.choose_course(python) # 组合选课程
tea1 = Teacher('qz', 30, 'male', python)
tea1.performance(stu1, 85)
print(tea1.teach.course_name) # 组合
3.多态性
多态指的是在子类中复写父类的方法。
这样做的好处是:同样名称的方法在不同的子类中会有不同的行为。但是它们有相同的特征,可以使用相同的方法来访问它们。
class Animal():
def talk(self):
print('嘿嘿')
class Cat(Animal):
def talk(self):
print('喵')
class Dog(Animal):
def talk(self):
print('汪')
class Duck(Animal):
def talk(self):
print('噶')
cat = Cat()
dog = Dog()
duck = Duck()
cat.talk()
dog.talk()
duck.talk()
3.1多态性
把对象的使用方法统一,做为接口,调用一个接口函数,传入不同的参数,可以达到不同的功能,一个接口多种实现。
# 多态性应用
class Animal():
def talk(self):
print('嘿嘿')
class Cat(Animal):
def talk(self):
print('喵')
class Dog(Animal):
def talk(self):
print('汪')
class Duck(Animal):
def talk(self):
print('噶')
def talk(obj):
obj.talk()
cat = Cat()
dog = Dog()
duck = Duck()
talk(cat)
talk(dog)
talk(duck)
Python中一切皆对象,本身就支持多态性。
'sasada'.__len__()
{'k1': 1}.__len__()
[1, 2, 3].__len__()
len('sasada')
len({'k1': 1})
len([1, 2, 3])
多态性的本质在不同的类中定义有相同的方法名称,可以在父类中限制子类中必须有某些方法名称实现相对应的功能。
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 装饰器现在子类中必须定义talk方法。
def talk(self): # 抽象方法,功能自己写去吧,我不管。
pass
class Cat(Animal):
pass
cat = Cat() # Cat类中没有talk方法直接报错。
class Cat(Animal):
def talk(self): # 符合父类的要求
print('喵')
cat = Cat()
4.鸭子类型
Python崇尚鸭子类型,如果看起来像,叫声也像,走路也像鸭子,那么他就是鸭子。
对接口函数,传入不同的参数,只要这个参数中有相同的属性即可。
class Animal:
def talk(self):
print('嘿嘿')
class Cat(Animal):
def talk(self):
print('喵')
class Dog(Animal):
def talk(self):
print('汪')
class Duck(Animal):
def talk(self):
print('噶')
class Phone(object): # 我做鸭子了
def talk(self):
print('支付宝到账100块')
def talk(obj):
obj.talk()
cat = Cat()
dog = Dog()
duck = Duck()
phone = Phone()
talk(cat)
talk(dog)
talk(duck)
talk(phone)
使用一个talk()函数来访问Animal子类的相同方法,但对函数来说传入的值不管是什么,只要有它内部执行的这个方法即可。它不依赖继承关系,只要这样对象看起来像鸭子,走起来像鸭子就可以把它当作鸭子。