Python基础 ( 十 ) —— 面向对象(多态、封装、反射、动态导入)
#面向对象的三大特性
1 继承(上一章的内容)
2 多态
python本身就是多态的
3 封装
# 多态
#不同类的实例化对象,调用同一个方法(执行的逻辑不同),而不用考虑他们具体的类,例如:
字符对象s和列表对象l都调用了同一个__len__的方法(都继承于他们的父类即str和list),却不需要考虑他们属于不同类
s = str(111) #相当于str这个类将数字1传入,实例化出来一个字符串对象 l = list('abc') #相当于list这个类将'abc'传入,实例化出来一个列表对象 len(s) #相当于字符对象s调用了字符类下的一个__len__的方法,即s.__len__() print(s.__len__()) len(l) #同理 print(l.__len__()) print(dir(str)) #里面有__len__print(dir(list)) #里面有__len__
#其实len函数相当于
def len(obj) :obj.__len__()
#多态反应的是一个执行时候的状态
#再举一个例子加深理解
class H20 :def __init__(self,temperature):self.temperature = temperaturedef trans(self):if self.temperature < 0 :print('freezing')if self.temperature > 0 and self.temperature < 100 :print('flowing')if self.temperature > 100 :print('boiling') class liquid(H20):pass class solid(H20) :pass s1 = liquid(110) s2 = liquid(20) s1.trans() #都调用了同一种方法,却属于不同类 s2.trans() def trans(obj) : #其实这里定义了这个函数,才叫真正的多态。当你不调用时,没差别;而当你调用这个函数时,不管是什么类实例化出来的对象,都能执行同一套方法。obj.trans() trans(s1) trans(s2)
到此,我们也就明白到底什么是多态了:不同子类继承了父类的共同的函数属性,并且不同子类实例化出来的不同对象都调用父类的函数属性,这种动态的过程,就叫做多态。其实多态的基础就是就是继承,就是一种继承的体现方式。
换句话说,继承解决的是代码重用的问题,而把这个优势体现出来的方式就叫做多态,即父类定义的函数,要考虑到多个子类的继承问题(需要是有意义的)
#封装
#封装是一种思想(本质就是要区别内外,内部就是类里面,外部就是调用者;外部调用者无需知道内部逻辑),装就是把东西都放到一个袋子里,封就是把袋子封口,将东西隐藏起来,也就是定义一个类,往里面定义数据属性和函数属性,这就叫装(装到了__dict__里)
#那么什么是封呢?
(类中定义私有的,只想让其在类内部被访问,外部不需访问,但需要给外部定义一个接口函数,用于外部访问内部)
1 在一个py文件里定义的类,由其他py文件调用,其实就已经有隐藏的含义了,调用者并不知道其内部逻辑,只需要用就行
2 通过python约定俗成的命名方法来命名,达到隐藏的效果:
3 为封装到内部的逻辑提供一个外部访问的接口
# _开头的变量如 _abc 代表这个属性不该被外部调用者调用
class A :_b = '你不该在外部调用这个数据属性'def __init__(self):pass a = A() print(a._b) #还是能调用到这个_b,因为这只是文字上的约束,python并没有内部逻辑帮你阻止调用#但你看到_开头的就要明白,这个属性是不该被你调用的
#__开头的变量如__abc (__abc__这样末尾有__的不算),python会给你自动重命名为_类名__abc
class A :__b = '你调用不到我,会报错'def __init__(self):print('但我可以在这里调',self.__b)def C(self): #接口函数(访问函数)print(self.__b,'内部就能调用') a = A() # print(a.__b) #调用不到__b,会报错 ,因为以及被python自动重命名为_A__b了,可以在__dict__中找到 print(A.__dict__) print(a._A__b) a.C() #外部调用者通过调用接口函数,访问到了在内部被封装的属性
#注意事项:
要把什么变量做成私有的需要深思熟虑(不然后期只能通过不断的添加接口函数来弥补,在一个项目里把私有的变量名再改回去是不现实的)
#来几个真正封装的例子
class cal_area :def __init__(self,name,width,length):self.name = nameself.__width = widthself.__length = lengthdef result(self):print('%s的面积为%s平方米' %(self.name,self.__length*self.__width))def port(self):return self.__width,self.__length s = cal_area('home',100,100) s.result() print(s.port()) #没法直接调用内部私有的__width和__length,只能通过新写的接口函数(也叫访问函数)来调用
#反射(又称自省)
#主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
四个可以实现反射的函数(适用于类和对象):
hasattr(object,name):判断对象中有没有一个叫做name的方法或属性(数据属性或函数属性),
或者换句话说,能不能调用到name的方法或属性,返回bool值. 注意name是个字符串!
a = 'abc' print(hasattr(a,'__len__')) #可以传入实例化对象 print(hasattr(str,'__len__')) #也可以传入一个类 class A:def __init__(self,name):self.__name = namedef __test(self):pass print(hasattr(A,'__test')) #hasattr检测的是能被调用的方法或属性,这里做了封装所以没找到
getattr(object,name,default=None):获取对象或者类中能被调用的方法或者属性
a = 'abc' b = getattr(a,'__len__') #在实例化对象a中,获取到叫做'__len__'的属性,并且可以调用.(没有则会报错) d = getattr(a,'adflkj','如果找不到,得到这里的值') #这样写找不到也不会报错 e = getattr(a,'adsf',default=None) print(b()) print(d) c = getattr(str,'__len__') print(c(a)) #其实getattr(object,name)就等于object.name
setattr(object,key,value):给对象或类设置方法或属性
class A:def __init__(self,name):self.name = namedef test(self):pass a = A('abc') setattr(a,'name0','ssy') print(a.__dict__) #相当于直接 a.name = 'alex' print(a.__dict__) #也可传入函数属性 def test(self) :print(self.name) setattr(A,'test',test) a.test()
delattr(object,key):删除对象或类的属性或方法,相当于 del A.key
class A:def __init__(self,name):self.name = namedef test(self):pass a = A('abc') delattr(a,'name') #相当于直接 del a.name print(a.__dict__)
#反射的好处:
当多人开发一个项目时候,你需要调用别人负责实现的的类,但是对方没实现,甚至都没定义这时候怎么办?
难道要等到他实现了通知你,你才开始写代码么?这时候就可以用hasattr来进行一个判断
from XXX import A a = A('abc') #调用别人的类来实例化 if hasattr(a,'你要调用的方法') :b = getattr(a,'你要调用的方法')b() #运行调用的方法 #如果不存在,就接着下面的逻辑
这样,当你调用的类不存在时,就跳过;存在的时候即调用;你这段调用的代码其实就已经写好了,不论这个类有没有被实现。
换句话说就是你不用等别人实现这个类,再回过头来写这个调用逻辑了。
#动态导入
#以一个字符串的名字的形式导入模块
#动态导入,可以导入字符串名字的模块。但是无论你调用多少层,总是获取最顶层 a = __import__('module_test.bin') #导入相当于执行了一遍文件. print(a) #获取的不是你导入的最低层bin,而是顶层module_test a.bin.test() #所以得这么才能调用到,但是为了能调用到,__import__里还是得写到最低层,即'module_test.bin' #导入的过程相当于执行了一次文件,下面拿以前的导入方式来距离 from module_test import bin bin.test() #bin下定义的函数得通过bin这个类调用,不能直接test() #或者直接把模块里的所有东西导入到当前,那就可以直接test()调用了 from module_test.bin import * # * 跟linux里的通配符一个意思 test() #但是这种用*的方法没法导入_开头的函数 _test() #没找到这个函数 #不过python没有在真正逻辑层面上限制你调用,你可以这么调_test from module_test.bin import test,_test _test() #或者用__import__调用也可以 a.bin._test()#另一种更好的方法动态导入 import importlib a = importlib.import_module('module_test.bin') a.test() a._test()
#为什么这里要讲动态导入呢?因为动态导入就是基于反射做的。而模块其实就是一个类
比如 importlib.import_module('module_test.bin'),相当于从importlib这个类里找到一个import_module方法;
这个方法能从当前类(文件夹就是一个类)下找到module_test这个类,再从中找到bin这个类
这也就解释了为什么pycharm创建文件夹的时候,会生成一个__init__的文件,并且自动执行,其实它就是用来实例化出对象(文件夹里的文件)的
# __getattr__ 、 __setattr__ 、 __delattr__
(注意:形如 __XXX__ 都是类的内置方法,当不自己设置__XXX__的时候用内置的,设置跟他名字一样的__XXX__则用你设置的)
(常用)#__getattr__ : 当对象或类调用不存在的方法时,会自动运行类下的__getattr__方法 (如果不像下面自己设置__getattr__则调用内置的结果是输出报错信息到屏幕)
(不常用)#__delattr__: 类或对象在删除属性时,会自动运行__delattr__
(不常用)#__setattr__: 类或对象在设置属性时,会自动运行__setattr__
class Foo :name = 'abc'def __init__(self,x):self.x = xdef __getattr__(self, item):print('__getattr__被执行')def __delattr__(self, item):print("__delattr__被执行")def __setattr__(self, key, value):print("__setattr__被执行")# self.key = value #不能这么设置属性,因为这里一设置又会触发__setattr__的执行,然后再设置,无限循环self.__dict__[key] = value #这样设置才对 a = Foo(1) a.adfdaf #类或对象调用不存在的属性时,会自动运行__getattr__ del a.name #类或对象在删除属性时,会自动运行__delattr__ a.name1 = 'cba' #触发__setattr__
转载于:https://www.cnblogs.com/Matrixssy/p/10911952.html
Python基础 ( 十 ) —— 面向对象(多态、封装、反射、动态导入)相关推荐
- python基础(面向对象(封装、私有化封装))
封装 封装(encapsulation)指的是向外部隐藏不必要的细节.这听起来有点像多态(无需知道对象的内部细节就可使用它).这两个概念很像,因为它们都是抽象的原则.它们都像函数一样,可帮助你处理程序 ...
- Python基础十五:面向对象编程四:高级特性
Python基础十五:面向对象编程四:高级特性 Python基础系列内容为学习廖雪峰老师Python3教程的记录,廖雪峰老师官网地址:廖雪峰Python3教程 Author:yooongchun Em ...
- 【Python基础】面向对象封装 案例(二)
目录 案例二 1.首先开发 枪类 2.接着开发 士兵类 3.开发 开火类. 案例一在这里: [Python基础]面向对象封装 案例(一) 案例二 仍然是一步一步开发.同时,下面的第3小步是完整代码,亦 ...
- Python成长之路【第九篇】:Python基础之面向对象
一.三大编程范式 正本清源一:有人说,函数式编程就是用函数编程–>错误1 编程范式即编程的方法论,标识一种编程风格 大家学习了基本的Python语法后,大家就可以写Python代码了,然后每个人 ...
- (转)Python成长之路【第九篇】:Python基础之面向对象
一.三大编程范式 正本清源一:有人说,函数式编程就是用函数编程-->错误1 编程范式即编程的方法论,标识一种编程风格 大家学习了基本的Python语法后,大家就可以写Python代码了,然后每个 ...
- 5.Python基础之面向对象
文章目录 Python基础之面向对象 面向对象的三大特性 类和对象的关系 类的组成 类的书写规则 实例化对象 检测类和对象的成员 类和对象成员的操作 类成员操作 对象成员操作 关于self 封装特性 ...
- python基础之面向对象编程
python基础之面向对象编程 面向对象编程思想 面向对象是一门编程思想,编程思想仅仅是一门思想,与任何技术无关 核心是对象两字,对象可以理解为特征与技能的结合体 基于该编程思想编写程序,就好比创造世 ...
- Python基础_07_面向对象1
python基础7_面向对象1 文章目录 python基础7_面向对象1 一.面向对象:类和对象.魔法方法 1. 面向对象编程概述 1.1[了解]面向过程和面向对象的区别 1.2[知道]类和对象介绍 ...
- Python基础十九:多进程
Python基础十九:多进程 Python基础系列内容为学习廖雪峰老师Python3教程的记录,廖雪峰老师官网地址:廖雪峰Python3教程 Author:yooongchun Email:yooon ...
最新文章
- 基于 Android NDK 的学习之旅-----资源释放
- JS中IE与W3C不同的地方
- java 根据类名示例化类_如何使用示例从Java中的类路径加载资源
- 数组copyWithin()方法以及JavaScript中的示例
- 视频过大怎么压缩变小
- 微信小程序开发入门与实践
- iSpiik产品说:谈谈小程序直播-数据背后几个思考
- 头条白板面试_让我们谈谈白板面试和可能的替代方法
- Client can't access Jboss server, the port is not accessable.
- 行为识别阅读笔记(paper + parted code):Beyond Frame-level CNN Saliency-Aware 3-D CNN with LSTM for Video Acti
- 3、微信小程序-通信
- 在Windows上挂载磁盘为非445端口的SAMBA服务(原创)
- 优盘复制进来为空_为什么复制后文件夹u磁盘为空
- 数学知识整理:二重积分
- 【历史上的今天】10 月 6 日:互联网先驱诞生日;莲花公司宣布上市
- 贪心之最大相容子集合问题
- docker ——安装tomcat
- 关于大一新生的一些话
- 我认为这种计算机卖的很好英语翻译,英语翻译
- C#读写调整UVC摄像头画面-饱和度
热门文章
- Elasticseach 从零开始学习记录(一) - 单实例环境搭建
- 为制造业构建Teams Power App 3:创建制造商UI
- (四)训练用于口罩检测的YOLOv5模型
- 微软推出新编程语言 Bosque,超越结构化程序设计
- 在IIS中调试ASP.NET Core应用程序
- ajax jinja,在向Flask发出jQuery AJAX请求后渲染Jinja
- 前端悬浮窗效果_web前端入门到实战:css过渡和动画解析文
- 如何访问云端的tcpserver_Swoole: TcpServer+SocketServer+EMQTT组合,实现基础设备控制
- bootstrap表单拖拽生成器插件_web前端常用插件、工具类库汇总,新手必收藏!!!...
- python函数的内涵_python内涵段子文章爬取