210225课 类的继承
继承
1,继承的定义
让子类直接拥有父类的属性和方法的过程
**子类;**继承者
**父类:**被继承者,又称 超类
2,继承方法
class 子类(父类)
pass
**注意:**如果没有添加括号,默认继承基类object
一个子类可以同时拥有多个父类 class 子类(父类1,父类2,…)
Python中子类可以继承父类所有的属性和方法
class Person:
num = 61
def __init__(self):
self.name = '小红'
self.age = 18
self.sex = '女'
def eat(self, food):
print(f'{self.name}在吃{food}')
# 类方法
@classmethod
def show_num(cls):
print('人类的数量:', cls.num)
# 静态方法
@staticmethod
def info():
print('人类破坏环境!')
class Student(Person):
pass
stu1 = Student()
print(stu1.age, stu1.name, stu1.sex)
# 18 小红 女
print(Student.num)
# 61
stu1.eat('包子')
# 小红在吃包子
Student.show_num()
# 人类的数量: 61
Student.info()
# 人类破坏环境!
子类重写
1,在子类中添加属性和方法
1)添加类属性
直接在子类中定义新的类属性即可
2)重写: 在子类中可以添加跟父类相同的方法
调用:各用各的重写部分时直接调用
既用重写又用父类方法时,通过 super().方法 来调用 (静态方法除外)
总结:super的用法
super().方法() 直接调用当前父类的制定方法
super(类,对象).方法()
调用指定类的父类的制定方法(要求对象必须是前面类的对象
3)添加对象属性
在子类的 _ _ init _ _ 方法中通过super()去调用父类的 _ _ init _ _
class A:
x = 100
@staticmethod
def func1():
print('A')
@classmethod
def funca(cls):
print('A1')
def func4(self):
print('A的对象方法1')
def func5(self):
print('A的对象方法2')
class B(A):
y = 20
@classmethod
def func2(cls):
print('B')
@staticmethod
def func1():
print('BB')
@classmethod
def funca(cls):
super().funca()
"""cls.__base__.funca()"""
print('B2')
def func4(self):
super().func4()
super().func5()
print('B的对象方法')
@staticmethod
def func3():
# super().func1() # 报错
super(B, B()).func1()
print('B的静态')
class C(B):
pass
print(A.x) # 100
print(B.x) # 100
print(C.x) # 100
print(B.y) # 20
# print(A.y)
print(C.y) # 20
B.func1() # BB
A.func1() # A
B.funca() # A1 B2
b = B()
b.func4() # A的对象方法1 A的对象方法2 B的对象方法
B.func3() # A B的静态
class X:
def fx(self):
print('x')
class Y(X):
def fy(self):
super().fx()
"""super(Y, self).fx()"""
print('y')
def f(self):
super().fx()
super(N, N()).fm()
class M:
def fm(self):
print('m')
class N(M):
def fn(self):
print('n')
x = X()
y = Y()
y.fy() # x y
y.f() # x m
print('================================================')
class Animal:
def __init__(self):
self.age = 0
self.gender = '雌'
class Cat(Animal):
def __init__(self):
super().__init__()
self.color = '白色'
self.price = 2000
self.breed = '野猫'
pass
cat = Cat()
print(cat.age, cat.gender) # 0 雌
print(cat.color) # 白色
对象属性的添加问题
class A:
def __init__(self, a, b=10):
# a = 200, b=10
self.a = a # 200
self.b = b # 10
self.c = 0 # 0
class B(A):
def __init__(self, d, a):
# d = 100, a = 200
# super().__init__(100)
super(B, self).__init__(a) # A: __init__(200)
self.d = d # 100
bb = B(100, 200) # B: __init__(100, 200)
print(bb.a, bb.b, bb.c, bb.d)
# 200 10 0 100
'''练习:
创建一个人类有属性:姓名、年龄、性别,
要求创建人的对象的时候姓名和年龄必须赋值,
性别可以赋值也可以不赋(默认是男)
创建学生类有属性:姓名、年龄、性别、学号、学分和电话,
要求创建学生对象的时候,姓名和电话必须赋值。
年龄和性别可以赋值也可以不赋(默认是18和年),
学分和学号创建的时候不能赋值,默认值分别是'000'和0
'''
class Person:
def __init__(self, name, age, gender='男'):
self.name = name
self.age = age
self.gender = gender
class Students(Person):
def __init__(self, name, tel, age=18, gender='男'):
super(Students, self).__init__(name, age, gender)
self.study_id = '007'
self.score = 0
self.tel = tel
p = Person('小明', 18)
stu = Students('小红', '1110', 20, '女')
print(stu) # <__main__.Students object at 0x000000000255B160>
多继承
多继承时子类可以继承所有父类的类属性和方法,
但是只能继承第一个父类的对象属性
_ _ mro _ _ 模型 适用于多继承(了解)
class Animal:
num = 61
def __init__(self):
self.age = 0
self.gender = '雄'
@classmethod
def show(cls):
print('数量:', cls.num)
class Fly:
name = '飞行器'
def __init__(self):
self.height = 100
self.time = 3
@staticmethod
def message():
print('飞行器')
class Bird(Fly, Animal):
pass
print(Bird.num, Bird.name)
Bird.show()
Bird.message()
b = Bird()
# print(b.age, b.gender)
print(b.height, b.time)
私有化
访问权限:
1)公开的:在类的内部和外部都可以使用和被继承
(Python中所有的属性都是公开的)
2)保护的:在类的内部可以使用和被继承
3)私有的:在类的内部使用,不能被继承
在Python的类里面的属性名或方法名命名前加2个下划线__
即可使属性或方法私有化
Python的私有化是个伪概念,加2个下划线相当于更换了一个存储位置
相当于在2个下划线开头加’_类名’,
如果想被继承,在前面加 _类名 即可. 本质还是公开的
class A:
num = 100
__x = 200 # __x是私有的
def __init__(self):
self.name = '小明'
self.__age = 18 # __age是私有的
def info(self):
print('信息:', self.__age)
self.__f1()
@classmethod
def show(cls):
print(cls.num, cls.__x)
def __f1(self):
print('对象方法')
print(A.num)
A.show()
# print(A.__x)
a = A()
print(a.name)
# print(a.__age)
a.info()
# a.__f1()
print(a.__dict__) # {'name': '小明', '_A__age': 18}
print(a._A__age) # 18
拷贝
浅拷贝和深拷贝
**相同点:**都会复制被拷贝的对象,产生新的对象,然后用新的对象来赋值
**不同点:**如果被拷贝的对象有子类,浅拷贝只复制父类,深拷贝都拷贝
# 导入copy模块
from copy import copy, deepcopy
class Dog:
def __init__(self):
self.name = '旺财'
self.gender = '公狗'
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]},id:{id(self)}>'
class Person:
def __init__(self, name, age=18, gender='女'):
self.name = name
self.age = age
self.gender = gender
self.dog = Dog()
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>'
p1 = Person('小明', 20, '男')
p2 = p1 # 直接赋值,将p1中的地址赋给p2
p3 = copy(p1) # 浅拷贝。复制p1产生一个新的对象,用新对象给p3赋值
p4 = deepcopy(p1) # 深拷贝。复制p1产生一个新的对象,用新对象给p4赋值
print('原数据:', p1)
print('直接赋值:', p2)
print('浅拷贝:', p3)
print('深拷贝:', p4)
print('=================================')
p1.name = '小花'
p1.dog.gender = '母狗'
print('原数据:', p1)
print('直接赋值:', p2)
print('浅拷贝:', p3)
print('深拷贝:', p4)
# 练习:
A = [10, 20, 30, ['abc', '123']]
B = A
C = copy(A)
D = deepcopy(A)
A.append(100) # A=[10, 20, 30, ['abc', '123'], 100]
A[3].pop() # A=[10, 20, 30, ['abc'], 100]
print(B) # [10, 20, 30, ['abc'], 100]
print(C) # [10, 20, 30, ['abc']]
print(D) # [10, 20, 30, ['abc', '123']]
内存管理
内存管理分为内存的开辟和释放
1,内存的开辟 使用数据时在堆里面申请内存,值与栈里的名字相对应
Python中所有的类型都是类,所有数据都是对象,所有数据都保存在堆里面
堆在保存数据时对于相同的不可变数据,只保存一份
对于相同的可变数据,保存多份
2,内存的释放 垃圾回收机制
Python中内存的某个数据是否释放,看这个数据在程序中的引用个数
大于0,不会被销毁,反之会被销毁
print(type(10))
a = 100
age = 100
list1 = [100, 200]
print(id(a), id(age), id(list1[0]))
a = [10, 20]
b = [10, 20]
c = [100, [10, 20]]
print(id(a), id(b), id(c[-1]))
A = 100
del A
# B = A # NameError: name 'A' is not defined