Python中类支持继承,并且支持多继承
一、继承
1、什么是继承
父类(超类):被继承的类
子类:继承父类的类
继承就是让子类拥有父类的属性和方法,但父类的属性和方法不发生减少和改变
Python中所有的类都是直接或间接的继承自object
2、怎么继承
class 类名(父类):
class 类名:== class 类名(object):
3、能继承哪些东西
对象属性、对象方法、类的字段、类方法、静态方法都可以继承
注意:
如果当前类设置了slots方法,会约束当前类的对象属性,会导致当前类对象无法添加除slots方法包含属性的以外属性,
其dict方法返回的字典中只包含slots方法中的属性。
如果父类设置了slots方法,不会约束到子类的对象属性和添加,
但是会导致子类对象的dict方法返回属性只有除dict方法包含属性的以外属性
class Person:
num=67
__slots__ = ('age') #__slots__魔法方法,只允许该类的对象属性含有‘age’
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self,food):
print('%s吃%s'%(self.name,food))
@classmethod
def show_num(cls):
print("人类数量:%d亿" %cls.num)
@staticmethod
def func1():
print("静态方法")
class Student(Person):
def score(self,score):
self.score=score
return self.score
# p1=Person('老王',65) #AttributeError: 'Person' object has no attribute 'name',父类__slots__方法里包含age
# print(p1.__dict__)
stu1=Student('小明',12) #添加name和age属性 子类能添加name属性
stu1.score(65) #添加score属性
print(stu1.__dict__)#{'name': '小明', 'score': 65} 返回字典中无age属性,父类__slots__方法里包含age
stu1.eat("瓦萨比")
print(stu1.num)
stu1.show_num()
stu1.func1()
二、重写
继承后,子类会拥有父类的属性和方法,也可以添加属于自己的属性和方法
1、添加新方法
直接在子类中声明的新方法只能通过子类来使用
class Person:
num=13
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self,food):
print('%s吃%s'%(self.name,food))
@classmethod
def get_up(cls):
print("%d亿人起床了" %cls.num)
@staticmethod
def run():
print("人在跑步")
class Student(Person):
new_num=3
def study(self):
print('%s学习努力'%self.name)
@staticmethod #静态方法
def run(): #完全重写了run()方法,子类调用的是此方法,父类不变
print("学生在跑步")
@classmethod #类方法
def get_up(cls): #部分重写get_up()方法,调用父类的功能,同时新增子类的功能
super().get_up() # 调用父类对应方法的功能
print("%d亿学生也起床了" %cls.new_num) #新写的功能
# stu1=Person('小花',23)
# stu1.study() #AttributeError: 'Person' object has no attribute 'study'
stu2=Student('小花',23)
stu2.study()
2、重写
a、子类继承父类的方法,在子类中去重新实现这个方法的功能——》完全重写
b、在子类方法中通过 super().父类方法 去调用父类对应方法的功能——》部分重写
p1=Person('老王',56)
p1.run() #人在跑步
p1.get_up() #13亿人起床了
stu3=Student('小王',17)
stu3.run() #学生在跑步
stu3.get_up() #13亿人起床了
#3亿学生也起床了
3、类中方法的调用过程
类.方法(),对象.方法()
先看当前类是否有这个方法,如果有就直接调用当前类的相应方法;
如果当前类没有这个方法,就会去父类中查找,如果有就调用父类的相应方法;
如果父类没有这个方法,就去父类的父类中找,依次类推直到找到为止;
如果找到基类object还没找到相应方法,程序才会崩溃
4、添加属性
(1)添加字段
直接在子类中声明新的字段
(2)添加属性
子类是通过继承父类的init方法来继承父类的对象属性
class Car:
num=10
def __init__(self,color='red'):
self.color=color
class SportCar(Car):
num=6 #修改父类字段默认值
wheel_num=4 #添加新字段
def __init__(self,color,price):
super().__init__(color) #调用父类init方法,并给color属性传参
self.price=price
print(Car.num)
print(SportCar.num,SportCar.wheel_num)
car1=Car()
spcar1=SportCar('white',5000)
print(car1.__dict__)
print(spcar1.__dict__)
练习:
声明一个Person类,有属性名字、年龄和身份证号码。
要求创建Person的对象的时候,必须给名字赋值,年龄和省份证可以赋值也可以不赋
声明一个学生类,有属性名字、年龄、身份证号码和学号,成绩(用继承)
要求创建学生的时候,必须给学号赋值,可以给年龄,名字赋值,不能给省份证号,和成绩赋值
print('======================')
class Person:
def __init__(self,name,age=20,person_id=123456):
self.name=name
self.age=age
self.person_id=person_id
class Student(Person):
def __init__(self,stu_id,name='lw',age=12):
super().__init__(name,age)
self.stu_id=stu_id
self.score=60
p1=Person('xm')
stu1=Student(1)
print(p1.__dict__)
print(stu1.__dict__)
print('======================')
三、重载
运算符重载:通过实现类相应的魔法方法,来让类的对象支持相应的运算符
10>20 #int类,实现 > 对应的魔法方法 gt ;实现 < 对应的魔法方法lt
class Student:
def __init__(self,name,age,score):
self.name=name
self.age=age
self.score=score
def __gt__(self, other): # >对应的魔法方法
#self指的是>符号前面的值,other指的是>符号后面的值
return self>other
def __lt__(self, other): # <对应的魔法方法
#self指的是<符号前面的值,other指的是<符号后面的值
return self<other
def __mul__(self, other): #* 对应的魔法方法
result=[]
for _ in range(other):
result.append(self)
return result
def __repr__(self):
return str(self.__dict__)
stu1=Student('aa',18,87)
stu2=Student('bb',17,80)
print(stu1.age > stu2.age) #True
print(stu1.score<stu2.score) #False
print(stu1*3) #[{'name': 'aa', 'age': 18, 'score': 87}, {'name': 'aa', 'age': 18, 'score': 87}, {'name': 'aa', 'age': 18, 'score': 87}]
四、内存管理机制
Python中的内存管理——》自动管理——》垃圾回收机制
内存结构中分栈区间和堆区间,栈区间中内存是系统自动开启自动释放。堆区间的内存需要手动申请手动释放。
目前绝大多数编程语言,都提供了一套属于自己的关于堆中的内存的管理方案——》Python中垃圾回收机制是用来管理堆中的内存的释放
Python中的数据都是存在堆中的,数据的地址都是在栈区间。(堆数据,栈地址)
1、内存开辟
Python中将值赋给变量时,会先在堆中开辟空间将数据存储起来,然后将数据对应的地址赋值给栈区间的变量。
但如果数据是数字(int或者float)和字符串(str),会先在缓存区查看这个数据之前是否已经创建过,
如果没有就去开辟空间存储数据,返回数据地址给变量;如果之前创建过这个数据就会直接将这个数据的地址返回给变量
2、内存释放——》垃圾回收机制
系统每个一段时间,就会去检测当前程序中所有的对象的引用计数值是否为0,如果对象的引用计数是0,对象对应的内存就会被销毁。
每个对象都有引用计数属性,用来存储当前对象被引用的次数。可以通过sys模块中的getrefcount去获取一个对象的引用计数值。
(1)增加引用计数次数——》
(2)减少引用计数次数——》删除储存对象地址的变量;修改存储对象地址变量的值
from sys import getrefcount
a=[1,2,3,4,5,6]
b=a
d=a.copy()
c=[a,b]
print(getrefcount(a)) #5 4+1
print(getrefcount(d)) #2 1+1
网友评论