Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性
上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员、成员修饰符 面向对象的三大特性:继承、多态和封装,貌似今天内容挺多的,没有关系,慢慢来!
一、类中的基本知识:
一、类的成员、成员修饰符
一、字段
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
- 普通字段属于对象
- 静态字段属于类
- class Room:
- tag=1
- def __init__(self,name,owner,width,length,heigh):
- self.name=name
- self.owner=owner
- self.width=width
- self.length=length
- self.heigh=heigh
- r1=Room('厕所','sb',100,100,100000)
- print(r1.name) # 访问的是普通字段
- print(Room.tag) # #直接访问静态字段
so,通过上述例子可以看出:
- 静态字段在内存中只保存一份
- 普通字段在每个对象中都要保存一份(相当于绑定在每个实例化对象的身上,然后本身有一个类“指针”的东西指向类)
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段
二、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
- class Foo:
- def __init__(self, name):
- self.name = name
- def ord_func(self):
- """ 定义普通方法,至少有一个self参数 """
- # print self.name
- print ('普通方法')
- @classmethod
- def class_func(cls):
- """ 定义类方法,至少有一个cls参数 """
- print ('类方法')
- @staticmethod
- def static_func():
- """ 定义静态方法 ,无默认参数"""
- print ('静态方法')
- # 调用普通方法
- f = Foo('sb')
- f.ord_func()
- # # 调用类方法
- Foo.class_func()
- f.class_func()
- #
- # # 调用静态方法
- Foo.static_func()
- f.static_func()
类方法调用和静态方法调用的时候既可以使用使用类名调用,也可以使用对象来调用,区别在哪里呢?注意:最大的区别是用类名调用的时候是不需要实例化的,而使用对象来访问时是先要进行实例化,之后再进行调用。
三、属性
如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。
对于属性,有以下三个知识点:
- 属性的基本使用
- 属性的两种定义方式
- class Goods:
- @property
- def pricr(self):
- #print('nijiushidahbi')
- return "haishininiubi"
- obj = Goods()
- result = obj.pricr
- print(result)
- 显示结果:haishininiubi
由属性的定义和调用要注意一下几点:
- 定义时,在普通方法的基础上添加 @property 装饰器;
- 定义时,属性仅有一个self参数
- 调用时,无需括号
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回
二、面向对象编程的三大特性介绍
1.继承与派生
继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类。
python中类的继承分为:单继承和多继承
- class Grandfather:
- pass
- class Father(Grandfather): #单继承 Father是派生类,grandfather 是基类
- pass
- class son(Father,Grandfather): #多继承
- pass
继承使用产生的场景:如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时我们不可能从头开始写一个类B,这就用到了类的继承的概念。通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用。
除了继承与派生的概念还有一个概念是需要提出的那就是:组合。组合就是指在一个类中以另外一个类的对象作为数据属性,成为类的组合。
组合与继承两者到底什么的关系?1.继承的方式:通过继承建立了派生类与基类的关系,两者之间是“是”的关系。当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师 2.组合的方式:用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程(当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好)
- class School:
- def __init__(self,name,addr):
- self.name=name
- self.addr=addr
- def zhao_sheng(self):
- print('%s 正在招生' %self.name)
- class Course:
- def __init__(self,name,price,period,school):
- self.name=name
- self.price=price
- self.period=period
- self.school=school
- s1=School('北大','北京')
- c1=Course('linux',10,'1h',s1)
- print(c1.name) #linux
- print(c1.school) # <__main__.School object at 0x02182330>
- print(c1.school.name) # 北大
- print(c1.school.addr) # 北京
在这个例子中呢,创建了两个类,一个是学校类一个是课程类。需要将课程类与学校类进行相关联的时候,继承在这里是不合适的,那我们采用组合的方式来对这两个类进行关联,这样就在实例化一门课程的时候把学校的信息进行关联。
接口的概念:
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(解决代码重用,但是子类与基类出现强耦合)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。(推举使用)
归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
接口继承:就是定义一个父类,其主要目的就是所有的子类,必须去实现父类的方法(与是否省代码,么有半毛钱关系),父类可以不去具体实现,具体的实现由子类自己去实现。
举个例子:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样。
抽象类: 从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法(这种解释有点像接口了)
- #一切皆文件
- import abc #利用abc模块实现抽象类
- class All_file(metaclass=abc.ABCMeta):
- all_type='file'
- @abc.abstractmethod #定义抽象方法,无需实现功能
- def read(self):
- '子类必须定义读功能'
- pass
- @abc.abstractmethod #定义抽象方法,无需实现功能
- def write(self):
- '子类必须定义写功能'
- pass
- # class Txt(All_file):
- # pass
- #
- # t1=Txt() #报错,子类没有定义抽象方法
- class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
- def read(self):
- print('文本数据的读取方法')
- def write(self):
- print('文本数据的读取方法')
- class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
- def read(self):
- print('硬盘数据的读取方法')
- def write(self):
- print('硬盘数据的读取方法')
- class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
- def read(self):
- print('进程数据的读取方法')
- def write(self):
- print('进程数据的读取方法')
- wenbenwenjian=Txt()
- yingpanwenjian=Sata()
- jinchengwenjian=Process()
- #这样大家都是被归一化了,也就是一切皆文件的思想
- wenbenwenjian.read()
- yingpanwenjian.write()
- jinchengwenjian.read()
- print(wenbenwenjian.all_type)
- print(yingpanwenjian.all_type)
- print(jinchengwenjian.all_type)
继承实现的原理:(多继承,很多语言只支持单继承)
Python继承中有两种方式:一种是深度优先;另一种是广度优先;
当类是经典类时,多继承会按照深度优先方式查找;当类是新式类时,多继承会按照广度优先方式查找。注:当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
现在举个例子进行说明:
- class A(object):
- def test(self):
- print('from A')
- class B(A):
- def test(self):
- print('from B')
- class C(A):
- def test(self):
- print('from C')
- class D(B):
- def test(self):
- print('from D')
- class E(C):
- def test(self):
- print('from E')
- class F(D,E):
- # def test(self):
- # print('from F')
- pass
- f1=F()
- f1.test()
- print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
- #新式类继承顺序:F->D->B->E->C->A
- #经典类继承顺序:F->D->B->A->E->C
- #python3中统一都是新式类
- #pyhon2中才分新式类与经典类
在查找的过长中一旦找到查找过程就会立即中断,不会继续查找。
多继承的原理:(Python实现多继承的原理)
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如:
- F.mro() #等同于F.__mro__
- [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'objec
t'>]
子类调用父类方法的实现过程:子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法。
方法一:父类名.父类方法()
- class Vehicle: #定义交通工具类
- Country='China'
- def __init__(self,name,speed,load,power):
- self.name=name
- self.speed=speed
- self.load=load
- self.power=power
- def run(self):
- print('开动啦...')
- class Subway(Vehicle): #地铁
- def __init__(self,name,speed,load,power,line):
- Vehicle.__init__(self,name,speed,load,power) #子类继承父类
- self.line=line
- def run(self):
- print('地铁%s号线欢迎您' %self.line)
- Vehicle.run(self)
- line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
- line13.run()
- # 地铁13号线欢迎您
- 开动啦...
方法二:super()(推举使用此种方式)
- class Vehicle: #定义交通工具类
- Country='China'
- def __init__(self,name,speed,load,power):
- self.name=name
- self.speed=speed
- self.load=load
- self.power=power
- def run(self):
- print('开动啦...')
- class Subway(Vehicle): #地铁
- def __init__(self,name,speed,load,power,line):
- #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
- super().__init__(name,speed,load,power)
- self.line=line
- def run(self):
- print('地铁%s号线欢迎您' %self.line)
- super(Subway,self).run()
- class Mobike(Vehicle):#摩拜单车
- pass
- line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
- line13.run()
注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表。
2.多态(性)
多态是指一个事物有多中形态(一个抽象类有多个子类,so 多态的概念依赖于继承),而多态性是指:指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
多态是反映在执行时的状态,在面向对象中,多态是怎么来得呢?首先,先定义一个基类,再定义一堆子类。其次,才能展现不同的类实例化出的实例去调用同一个方法。
- class H2O:
- def __init__(self,name,temperature):
- self.name=name
- self.temperature=temperature
- def turn_ice(self):
- if self.temperature < 0:
- print('[%s]温度太低结冰了' %self.name)
- elif self.temperature > 0 and self.temperature < 100:
- print('[%s]液化成水' %self.name)
- elif self.temperature > 100:
- print('[%s]温度太高变成了水蒸气' %self.name)
- def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(self):
- pass
- class Water(H2O):
- pass
- class Ice(H2O):
- pass
- class Steam(H2O):
- pass
- w1=Water('水',25)
- i1=Ice('冰',-20)
- s1=Steam('蒸汽',3000)
- w1.turn_ice()
- i1.turn_ice()
- s1.turn_ice()
3.封装
装就是把东西包起来,而封的意思就是把口子封起来。为何要在编程的过程中使用这一特性呢?封装数据的作用就是为了保护隐私,而封装方法的作用就是为了隔离复杂程度。
封装其实是有两个层面的意思:
其一:第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装。(注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口)
其二:第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
在Python中,用双下划线来实现隐藏属性(设置成私有的),(类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式)
- class A:
- __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
- def __init__(self):
- self.__X=10 #变形为self._A__X
- def __foo(self): #变形为_A__foo
- print('from A')
- def bar(self):
- self.__foo() #只有在类内部才可以通过__foo的形式访问到.
- f1 = A()
- # f1.__foo() # 'A' object has no attribute '__foo'
- f1.bar() # 通过在对象A中创建一个接口,在内部调用私有方法
好了,今天就搞到这里,明天继续!!!
Python 基础 面向对象之二 三大特性的更多相关文章
- python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)
python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
- python基础——面向对象进阶
python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...
- python基础篇(二)
PYTHON基础篇(二) if:else,缩进 A:if的基础格式和缩进 B:循环判断 C:range()函数和len()函数 D:break,contiue和pass语句 for,while循环 函 ...
- java基础(三)-----java的三大特性之多态
面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 继承 ...
- java基础(一)-----java的三大特性之封装
面向对象编程有三大特性:封装.继承.多态.本文将介绍java的三大特性之封装 封装 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成 ...
- python基础扩展(二)
python基础扩展(二) 常用操作 1.startswith(以什么开始) endswith(y)什么结束 s='taiWanw39dd' print(s.startswith('t')) #意思是 ...
随机推荐
- Tensorflow-gpu在windows10上的安装(anaconda)
文档来源转载: http://blog.csdn.net/u010099080/article/details/53418159 http://blog.nitishmutha.com/tensorf ...
- Java学习笔记之基础语法(数据类型)
8种基本数据类型 整型: byte[1字节] short[2字节] int[4字节] long[8字节] 1,四种整型之间的区别:申 ...
- 渗透测试-基于白名单执行payload--Compiler
复现亮神课程 0x01 Compiler前言 说明:Microsoft.Workflow.Comiler.exe是.NET Framework默认自带的一个实用工具,用户能够以XOML工作流文件的形式 ...
- postman-windows下newman的使用
一.newman的安装 1.安装node.js下载https://nodejs.org/en/ C:\Users\iphauser>node -vv10.16.1C:\Users\iphause ...
- 百万年薪python之路 -- 带颜色的print
带颜色的print print输出带颜色的方法详解 书写格式: 开头部分:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m 注意:开头部分的三个参数:显示方式,前景色,背景色是可 ...
- 百万年薪python之路 -- 小数据池和代码块
1.小数据池和代码块 # 小数据池 -- 缓存机制(驻留机制) # == 判断两边内容是否相等 # a = 10 # b = 10 # print(a == b) # is 是 # a = 10 # ...
- The usage of Markdown---列表
目录 1. 序言 2. 有序列表 3. 多级有序列表 3. 无序列表 4. 多级无序列表 5. 列表中的转义字符 6. 无效化 7. 任务列表 更新时间:2019.09.14 1. 序言 其实我昨 ...
- web常用知识
Html 1.打电话,发短信和发邮件 <a href="tel:0755-10086">打电话给:0755-10086</a> <a href=&qu ...
- 数据类型(二)---day04
目录 上节课回顾 五 变量 (一)什么是变量 (二)变量的组成 (三)变量名的命名规范 (四)常量 (五)python变量内存管理 (六)变量的三种打印方式 六 数据类型 (一)数字类型 (二)字符串 ...
- fenby C语言 P6
printf=格式输出函数; printf=("两个相加的数字是:%d,%d,他们的和是:%d\n",a,b,c); %d整数方式输出; \n=Enter; int a=1; fl ...