Python面向对象 -- 继承和多态、获取对象信息、实例属性和类属性
继承和多态
继承的好处:
1,子类可以使用父类的全部功能
2,多态:当子类和父类都存在相同的方法时,子类的方法会覆盖父类的方法,即调用时会调用子类的方法。这就是继承的另一个好处:多态。
多态:
调用方只管调用,不管细节,当我们新增一种Animal的子类时,只要确保run( )方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
对扩展开放:允许新增Animal的子类
对修改封闭:不需要修改依赖Animal类型的run_twice( )等函数
静态语言VS动态语言
对于静态语言(如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run( )方法。
对于Python这样的动态语言来说,如果需要传入Animal类型,则不一定要传入Animal类型,我们只需要保证传入的对象有一个run( )方法就可以了。
动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
两个特点:
外观:看起来像鸭子
行为动作:走起路来像鸭子
Python的 " file-like object "就是一种鸭子类型。对于真正的文件对象来说,它有一个read( )方法,返回其内容。但是,许多对象,只要有read( )方法,都可以被看做" file-like object ",即你不一定要传入真正的文件对象,可以传入任何实现了read( )方法的对象。
下面代码中,
1,对于Dog来说,Animal就是它的父类;对于Animal来说,Dog就是它的子类。
2,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行了。
Dog的实例d,d的数据类型是Dog,同时也是Animal类型,因为Dog是从Animal继承下来的。
class Animal(object):
def run(self):
print('Animal is running...') class Dog(Animal): #继承了Animal类的子类Dog
def run(self):
print('Dog is running...') class Cat(Animal): #继承了Animal类的子类Cat
def run(self):
print('Cat is running...') class Tor(object): #虽然不是Animal类型,但是有run方法,“鸭子类型”
def run(self):
print('tor is running slowly') def run_twice(animal):
animal.run()
animal.run() a = Animal()
d = Dog()
c = Cat()
t = Tor() print("判断实例a是否是Animal, Dog, Cat")
print('a is Animal?', '', isinstance(a, Animal))
print('a is Dog?','', isinstance(a, Dog))
print('a is Cat?','', isinstance(a, Cat))
print("") print("可以看到Dog继承了Animal类,所以Dog的实例的数据类型既是Dog, 也是父类Animal")
print('d is Animal?','', isinstance(d, Animal))
print('d is Dog?','', isinstance(d, Dog))
print('d is Cat?','', isinstance(d, Cat))
print("") run_twice(a)
run_twice(d)
run_twice(c) print("")
print("可以看到实例t不是是Animal,但是也能运行run_twice()函数,是因为它有run方法")
print('t is Tor?','', isinstance(t,Tor))
print('t is Animal?','', isinstance(t,Animal))
print("") run_twice(t)
运行结果:
小结:
继承可以把父类所有的功能都继承过来,这样就不必从0开始做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
动态语言的" 鸭子类型 "决定了继承不像静态语言那样数据类型是必须的。
获取对象信息
type( )函数、isinstance( )函数、dir( )函数、getattr( )函数、setattr( )函数、hasattr( )函数
type( )函数:
(1)判读对象的基本类型、或者直接写int,str
(2)一个变量指向函数或者类,进行判断
(3)判断两个对象的type类型是否相同
(4)判断一个对象是否是函数? 方法:使用types 模块中定义的常量
import types
def fn():
pass print("是否是函数类型:",type(fn)==types.FunctionType) #判断是否是函数类型
print("是否是绝对值类型:",type(abs)==types.BuiltinFunctionType)
print("是否是lambda匿名函数类型:",type(lambda x: x)==types.LambdaType) #判断是否是lambda匿名函数类型
print("是否是生成器类型:",type(x for x in range(10))==types.GeneratorType) #判断是否是生成器类型
使用Isinstance( )函数
(1)判断class类的类型,Isinstance( )函数判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上
(2)能用type( )判断的也能用isinstance( )判断
(3)判断一个对象是否是某些类型中的一种
print(isinstance([1,2,3,4],(list,tuple)))
print(isinstance((1,2,3,4),(list,tuple)))
print(isinstance([1,2,3,4],(int,str)))
结论:总是优先使用isinstance( )函数来判断类型,可以将指定类型及其子类“一网打尽”
dir( )函数
功能:可以获得一个对象的所有属性和方法,它返回一个包含字符串的list列表
注:获取属性值的格式,尽量使用 “实例.属性名”,少用getattr( )函数获取属性值
测试对象的属性 , attr, attribute属性缩写 has+attr=hasattr, get+attr=getattr, set+attr=setattr
hasattr( ):只有两个参数,判断实例变量是否有这个属性或方法,参数中属性或方法都要用引号引起来
setattr( ):有3个参数,(实例变量,属性名,属性值),为实例变量添加属性值,
getattr( ):有3个参数,获取实例变量的属性值或方法, 可以设置默认值default,如果有属性不存在,就返回默认值
对于属性,getattr返回的是属性值
对于方法,getattr返回的是实例变量.方法名
注意:方法名后面不带括号,如果想调用这个方法,就写成这种形式getattr( )( ),在getattr( )函数的后面加上一个括号
(1)类似__xxx__这样的属性和方法在Python中是有特殊用途的,比如__len__方法返回长度
(2)在Python中,调用len( )函数获取一个对象的长度,实际上,在len( )函数内部,它自动去调用该对象的__len__( )方法。
所以,下面的代码是等价的:
(3)如果自己写类,想用len( myObj )的话,就自己写一个__len__( )方法
注意:是__len__( )方法,前后带2个下划线,而不是len( )方法
(4)使用hasattr( ), setattr( ), getattr( )操作对象
测试对象的属性,如果获取不存在的属性,会抛出AttributeError错误,此时可以设置一个default参数,如果属性不存在,就返回默认值
测试对象的方法:
小结
(1)可以直接写obj.x,就不要写getattr(obj, 'x')
(2)假设我们从文件流fp中读取图像,首先要判断该fp对象是否存在read方法,如果存在,则该对象是一个流,如果不存在,则无法读取。 hasattr( )就派上用场了。
注意:在Python这类动态语言中,根据鸭子类型,有read( )方法,不代表该fp对象就是一个文件流,它也可能是网络流,也可能是内存中的一个字节流,但只要read( )方法返回的是有效的图像数据,就不影响读取图像的功能。
def readImage(fp):
if hasattr(fp, 'read'):
return readData(fp)
return None
实例属性和类属性
1、类属性属于类所有,该类的所有实例均可以访问,所有实例共享一个属性。
2、定义了类属性后,如果实例中的属性名和类中的属性名相同,则访问实例的这个属性值时将会覆盖类中相同属性名的值,如果属性名不相同,则不会覆盖
3、实例属性属于各个实例,互不干扰
注:从下面的代码中可以看出,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将会覆盖掉类属性,但是当删除实例属性后,再访问时,访问到的是类属性。
class Student(object):
name='Student' s=Student() print('s.name:',s.name) #实例的name属性值
print('Student.name:',Student.name) #类Student的name属性值 print("")
print("添加了实例的namea属性后:")
s.namea='Michael' #定义了实例的namea属性值,注意后面多了一个a
print('s.namea:',s.namea) #实例中定义了和类Student中name属性,不同属性名的属性namea
print('s.name:',s.name) #此时实例的name属性值
print('Student.name:',Student.name) print("")
print("添加了实例的name属性后:")
s.name='hello'
print('s.name:',s.name) #此时实例的name属性值
print('Student.name:',Student.name) #类Student的name属性值 print("")
print("删除了实例的name属性后:")
del s.name #删除了实例中的name属性
print('s.name:',s.name)
print('Student.name:',Student.name)
运行结果如下:
实战:为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加:
class Student(object):
count=0 #初始化计数变量 def __init__(self,name):
self.name=name
Student.count+=1 if Student.count != 0: #先判断计数变量是否初始化为0
print('测试失败!')
else:
bart = Student('Bart') #创建第一个实例变量
if Student.count != 1: #创建完第一个实例变量后,此时的Student.count应该为1
print('测试失败!')
else:
lisa = Student('Lisa')#又创建第二个实例变量
if Student.count != 2:
print('测试失败!')
else:
print('Students:', Student.count)
print('测试通过!')
运行结果:
参考网址:廖雪峰的官方网站
Python面向对象 -- 继承和多态、获取对象信息、实例属性和类属性的更多相关文章
- Python面向对象-继承和多态特性
继承 在面向对象的程序设计中,当我们定义一个class时候,可以从现有的class继承,新的class成为子类,被继承的class称为基类,父类或超类. 比如,编写一个名为Animal的class: ...
- python类的继承和多态,获取对象信息
继承 类的继承机制使得子类可以继承父类中定义的方法,拥有父类的财产,比如有一个Animal的类作为父类,它有一个eat方法: class Animal(object): def __init__(se ...
- python 面向对象编程、获取对象信息
面向对象与面向过程 参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0 ...
- Python之路-面向对象&继承和多态&类属性和实例属性&类方法和静态方法
一.面向对象 编程方式 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强…” 什么是面 ...
- python基础——获取对象信息
python基础——获取对象信息 当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type( ...
- python 获取对象信息
当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type()判断: >>> ...
- 【Python】[面性对象编程] 获取对象信息,实例属性和类属性
获取对象信息1.使用isinstance()判断class类型2.dir() 返回一个对象的所有属性和方法3.如果试图获取不存在的对象会抛出异常[AttributeError]4.正确利用对象内置函数 ...
- python获取对象信息
获取对象信息 拿到一个变量,除了用 isinstance() 判断它是否是某种类型的实例外,还有没有别的方法获取到更多的信息呢? 例如,已有定义: class Person(object): def ...
- Python基础(获取对象信息)
import types print(type('abc') == str)#True print(type(123) == int)#True def f1(): pass print(type(f ...
随机推荐
- CentOS 7 Sersync+Rsync 实现数据文件实时同步
rsync+inotify-tools与rsync+sersync架构的区别? 1.rsync+inotify-tools inotify只能记录下被监听的目录发生了变化(增,删,改)并没有把具体是哪 ...
- sql server导出数据,远程连接失败,需要设置权限
在sql server management中右键当前连接——>方面 在 服务器配置中 将 RemoteAccessEnabled.RemoteDacEnabled设置为TRUE 安全性—— ...
- ls file less
ls-a 列出所有文件,包含隐藏文件-l 以长格式显示结果-F 在所列出的文件后面显示其格式-r 按照文件名降序展示-t 按照时间列出-S 按照文件大小排序 file 文件名:展示文件的类型简单描述 ...
- t-SNE完整笔记
http://www.datakit.cn/blog/2017/02/05/t_sne_full.html t-SNE(t-distributed stochastic neighbor embedd ...
- Typora/VSCode/Sublime 更改Markdown默认宽度样式等
Typora 所见即所得Markdown编辑器更改 最大宽度 C:\Users\Desk\AppData\Roaming\Typora\themes\github.css CSS第46行改为 max- ...
- python之堡垒机(第九天)
本节作业: 通过使用paramiko和sqlalchemy实现堡垒机功能 主要功能实现: 1.用户登录堡垒机后,无需知道密码或密钥可以SSH登录远端服务器: 2.用户对一个组内所有主机批量执行指定命令 ...
- laravel5.7 前后端分离开发 实现基于API请求的token认证
最近在学习前后端分离开发,发现 在laravel中实现前后台分离是无法无法使用 CSRF Token 认证的.因为 web 请求的用户认证是通过Session和客户端Cookie的实现的,而前后端分离 ...
- OpenCV学习笔记(二) - 写入视频、jpg格式
写入视频: import sys, os import cv2 imgDir = '/Users/xxx/salient/' videoName = 'vname' fps = 30 #帧频 outp ...
- PyTorch进行深度学习入门
一.PyTorch是什么? 这是一个基于Python的科学计算软件包,针对两组受众: ①.NumPy的替代品,可以使用GPU的强大功能 ②.深入学习研究平台,提供最大的灵活性和速度 二.入门 ①.张量 ...
- 20175208 《Java程序设计》第八周学习总结
20175208 2018-2019-3<Java程序设计>第八周学习总结 一.教材学习内容总结: 1.泛型: 泛型的主要目的是可以建立具有类型安全的集合框架(如链表.散列映射等数据结构) ...