类的进阶

一 isinstance(obj,cls)和issubclass(sub,super)

 class Foo:
def __init__(self,name):
self.name = name obj = Foo("egon") print(isinstance(obj,Foo)) l = list([1,2,3])
print(isinstance(l,list)) -----------------结果----------- True
True isinstance(obj,cls)检查是否obj是否是类 cls 的对象

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

 class Foo:
pass class Bar(Foo):
pass print(issubclass(Bar,Foo)) ------------------------结果----------
True issubclass(sub, super)检查sub类是否是 super 类的派生类

issubclass(sub, super)检查sub类是否是 super 类的派生类

二.反射

1.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

 class People:
country = "china"
def __init__(self,name):
self.name = name p = People("egon")
print(p.__dict__)
#-------------------------
print(hasattr(p,"name"))
print("name" in p.__dict__)
print(hasattr(People,"country")) ----------------------------------
{'name': 'egon'}
True
True
True

hasattr(object,name)

 class People:
country = "china"
def __init__(self,name):
self.name = name def walk(self):
print("%s is working" % self.name) p = People("egon") print(getattr(p,"country")) #print(p.country)
# china
print(getattr(p,"walk")) #print(p.walk)
#<bound method People.walk of <__main__.People object at 0x101979278>>

getattr(object, name, default=None)

 class People:
country = "china"
def __init__(self,name):
self.name = name def walk(self):
print("%s is working" % self.name) p = People("egon") setattr(p,"age",15)
print(p.__dict__)
{'age': 15, 'name': 'egon'}

setattr(x, y, v)

 class People:
country = "china"
def __init__(self,name):
self.name = name def walk(self):
print("%s is working" % self.name) p = People("egon") print(p.__dict__)
{'name': 'egon'}
delattr(p,"name")
print(p.__dict__)
{}

delattr(x, y)

 import sys
def add():
print("add") def delete():
print("delete") def update():
print("update") def search():
print("search") this_module = sys.modules[__name__]
while True:
cmd = input("please input: ")
if not cmd:continue
if hasattr(this_module,cmd):
func = getattr(this_module,cmd)
func()

sys.modules[__name__]

2.反射的好处 

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,

lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?

即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能 

 #Ftpclent.py 文件

 class FtpClient:
'ftp客户端,但是还么有实现具体的功能'
def __init__(self,addr):
print('正在连接服务器 %s ' %addr)
self.addr=addr def get(self):
print("get") #Ftpserver.py 文件 from day32 import FtpClient obj = FtpClient.FtpClient('192.168.1.1') if hasattr(obj,"get"):
func = getattr(obj,"get")
func() print("other func")

FTP 代码

    好处二:动态导入模块(基于反射当前模块成员)

1
2
3
4
5
6
7
8
#导入字符串
__import__("time")
 
#使用模块
import importlib
= importlib.import_module("time")
print(t.time())
    1493026292.217129

三.__setattr__,__delattr__,__getattr__

 #初始化和赋值时触发__setattr__运行

 #发现__dict__没有name 和 age
class Foo:
def __init__(self,name):
self.name = name def __setattr__(self, key, value):
print("__setattr__ key:%s value:%s"%(key,value)) obj = Foo("egon")
__setattr__ key:name value:egon
obj.age = 18
__setattr__ key:age value:18
print(obj.__dict__) #发现__dict__没有name 和 age
{} #初始化和赋值都在__dict__中找到 class Foo:
def __init__(self,name):
self.name = name def __setattr__(self, key, value):
print("__setattr__ key:%s value:%s"%(key,value))
self.__dict__[key] = value obj = Foo("egon")
__setattr__ key:name value:egon
obj.age = 15
__setattr__ key:age value:15
print(obj.__dict__)
{'name': 'egon', 'age': 15} #初始化赋值时判断如果不是数字不可以赋值 class Foo:
def __init__(self,name):
self.name = name def __setattr__(self, key, value):
if not isinstance(value,int):
raise TypeError("type error")
self.__dict__[key] = value obj = Foo(15)
obj.age = 15
print(obj.__dict__)
{'age': 15, 'name': 15}

__setattr__

 __delattr__ 

__delattr__

 #属性不存在时候运行

 class Foo:
def __init__(self,name):
self.name = name def __getattr__(self, item):
print("__getattr__ %s" % item) obj = Foo("egon")
print(obj.name)
egon
print(obj.xxx)
__getattr__ xxx
None

__getattr__

四. 二次加工标准类型(包装)

包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)

 #自定义自己的数据类型,追加和插入,如果不是数字,报错

 class List(list):
def append(self, p_object):
if not isinstance(p_object,int):
raise TypeError("Type error")
super().append(p_object) def insert(self, index, p_object):
if not isinstance(p_object,int):
raise TypeError("Type error")
super().insert(index,p_object) l = List([1,2,3])
print(l)
[1, 2, 3]
l.append("") #不能追加字符串 l.insert(0,-1)
print(l)
[-1, 1, 2, 3]

