一 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 的对象------------------------结果----------
class Foo:
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo))
True
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)
2. 反射的好处
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__]
好处一:实现可插拔机制
有俩程序员,一个 lili,一个是 egon,lili 在写程序的时候需要用到 egon 所写的类,但是 egon 去跟女朋友度蜜月去了,还没有完成他写的类,
lili 想到了反射,使用了反射机制 lili 可以继续完成自己的代码,等 egon 度蜜月回来后再继续完成类的定义并且去实现 lili 想要的功能.
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种'后期绑定',什么意思?
即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
FTP 代码
#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")
好处二:动态导入模块(基于反射当前模块成员)
三.__setattr__,__delattr__,__getattr__
?
#导入字符串
__import__
(
"time"
)
#使用模块
import
importlib
t
=
importlib.import_module(
"time"
)
(t.time())
1493026292.217129
#初始化和赋值时触发__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__
class Foo:
def __init__(self,name):
self.name = name
def __setattr__(self, key, value):
self.__dict__[key] = value
def __delattr__(self, item):
self.__dict__.pop(item)
obj = Foo("egon")
print(obj.__dict__)
{'name': 'egon'
del obj.name
print(obj.__dict__)
{}
__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("4") #不能追加字符串
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.
基于授权定制自己的列表类型,要求定制的自己的__init__方法,2.
定制自己的append:只能向列表加入字符串类型的值
3.
定制显示列表中间那个值的属性(提示:
property
)
4.
其余方法都使用list
默认的(提示:__getattr__加反射)
六.__setitem__,__getitem,__delitem__
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("111")
return str(self.seq)
l=List([1,2,3])
l.append('1')
print(l.mid)
l.insert(0,123)
View Code
把对象操作属性模拟成字典的格式
#把对象操作属性模拟成字典的格式
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__
__slots__使用
+ View Code ?
'''
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
#报错
(f1.__slots__)
#f1不再有__dict__
class
Bar:
__slots__
=
[
'x'
,
'y'
]
n
=
Bar()
n.x,n.y
=
1
,
2
n.z
=
3
#报错
八.__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语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
with open('a.txt') as f:
'代码块'
-----------------结果----------------
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中代码块执行完毕时执行我啊
说明
__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)
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->不会执行
如果__exit() 返回值为 True, 那么异常会被清空,就好像啥都没发生一样,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('0'*100) #------------------------------->会执行
Open 类 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")
十一.__call__
对象后面加括号,触发执行.
注:构造方法的执行是由创建对象触发的,即:对象 = 类名 () ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象 () 或者 类 ()()
十二.__str__
+ View Code ?
class
Foo:
def
__init__(
self
):
pass
def
__call__(
self
,
*
args,
*
*
kwargs):
(
'__call__'
)
obj
=
Foo()
# 执行 __init__
obj()
# 执行 __call__
__call__
名字是agon 年龄是18
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)
# --------------结果----------
__str__ 打印时候触发
十三.__new__
__new__ 单例
十四. 创建类
1. 类在创建的时候执行type的__init__方法 类相当于type的对象
2. 类() = type对象() 相当于实例化 执行type的__call__方法
3. type的__call__方法会调用
- 调用类的__new__方法 用于创建对象
- 调用类的__init__方法 用于初始化
4. 对象() 执行类的__call__方法
-------------------------------(一)-------------------------------
类默认是由type创建也可以指定metaclass创建 在父类构造方法继续让type执行 相当于没做什么操作
class SingletonType(type):
def __init__(self,*args,**kwargs):
super(SingletonType,self).__init__(*args,**kwargs)
class Foo(metaclass=SingletonType):
pass
对象是由类创建的
-------------------------------(二)-------------------------------
此时在父类里面打印print(self) 发现结果为<class '__main__.Foo'>
class SingletonType(type):
def __init__(self,*args,**kwargs):
print(self)
super(SingletonType,self).__init__(*args,**kwargs)
class Foo(metaclass=SingletonType):
pass
对象是类创建 创建对象时候类的__init__方法自动执行
类是type创建 创建类时候type的__init__方法自动执行
-------------------------------(三)-------------------------------
对象() 执行类的__call__方法
类() 执行type的__call__方法 执行__call__方法内部会调用(类的__new__方法和__init__方法)
-------------------------------(四)-------------------------------
class SingletonType(type):
def __init__(self,*args,**kwargs):
print(self)
super(SingletonType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs): # cls 表示 SingletonType类
obj = cls.__new__(cls, *args, **kwargs) # obj 为创建的对象
class Foo(metaclass=SingletonType):
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
创建类 对象 流程
class SingletonType(type):
def __init__(self,*args,**kwargs):
print(self)
super(SingletonType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs): # cls 表示 SingletonType类
obj = cls.__new__(cls, *args, **kwargs)
cls.__init__(obj,*args, **kwargs) # 实例化 底下两者效果相同
#obj.__init__(*args, **kwargs)
return obj
class Foo(metaclass=SingletonType):
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
obj = Foo()
元类是用来如何创建类的 正如类是创建对象的模版一样
元类的实例是类 正如类的实例为对象
一个类如果没有声明自己的元类,默认他的元类就是type, 也可以通过继承type来自定义元类
type 实例化结果就是一个类
def __init__(self,name,age):
pass
obj = type('foo',(object,),{'x':1,'__init__':__init__})
#参数一: 类名
#参数二: 继承类
#参数三: 类的属性 方法
View Code
来源: http://www.bubuko.com/infodetail-2456941.html