当前位置: 首页 > news >正文

从零开始的python学习(八)P115+P116+P117+P118+P119+P120+P121+P122

本文章记录观看B站python教程学习笔记和实践感悟,视频链接:【花了2万多买的Python教程全套,现在分享给大家,入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p=6&share_source=copy_web&vd_source=404581381724503685cb98601d6706fb

上节课学习两大编程思想-面向过程和面向对象,自定义类和创建自定义类的对象,类的组成,使用类模板创建N多个对象,动态绑定属性和方法,Python中的权限控制,属性的设置,本节课学习继承的概念,python中的多继承,方法重写,python中的多态,object类,对象的特殊方法,python中的特殊属性,类的深拷贝与浅拷贝。

1.继承的概念

class Person(): #默认继承了objectdef __init__(self, name, age):self.name = nameself.age = agedef show(self):print(f'大家好,我叫:{self.name},我今年:{self.age}岁')#Student继承Person类
class Student(Person):#编写初始化的方法def __init__(self, name, age, stuno):super().__init__(name, age) #super()表示调用父类的初始化方法,执行父类的__init__方法,给成员属性或者说是实例属性name和age去赋值self.stuno = stuno #学号stuno是父类没有的,因此需要单独赋值#Doctor继承Person类
class Doctor(Person):#编写初始化方法def __init__(self, name, age,department):super().__init__(name, age)self.department = department#目前为止Person有两个子类,一个是Student类,一个是Doctor类
#下面创建一个子类对象
stu=Student('艾伦耶格尔',20,'104')
stu.show()#这里直接执行就可以出现“大家好,我叫:艾伦耶格尔,我今年:20岁”
doctor=Doctor('韩吉',30,'军医')
doctor.show() #这里直接执行就可以出现“大家好,我叫:韩吉,我今年:30岁”,说明了子类只要继承了父类,那么这个歌子类就拥有了父类的公共的和受保护的成员

其中 super().__init__(属性1, 属性2)表示调用父类的初始化方法,执行父类的__init__方法,在这个实例中给成员属性或者说是实例属性name和age去赋值运行结果如下所示:

大家好,我叫:艾伦耶格尔,我今年:20岁
大家好,我叫:韩吉,我今年:30岁进程已结束,退出代码为 0

2.python中的多继承

上面我们学习了一个子类继承一个父类的,那么一个子类它也可以继承多个父类,只需要在小括号里面写入多个父类然后使用逗号隔开即可,这样的话这个子类就同时拥有了多个父类的公有的成员和受保护的成员。演示实例如下:

#多继承子类
class FatherA():def __init__(self,name):self.name=name #给实例属性赋值def showA(self):print('父类A中的方法')class FatherB():def __init__(self,age):self.age=agedef showB(self):print('父类B中的方法')
#多继承
class Son(FatherA,FatherB):def __init__(self,name,age,gender):#需要调用两个父类的初始化方法#super().__init__(属性1, 属性2)表示调用父类的初始化方法,但是需要指定哪一个父类FatherA.__init__(self,name)FatherB.__init__(self,age)self.gender=gender#子类实例
son=Son('芙宁娜','500','女') #调用Son类中的__init__执行
son.showA()
son.showB()

总而言之,在执行调用父类的对象和方法的时候,实际上就跳回父类定义的那些属性(局部变量)和方法然后输出结果。

3.方法重写

如图,假设在右图里面,老父亲父类给两个子类各自买了一套房子,也就是说这两个子类得到的房子是从父类那里继承过来的,但是得到房子以后,两个子类对于房子的装修风格可以是不一样的,这个就是方法的重写。它要求继承来的方法它的方法名要和父类的一样(都是“房子”),这就是继承;但是继承过来以后修改方法的方法体(需要各自“装修”),这就是方法体的重新编写(方法重写)。当然了,如果在子类中重写方法的时候还需要父类的内容,则可以使用super().xxx()来调用父类的方法。

对于继承了父类的方法,子类更多时候仅仅是继承了一个方法名,具体还得重新编写。优先调用子类的方法,如果子类没有规定重写内容才去用父类的方法体。

