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基础——面向对象进阶的更多相关文章

  1. python基础——面向对象进阶下

    python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...

  2. python基础-面向对象进阶

    一.什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被 ...

  3. python基础——面向对象编程

    python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...

  4. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  5. Python基础与进阶

    1 Python基础与进阶 欢迎来到Python世界 搭建编程环境 变量 | 字符串 | 注释 | 错误消除 他只用一张图,就把Python中的列表拿下了! 使用 If 语句进行条件测试 使用字典更准 ...

  6. Python 3 面向对象进阶

    Python 3 面向对象进阶 一.    isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的 ...

  7. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  8. python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)

    python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...

  9. Python基础—面向对象(进阶篇)

    通过上一篇博客我们已经对面向对象有所了解,下面我们先回顾一下上篇文章介绍的内容: 上篇博客地址:http://www.cnblogs.com/phennry/p/5606718.html 面向对象是一 ...

随机推荐

  1. SQL 存储过程 多条件 分页查询 性能优化

    最优化查询代码 -- 注意:此处可能会出现 字符串过长问题,所以 必要的情况下请分段处理 set @sql1 =' SELECT * FROM ( select ROW_NUMBER() OVER(O ...

  2. Docker国内镜像源设置

    编辑json文件,添加如下内容后重启docker即可. [root@Docker ~]# cat /etc/docker/daemon.json{ "registry-mirrors&quo ...

  3. Mysql使用规范文档 20180223版

    强制:不允许在跳板机上/生产服务器上手工连接,查询或更改线上数据 强制:所有上线脚本必须先在测试环境执行,验证通过以后方可在生产环境执行. 强制:上线脚本的编码格式统一为UTF-8 强制:访问数据库需 ...

  4. Mysql5.7动态修改innodb_buffer_pool_size

    SELECT @@innodb_buffer_pool_size,@@innodb_buffer_pool_chunk_size,@@innodb_buffer_pool_instances; SET ...

  5. Node.JS开发环境准备

    1.安装Nodejs的Windows包. 官网:http://nodejs.org/ 2.可以使用cmd运行nodejs项目,命令格式: node  文件名.js node  文件名 3.对于不熟悉的 ...

  6. Http最常见的错误代码

    1XX 表示消息 2XX 表示成功 3XX 表示重定向 4XX 表示请求错误 5XX 表示服务器端错误 我们最常见的就是: 404(页面找不到),这个错误代码是由于我们输入的网址不对造成的,浏览器找不 ...

  7. servlet实现方式(未完待续)

    servlet的是方式有三种,分别是: 1,实现servlt接口 点击查看详情 2,继承GenericServlet类[适配器模式] 3,继承HttpServlet类[模板方法设计模式]最常用的方法 ...

  8. Spring Cloud简介以及版本选择

    什么是SpringCloud 官方的说法就是spring Cloud 给开发者提供一套按照一定套路快速开发 分布式系统 的工具. 具体点就是Spring boot实现的微服务架构开发工具.它为微服务架 ...

  9. c++ --> union介绍

    union介绍 共用体,也叫联合体,在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,以达到节省空间的目 ...

  10. DevOps实践之Gitlab安装部署

    All GitLab packages are posted to our package server and can be downloaded. We maintain five repos: ...