python基础——面向对象进阶
python基础——面向对象进阶
1、isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
- class Foo:
- pass
- obj=Foo()
- print(isinstance(obj,Foo)) #判断是不是类的对象
输出结果为:
- True
issubclass(sub, super)检查sub类是否是 super 类的派生类
- class Bar():
- pass
- class Foo(Bar):
- pass
- print(issubclass(Foo,Bar)) #判断FOO 是不是Bar的儿子类
输出结果为:
- True
2、反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr() 判断object中有没有一个name字符串对应的方法或属性
- class People:
- county='China'
- def __init__(self,name):
- self.name=name
- p=People('egon')
- print(hasattr(p,"name"))
输出结果为:
- True
getattr() 获取到 并有一个返回值, 通过字符串来获取属性,来判断有没有属性,来操作关于属性问题
- getattr(p,'country')
- res=getattr(p,'country') #res=p.country
- print(res)
- res=getattr(p,'name')
- print(res)
输出结果为:
- China
- egon
获取一个类里面不存在的值情况
- class People:
- country='China'
- def __init__(self,name):
- self.name=name
- def walk(self):
- print('%s is walking'%self.name)
- p=People('egon')
- print(getattr(p,'xxxx')) #报错
- getattr(p,'xxxxxx','这个属性确实不存在') #没有报错 可以加个参数
- print(getattr(p,'xxxxxx','这个属性确实不存在'))
- #可以给getattr在加一个参数,在你获取不到属性的情况下,
- # 把前面的参数作为返回值返回,保证程序不会抛出异常
输出结果为:
- AttributeError: 'People' object has no attribute 'xxxx' #报错
- 这个属性确实不存在
可以判断有没有这个属性,有的话 就直接打印出来( hasattr getattr #是最常用的 )
- if hasattr(p,'walk'):
- func=getattr(p,'walk')
- func()
- print('----->')
- print('----->')
输出结果为:
- egon is walking
- ----->
- ----->
stettr() 设置 用字符串去代替属性
- class People:
- country='China'
- def __init__(self,name):
- self.name=name
- def walk(self):
- print('%s is walking'%self.name)
- p=People('egon')
- p.sex='male'
- print(p.sex)
- print(p.__dict__)
- 输出结果为:
- male
- {'name': 'egon', 'sex': 'male'}
delattr() 删除
- class People:
- country='China'
- def __init__(self,name):
- self.name=name
- def walk(self):
- print('%s is walking'%self.name)
- p=People('egon')
- print(p.__dict__) #删除前
del p.name
print(p.__dict__) #删除后
- 输出结果为:
- {'name': 'egon'}
- {}
3、反射的用途
- 第一种:把字符串映射成可执行命令,或者映射成属性得到一个值
- 例子:
- import sys
- def add():
- print('add')
- def change():
- print('change')
- def search():
- print('search')
- def delete():
- print('delete')
- this_module=sys.modules[__name__]
- while True:
- cmd=input('>>:').strip()
- if not cmd:continue
- if hasattr(this_module,cmd):
- func=getattr(this_module,cmd)
- func()
第二种:实现可插拔机制
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能
egon还没有实现全部功能:
- class FtpClient:
- 'ftp客户端,但是还么有实现具体的功能'
- def __init__(self,addr):
- print('正在连接服务器[%s]' %addr)
- self.addr=addr
不影响lili的代码编写:
- #from module import FtpClient
- f1=FtpClient('192.168.1.1')
- if hasattr(f1,'get'):
- func_get=getattr(f1,'get')
- func_get()
- else:
- print('---->不存在此方法')
- print('处理其他的逻辑')
4、通过字符串导入模块
官方不推荐使用:
- m=input('请输入你要导入的模块:')
- m1=__import__(m) #用字符串导入了一个模块
- print(m1)
- print(m1.time())
推荐使用方法:
- import importlib #导入一个模块
- m=input('请输入你要导入的模块:')
- t=importlib.import_module('time') #传一个字符串
- print(t.time())
5、反射当前模块属性
什么是模块:
- 每写一个py文件就是模块,可以自己使用,别人需要用 导入一个import模块
文件本身是对象,文件下定义各种各样名字- 在自己当前模块里面要获取自己模块内存地址
在自己模块里不能自己导入自己
- import sys #导入一个模块名
- x=111 #定义一个变量名
- class Foo:
- pass
- def s1():
- print('s1')
- def s2():
- print('s2')
- 文件两者用途
- 第一种 直接运行文件,把文件当做脚本运行
- 不运行这个文件,在另外一个文件里面当做模块导入这个文件
- print(__name__) #等于__main__区分文件不同用处
6、_setattr_,_delattr_,_getattr_
_setattr_ 设置一个属性
- class Foo:
- def __init__(self,name):
- self.name=name
- def __setattr__(self, key, value):
- print('----setattr----key:%s,value:%s'%(key,value))
- print(type(key))
- print(type(value))
- self.__dict__[key]=value #将值加入到字典里去
- f1=Foo('egon') # f1.name="egon" 触发setattr运行
- f1.age=18 #触发setattr运行
- print(f1.__dict__)
输出结果为:
- ----setattr----key:name,value:egon
- <class 'str'>
- <class 'str'>
- ----setattr----key:age,value:18
- <class 'str'>
- <class 'int'>
- {'name': 'egon', 'age': 18}
加上类型限制(不是字符串类型)
- class Foo:
- def __init__(self,name):
- self.name=name
- def __setattr__(self, key, value):
- if not isinstance(value,str):
- raise Exception('must be str')
- self.__dict__[key]=value
- f1=Foo('egon')
- f1.age=18
- print(f1.__dict__)
输出结果为:
- raise Exception('must be str') #报错
- Exception: must be str
最终结果
- class Foo:
- def __init__(self,name):
- self.name=name
- def __setattr__(self, key, value):
- if not isinstance(value,str):
- raise Exception('must be str')
- self.__dict__[key]=value
- f1=Foo('egon')
- f1.age='18'
- print(f1.__dict__)
输出结果为:
- {'name': 'egon', 'age': '18'}
_getattr_ 获取一个属性 (属性不存在的情况下才会触发)
- class Foo:
- def __init__(self,name):
- self.name=name
- # 属性不存在的情况下才会触发
- def __getattr__(self, item):
- print('getattr-->%s %s'%(item,type(item)))
- f=Foo('egon')
- print(f.name) #存在的情况下没有触发getattr
- print(f.xxxx) #属性不存在才会触发getattr
输出结果为:
- egon
- getattr-->xxxx <class 'str'>
- None
_delattr_ 删除
- class Foo:
- def __init__(self,name):
- self.name=name
- def __setattr__(self, key, value):
- self.__dict__[key]=value #字典的方式加入
- def __delattr__(self, item):
- print('delattr:%s'%item)
- print(type(item))
- self.__dict__.pop(item)
- f1=Foo('egon')
- f1.age=18
- del f1.age
- print(f1.__dict__)
输出结果为:
- delattr:age
- <class 'str'>
- {'name': 'egon'}
7、定制自己的数据类型
- python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,
新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
- class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
- def append(self, p_object):
- ' 派生自己的append:加上类型检查'
- if not isinstance(p_object,int):
- raise TypeError('must be int')
- super().append(p_object)
- @property
- def mid(self):
- '新增自己的属性'
- index=len(self)//2
- return self[index]
- l=List([1,2,3,4])
- print(l)
- l.append(5)
- print(l)
- # l.append('1111111') #报错,必须为int类型
- print(l.mid)
- #其余的方法都继承list的
- l.insert(0,-123)
- print(l)
- l.clear()
- print(l)
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
例子 来实现open函数的功能,不能用继承
- import time
- class Open:
- def __init__(self,file_path,m='r',encode='utf8'):
- self.file_path=file_path
- self.mode=m
- self.encoding=encode
- self.x=open(file_path,mode=m,encoding=encode) #文件保存在self.x里面
- def write(self,line):
- print('f自己的write',line)
- t=time.strftime('%Y-%m-%d %x')
- self.x.write('%s %s'%(t,line))
- def __getattr__(self, item):
- print('---->',item,type(item))
- return getattr(self.x,item)
- f=Open('b.txt','r+')
- print(f.read)
- res=f.read()
- print(res)
输出结果为:
- <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>
- ----> read <class 'str'>
- <built-in method read of _io.TextIOWrapper object at 0x0235BE30>
- ----> read <class 'str'>
- 2017-04-25 04/25/17 1111
- 2017-04-25 04/25/17 1111
- 2017-04-25 04/25/17 1111
- 2017-04-25 04/25/17 1111
python基础——面向对象进阶的更多相关文章
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
- python基础-面向对象进阶
一.什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被 ...
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python基础与进阶
1 Python基础与进阶 欢迎来到Python世界 搭建编程环境 变量 | 字符串 | 注释 | 错误消除 他只用一张图,就把Python中的列表拿下了! 使用 If 语句进行条件测试 使用字典更准 ...
- Python 3 面向对象进阶
Python 3 面向对象进阶 一. isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的 ...
- Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
- python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)
python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...
- Python基础—面向对象(进阶篇)
通过上一篇博客我们已经对面向对象有所了解,下面我们先回顾一下上篇文章介绍的内容: 上篇博客地址:http://www.cnblogs.com/phennry/p/5606718.html 面向对象是一 ...
随机推荐
- 什么是yum源,如何更改yum源
Yum(全称为 Yellow dog Updater, Modified) yum是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于RPM包管理,能够从指定的服务器 ...
- @Controller 类中初始化问题解决办法
在Controller类中常常遇到有些参数需要初始化,甚至有些只允许初始化一次,而Controller类不像servelet类可以调用init()函数进行初始化,这里想到的办法是设置标记值,让初始化部 ...
- [译]Android view 测量布局和绘制的流程
原文链接 创造优秀的用户体验是我们开发者的主要目标之一.为此, 我们首先要了解系统是如何工作的, 这样我们才可以更好的与系统配合, 从它的优点中获益, 规避它的缺陷. 之前关于Android渲染过程的 ...
- Node.JS开发环境准备
1.安装Nodejs的Windows包. 官网:http://nodejs.org/ 2.可以使用cmd运行nodejs项目,命令格式: node 文件名.js node 文件名 3.对于不熟悉的 ...
- Spring容器中Bean的生命周期
- Mycat 分片规则详解--日期范围 hash 分片
实现方式:其思想和范围取模分片一样,由于日期取模会出现数据热点问题,所以先根据日期分组,再根据时间 hash 使得短期数据分布跟均匀. 优点:避免扩容时的数据迁移,可以在一定程度上避免范围分片的热点问 ...
- 初识mango DB
换工作了,第一次接触到mango数据库,有点云里雾里,整理一篇最基本的增删该查语句 百度百科说mango DB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据 ...
- postman简单教程,如何在请求中引用上次请求返回的值
做接口测试,一定会遇到这种情况,需要拿上次请求的值在本次请求中使用,比如,我们去测试一个东西,要去登录才能做其他的操作,需要拿到登录返回数据中的某些字段,比如,token啊等... 如果发一次请求,就 ...
- ava集合---HashSet的源码分析
一.HasnSet概述 Hashset实现set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set的迭代顺序.特别是它不保证该顺序恒久不变.此类允许使用Null元素 一.HasnSe ...
- 求逆序对[树状数组] jdoj
求逆序对 题目大意:给你一个序列,求逆序对个数. 注释:n<=$10^5$. 此题显然可以跑暴力.想枚举1到n,再求在i的后缀中有多少比i小的,统计答案即可.这显然是$n^2$的.这...显然过 ...