#方法重写
class Person(): #默认继承了objectdef __init__(self, name, age):self.name = nameself.age = agedef show(self):print(f'大家好,我叫:{self.name},我今年:{self.age}岁')#Student继承Person类
class Student(Person):#编写初始化的方法def __init__(self, name, age, stuno):super().__init__(name, age) #super()表示调用父类的初始化方法,执行父类的__init__方法,给成员属性或者说是实例属性name和age去赋值self.stuno = stuno #学号stuno是父类没有的,因此需要单独赋值def show(self):#调用父类中的方法super().show()#虽然调用的父类的方法,但是为了方便使用还是进行了添加重写print(f'我来自xxx大学,我的学号是{self.stuno}')
#Doctor继承Person类
class Doctor(Person):#编写初始化方法def __init__(self, name, age,department):super().__init__(name, age)self.department = departmentdef show(self):#super().show() #调用父类中的方法,然后重写自己独有的属性#直接不要父类的方法,而是完全重写了方法体print(f'大家好我叫:{self.name},我今年:{self.age}岁,我的工作科室是{self.department}')#目前为止Person有两个子类,一个是Student类,一个是Doctor类
#下面创建一个子类对象
stu=Student('艾伦耶格尔',20,'104')
stu.show()#如果父类和子类方法名一样,那么在调用这个方法的时候,会优先调用子类自己的show方法
doctor=Doctor('韩吉',30,'调查兵团')
doctor.show() #优先调用子类的方法

运行结果:

大家好,我叫:艾伦耶格尔,我今年:20岁
我来自xxx大学,我的学号是104
大家好我叫:韩吉,我今年:30岁,我的工作科室是调查兵团进程已结束,退出代码为 0

4.python中的多态

跟Java不一样,python只关心方法,Java是要求必须有继承做前提,而python没有这样的要求。

多态就是程序在运行当中动态地决定调用哪一个谈对象当中的方法,从而实现程序的可拓展性。

#多态
class Person():def eat(self): #前面讲了初始化方法是self.__init__(),这里没有使用初始化方法#只有有实例属性的时候在初始化方法中赋值;如果没有实例属性就可以不写初始化方法print('人吃五谷杂粮')class Cat():def eat(self):print('猫喜欢吃鱼')class Dog():def eat(self):print('狗喜欢啃骨头')#这三个类都有一个同名的方法
#编写函数
def fun(obj):#obj是函数的形式参数,在定义处不知道这个形参的数据类型obj.eat() #通过变量obj(对象)调用eat()方法#创建一个类的对象
per=Person()
cat=Cat()
dog=Dog()
#调用fun函数。在这里只有程序运行的时候才知道它属于的数据类型是什么(继承的什么类)
fun(per) #python中的多态,不关心对象是否有继承关系(以及数据类型),只关心对象是否具有同名方法
fun(cat)
fun(dog)

运行结果如下:

5.object类

在python中,如果一个类没有继承任何一个类的话,那么这个类就默认继承的是object类,也就是它是所有类的直接或者间接的父类。也就是说所有的类其实都有object类的属性和方法。

其中_new_()是由系统调用的,而且是创建对象时调用的。当创建对象时需要手动设置初始化方法,也就是_init_(),此时会先执行父类中的_new_()方法去创建对象开辟内存空间,然后再用_init_()给实例属性赋值。_str_()用于返回对象的一个描述信息。比如下面的示例中print(per)就会输出对象的内存地址,因为直接打印per就是自动调用str方法。当然我们也可以通过重新写str的方法,自己设计对象的描述信息。

下为简单示例方法有哪些。

#object类
class Person(): #这里虽然是空的,但是默认的是Person(object)def __init__(self, name, age):self.name = nameself.age = agedef show(self):print(f'大家好我是:{self.name}, 我今年:{self.age}')#创建Person类的对象
per=Person('空条承太郎',18) #创建对象的时候会自动调用__init__方法()
print(dir(per)) #内置函数dir可以查看对象所具有的属性或者方法print(per)

结果如下: 

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'show']
<__main__.Person object at 0x000002185319FFD0>进程已结束,退出代码为 0

下为示例如何重写str方法:

#object类有哪些方法
class Person(): #这里虽然是空的,但是默认的是Person(object)def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):return '这是一个人类,具有name和age两个实例属性' #返回值是一个字符串print('重写str前,执行print(per)结果为 <__main__.Person object at 0x000002185319FFD0>')
#创建Person类的对象
per=Person('空条承太郎',18) #创建对象的时候会自动调用__init__方法()
print(per) #此时输出的结果是“这是一个人类,具有name和age两个实例属性”

 此时执行str不会返回地址了:

6.对象的特殊方法

a=10
b=20
print(dir(a)) #python中的一切都是对象
print(a+b) #执行加法运算
print(a.__add__(b))
print(a.__sub__(b)) #执行减法运算
print(f'{a}<{b}吗?',a.__lt__(b))
print(f'{a}<={b}吗?',a.__le__(b))
print(f'{a}=={b}吗?',a.__eq__(b))
print('-'*40)
print(f'{a}>{b}吗?',a.__gt__(b))
print(f'{a}>={b}吗?',a.__ge__(b))
print(f'{a}!={b}吗?',a.__ne__(b))
#执行乘法运算
print('-'*40)
print(a.__mul__(b)) #乘法
print(a.__truediv__(b)) #除法
print(a.__mod__(b)) #求余数
print(a.__floordiv__(b)) #整除
print(a.__pow__(2)) #幂运算
print(a.__rshift__(b))

运行结果如下:


['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
30
30
-10
10<20吗? True
10<=20吗? True
10==20吗? False
----------------------------------------
10>20吗? False
10>=20吗? False
10!=20吗? True
----------------------------------------
200
0.5
10
0
100
0进程已结束,退出代码为 0

7.python中的特殊属性

class A:pass
class B:pass
class C(A,B):def __init__(self,name,age):self.name=nameself.age=age#创建类的对象
a=A()
b=B()
#创建C类对象
c=C('利威尔',30)
print('对象a的属性字典:',a.__dict__) #对象的属性字典
print('对象b的属性字典:',b.__dict__)
print('对象c的属性字典:',c.__dict__)print('对象a所属的类:',a.__class__)
print('对象b所属的类:',b.__class__)
print('对象c所属的类:',c.__class__)print('A类的父类元组:',A.__bases__)
print('B类的父类元组:',B.__bases__)
print('C类的父类元组:',C.__bases__) #运行结果是A类,如果继承了N多个父类,结果只是显示第一个继承的父类print('A类的父类:',A.__base__)
print('B类的父类:',B.__base__)
print('C类的父类:',C.__base__) #A类,如果继承了N多个父类,结果只显示第一个父类
#层次结构就是这个类它的父类都列出来,列完父类以后它的爷爷类也要列出来
print('A类的层次结构:',A.__mro__)
print('B类的层次结构:',B.__mro__)
print('C类的层次结构:',C.__mro__) #C类继承了A类B类间接继承了object类#subclasses方法可以得到子类列表(之前上面都是特殊属性)
print('A类的子类列表:',A.__subclasses__()) #A的子类有C类
print('B类的子类列表:',B.__subclasses__())
print('C类的子类列表:',C.__subclasses__()) #得到列表[]

运行结果如下: 

对象a的属性字典: {}
对象b的属性字典: {}
对象c的属性字典: {'name': '利威尔', 'age': 30}
对象a所属的类: <class '__main__.A'>
对象b所属的类: <class '__main__.B'>
对象c所属的类: <class '__main__.C'>
A类的父类元组: (<class 'object'>,)
B类的父类元组: (<class 'object'>,)
C类的父类元组: (<class '__main__.A'>, <class '__main__.B'>)
A类的父类: <class 'object'>
B类的父类: <class 'object'>
C类的父类: <class '__main__.A'>
A类的层次结构: (<class '__main__.A'>, <class 'object'>)
B类的层次结构: (<class '__main__.B'>, <class 'object'>)
C类的层次结构: (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
A类的子类列表: [<class '__main__.C'>]
B类的子类列表: [<class '__main__.C'>]
C类的子类列表: []进程已结束,退出代码为 0

8.类的深拷贝与浅拷贝

关于赋值和浅拷贝都是对子对象没有变化,因此源对象与拷贝对象都是引用一个子对象,两个的区别是后者是右创建了一个对象。

下面橘黄色的com3就是深拷贝的结果:

上图中赋值是深红色浅拷贝蓝色是浅拷贝,它们只是产生新的对象,而深拷贝不仅会产生新的对象,子对象也会重新创建。

#变量的赋值
class CPU():pass
class Disk():passclass Computer():#计算机由CPU和硬盘组成def __init__(self,cpu,disk):self.cpu=cpuself.disk=diskcpu=CPU() #创建了一个CPU对象
disk=Disk() #创建了一个硬盘对象
#创建一个计算机对象
com=Computer(cpu,disk) #分别传入一个cpu对象和硬盘对象
#变量(对象)的赋值
com1=com#此时如果输出print(com1)和print(com)就会发现内存地址是相同的
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com1,'子对象的内存地址:',com1.cpu,com1.disk)
#上面的结果是说明了两个对象指向了同一个对象,也就是com和com1都指向同一个computer对象#下面演示类对象的浅拷贝
print('-'*40)
import copy
com2=copy.copy(com) #com2是新产生的对象,com2的子对象,cpu和disk不变
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com2,'子对象的内存地址:',com2.cpu,com2.disk)
#下面演示类对象的深拷贝
print('-'*40)
com3=copy.deepcopy(com) #com3是新产生的对象,com3的子对象cpu和disk不变也会重新产生
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com2,'子对象的内存地址:',com2.cpu,com2.disk)