自定义数据类型

 import time

 class Open:
def __init__(self,filepath,mode="r",encode="utf-8"):
self.x = open(filepath,mode=mode,encoding=encode)
self.filepath = filepath
self.mode = mode
self.encoding = encode def write(self,value):
log_time = time.strftime('%Y-%m-%d %X')
self.x.write("%s %s" % (log_time,value)) def __getattr__(self, item):
return getattr(self.x,item) f = Open("b.txt","a+")
f.write("11111111\n")
f.seek(0)
print(f.read())

授权

 #基于继承来定制自己的数据类型
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])
print(l.mid) 基于授权来定制自己的数据类型: class Open:
def __init__(self,filepath,mode,encode='utf-8'):
self.f=open(filepath,mode=mode,encoding=encode)
self.filepath=filepath
self.mode=mode
self.encoding=encode def write(self,line):
print('write')
self.f.write(line) def __getattr__(self, item):
return getattr(self.f,item) f=Open('a.txt','w')
f.write('123123123123123\n')
print(f.seek)
f.close()

授权 继承 数据类型

五.反射作业

1
2
3
4
1.基于授权定制自己的列表类型,要求定制的自己的__init__方法,
2.定制自己的append:只能向列表加入字符串类型的值
3.定制显示列表中间那个值的属性(提示:property
4.其余方法都使用list默认的(提示:__getattr__加反射)
 class List:
def __init__(self,x):
self.seq=list(x) def append(self,value):
if not isinstance(value,str):
raise TypeError('must be str')
self.seq.append(value)
@property
def mid(self):
index=len(self.seq)//2
return self.seq[index]
def __getattr__(self, item):
return getattr(self.seq,item) def __str__(self):
print("")
return str(self.seq) l=List([1,2,3]) l.append('') print(l.mid) l.insert(0,123)

六.__setitem__,__getitem,__delitem__

 #把对象操作属性模拟成字典的格式

 class Foo:
def __init__(self,name):
self.name = name def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, item):
self.__dict__.pop(item) f = Foo("egon")
print(f.name)
egon
f.name = "egonlin"
print(f.__dict__)
{'name': 'egonlin'} f["age"] = 18
print(f.__dict__)
{'name': 'egon', 'age': 18} del f["name"]
print(f.__dict__)
{}

把对象操作属性模拟成字典的格式

七.__slots__

'''
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该
只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。 更多的是用来作为一个内存优化工具。 '''
class Foo:
__slots__='x' f1=Foo()
f1.x=1
f1.y=2#报错
print(f1.__slots__) #f1不再有__dict__ class Bar:
__slots__=['x','y'] n=Bar()
n.x,n.y=1,2
n.z=3#报错 __slots__使用

  

八.__next__和__iter__实现迭代器协议

 class Foo:
def __init__(self, end,start=0):
self.start = start
self.end = end
def __iter__(self):
return self def __next__(self):
if self.start >= self.end:
raise StopIteration
n = self.start
self.start+=1
return n f = Foo(10)
for i in f:
print(i)

rangge(10)

 class Range:
def __init__(self,start,stop):
self.start = start
self.stop = stop def __iter__(self):
return self def __next__(self):
if self.start >= self.stop:
raise StopIteration("StopIteration Error")
n = self.start
self.start += 1
return n obj = Range(0,15) for i in obj:
print(i)

Range(1,15)

 class Range:
def __init__(self, *args):
self.args = args
if len(self.args) == 2:
self.start = self.args[0]
self.end = self.args[1]
else:
self.start = 0
self.end = self.args[0]
def __iter__(self):
return self def __next__(self):
n = self.start
if n < self.end:
n = self.start
self.start += 1
return n
raise StopIteration for i in Range(1,10):
print(i) for i in Range(10):
print(i)

range(10) range(1,15)

 class Fib:
def __init__(self):
self._a=0
self._b=1 def __iter__(self):
return self def __next__(self):
self._a,self._b=self._b,self._a + self._b
return self._a f1=Fib() print(f1.__next__())
print(next(f1))
print(next(f1)) for i in f1:
if i > 100:
break
print('%s ' %i,end='')

斐波那契数列

九.__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

 class Foo:

     def __del__(self):
print('执行我啦') f1=Foo()
del f1
print('------->')
--------------------结果------------- 执行我啦
------->

销毁--->执行完

 class Foo:

     def __del__(self):
print('执行我啦') f1=Foo()
print('------->')
--------------------结果------------- ------->
执行我啦

执行完--->销毁

十.__enter__和__exit__

 with open('a.txt') as f:
  '代码块' 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法 class Open:
def __init__(self,name):
self.name=name def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊') with Open('a.txt') as f:
print('=====>执行代码块') -----------------结果---------------- 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊

说明

 class Open:
def __init__(self,name):
self.name=name def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb) with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print(''*100) #------------------------------->不会执行

__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行

 class Open:
def __init__(self,name):
self.name=name def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print(''*100) #------------------------------->会执行

如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

 import time

 class Open:
def __init__(self,filepath,mode="r",encode="utf-8"):
self.x = open(filepath,mode=mode,encoding=encode)
self.filepath = filepath
self.mode = mode
self.encoding = encode def __enter__(self):
return self def __exit__(self, exc_type, exc_val, exc_tb):
self.x.close()
return True def write(self,value):
log_time = time.strftime('%Y-%m-%d %X')
self.x.write("%s %s" % (log_time,value)) def __getattr__(self, item):
return getattr(self.x,item) with Open("b.txt","a+") as f : #obj = Open().__enter__() ---> obj = f
f.write("11111111\n")

Open类 with打开

十一.__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:
def __init__(self):
pass def __call__(self, *args, **kwargs):
print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__
__call__

  

十二.__str__

 class Foo:
def __init__(self,name,age):
self.name = name
self.age = age def __str__(self):
return "名字是%s 年龄是%s" %(self.name,self.age) f1 = Foo("agon",18)
print(f1) # --------------结果----------
名字是agon 年龄是18

__str__ 打印时候触发

python 类的进阶的更多相关文章

  1. Python类的进阶.md

    属性绑定 在python中可以给类对象动态的绑定属性 但是由于这种特性,随意动态绑定也会带来麻烦,因此可用__slots__来限制可绑定的属性名称 __slots__的绑定对于子类是不生效的,只对当前 ...

  2. Python类的继承(进阶5)

    转载请标明出处: http://www.cnblogs.com/why168888/p/6411918.html 本文出自:[Edwin博客园] Python类的继承(进阶5) 1. python中什 ...

  3. python 面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

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

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

  5. python基础——面向对象进阶

    python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...

  6. python面向对象编程进阶

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

  7. Python语言学习之Python入门到进阶

    人们常说Python语言简单,编写简单程序时好像也确实如此.但实际上Python绝不简单,它也是一种很复杂的语言,其功能特征非常丰富,能支持多种编程风格,在几乎所有方面都能深度定制.要想用好Pytho ...

  8. 【转】python 面向对象(进阶篇)

    [转]python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 ...

  9. 【转】Python之函数进阶

    [转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...

随机推荐

  1. iOS 提交审核报错 ERROR ITMS-90087解决办法

    ERROR ITMS-: "Unsupported Architectures. The executable for yht.temp_caseinsensitive_rename.app ...

  2. 快速搭建CentOS+ASP.NET Core环境支持WebSocket

    环境:CentOS 7.x,.net core 2 以下.net core 2安装操作为官方方法.如果你使用Docker,那么更简单了,只需要docker pull microsoft/dotnet就 ...

  3. linux(ubuntu)环境下安装IDEA

    想调试java虚拟机内存溢出的情况,在调试过程中总会出现一些不可预见的状况,正好在学linux,在windows上安装了虚拟机,安装的镜像是ubuntu(乌班图)装在了虚拟机中,装在虚拟机中好处是即使 ...

  4. webpack-dev-server 搭建本地服务以及浏览器实时刷新

    一.概述开发项目中为了保证上线,开发项目是都需要使用localhost进行开发,以前的做法就是本地搭建Apache或者Tomcat服务器.有的前端开发人员 对服务器的搭建和配置并不熟悉,这个时候需要后 ...

  5. Django——ORM

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  6. 【Python】 迭代器&生成器

    迭代器 任何一个类,只要其实现了__iter__方法,就算是一个可迭代对象.可迭代对象的__iter__方法返回的对象是迭代器,迭代器类需要实现next方法.一般来说,实现了__iter__方法的类肯 ...

  7. ReflectASM-invoke,高效率java反射机制原理

    前言:前段时间在设计公司基于netty的易用框架时,很多地方都用到了反射机制.反射的性能一直是大家有目共睹的诟病,相比于直接调用速度上差了很多.但是在很多地方,作为未知通用判断的时候,不得不调用反射类 ...

  8. Java学习日记——基本数据类型

    基本数据类型: byte 1个字节 正负都能表示2的8-1次方 -128~127(包括0) short 2个字节 2的16-1次 整数类型 (默认为int类型) int 4个字节 2的32-1次方 l ...

  9. openjudge(四)

    关于switch的应用: #include <iostream>#include<iomanip>using namespace std;int main(){int a,b; ...

  10. CSS 语法

    CSS 语法 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明: 选择器通常是您需要改变样式的 HTML 元素. 每条声明由一个属性和一个值组成. 属性(property)是您希望设置的样 ...