运行结果如下:

<__main__.Computer object at 0x00000290974D2F70> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>
<__main__.Computer object at 0x00000290974D2F70> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>
----------------------------------------
<__main__.Computer object at 0x00000290974D2F70> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>
<__main__.Computer object at 0x00000290974D2D60> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>
----------------------------------------
<__main__.Computer object at 0x00000290974D2F70> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>
<__main__.Computer object at 0x00000290974D2D60> 子对象的内存地址: <__main__.CPU object at 0x00000290974D2FD0> <__main__.Disk object at 0x00000290974D2FA0>进程已结束,退出代码为 0

本节完


文章转载自:
http://bucketful.kjawz.cn
http://characterisation.kjawz.cn
http://bvm.kjawz.cn
http://belief.kjawz.cn
http://antoinette.kjawz.cn
http://adept.kjawz.cn
http://athenian.kjawz.cn
http://affably.kjawz.cn
http://caravansary.kjawz.cn
http://aphotic.kjawz.cn
http://anticoagulate.kjawz.cn
http://anality.kjawz.cn
http://barnstorm.kjawz.cn
http://ardently.kjawz.cn
http://bedplate.kjawz.cn
http://chetrum.kjawz.cn
http://abgrenzung.kjawz.cn
http://absorb.kjawz.cn
http://araeostyle.kjawz.cn
http://actograph.kjawz.cn
http://alpage.kjawz.cn
http://adriamycin.kjawz.cn
http://annonaceous.kjawz.cn
http://agammaglobulinaemia.kjawz.cn
http://chagul.kjawz.cn
http://bipectinate.kjawz.cn
http://calculatedly.kjawz.cn
http://analytics.kjawz.cn
http://bedraggle.kjawz.cn
http://apoplectic.kjawz.cn
http://www.dtcms.com/a/280132.html

相关文章:

  • 部署本地大模型 Ollama + LLaMA3
  • Java基础(八):封装、继承、多态与关键字this、super详解
  • GPIO 输入/输出
  • GEO革命:当AI推荐成为新战场,传统SEO如何进化?
  • Linux基础学习---目录相关命令
  • 手机当路由,连接机器人和电脑
  • Typecho插件开发:实现文章字数统计与阅读时长计算功能
  • docker 方式gost代理搭建以及代理链实施
  • Android弹窗
  • uniapp中全局引入ronMounted, ref,watch onLoad,onShow等
  • Vim多列操作指南
  • docker-compose 配置启动2个MongoDB
  • SQL 常用版本语法概览:标准演进与关键语法分析
  • bat 批处理实现 FFmpeg 命令导出 mov 到 png 序列帧
  • 新版本PyCharm Conda环境设置 “找不到conda可执行文件”的解决
  • Git分支管理与工作流详解
  • 记录一条sql面试题2
  • MyBatis动态语法标签速查
  • Fastapi框架总览与核心架构
  • iOS App 上架工具选型与跨平台开发 iOS 上架流程优化实录
  • 深入探讨Hadoop YARN Federation:架构设计与实践应用
  • Datawhale AI数据分析 笔记
  • 2025开放原子开源生态大会 | openKylin的技术跃迁和全球协作
  • 回顾一下Docker的基本操作
  • Linux部署Python服务
  • 面向医疗AI场景的H20显卡算力组网方案
  • 2025开放原子开源生态大会 | 开源欧拉的AI原生实践与全球协作
  • 应用部署作业-02-流程
  • 第十四章 Stream API
  • 深度强化学习 | 图文详细推导深度确定性策略梯度DDPG算法