一、isinstance(obj, cls)
检查obj是否是类cls的对象。
class Foo: pass obj = Foo() print(isinstance(obj,Foo))
二、issubclass(sub, super)
检查sub类是否是 super 类的派生类
class Foo: pass class Bar(Foo): pass issubclass(Bar,Foo)
三、__setattr__,__getattr__,__delattr__
上述三个函数,具体如何使用,请看代码:
__setattr__:对属性进行赋值或者修改的时候被调用。
class Foo: def __init__(self,name): self.name = name def __setattr__(self, key, value): # self.__dict__[key] = value print('我执行了') f = Foo('alex') # 凡是对属性赋值或者修改操作,都触发__setattr__的执行 f.x = 3 # 触发__setattr__执行 print(f.__dict__) #######输出结果############# 我执行了 我执行了 {}
从上面结果可以看出,当我们设置属性或者给属性赋值的时候,会调用__setattr__的执行。但为什么对象f的名称空间没有我们设置的name和x两个变量呢?原因是:因为你重写了__setattr__功能,对它并没有进行任何操作,仅仅只有一条语句,而默认的__setattr__会将属性按照键值对写入对象的名称空间。如果自己重写了__setattr__,但是又没有进行任何操作,要想完成对象属性的赋值操作,必须得通过以下方式才能实现:
f.__dict__['name'] = xiaohua print(f.name) ##输出结果### xiaohua
所以,如果我们自己要重写__setattr__方法,必须按照如下方式来做:
def __setattr__(self, key, value): self.__dict__[key] = value
__getattr__:只有在调用属性时且属性不存在的情况下,触发這个函数的执行。
class Foo: def __init__(self,name): self.name = name def __getattr__(self, item): print('没有你要找的元素') f = Foo('alex') f.x = 3 print(f.__dict__) #####输出结果###### {'name': 'alex', 'x': 3} # 此时对象名称空间有两个属性值
当我们重写了__getattr__方法后,并且试图调用一个不存在的属性值:
class Foo: def __init__(self,name): self.name = name def __getattr__(self, item): print('没有你要找的元素') f = Foo('alex') f.x = 3 print(f.__dict__) f.a # 调用一个不存在的属性值 ########输出结果######## 没有你要找的元素
由结果分析,正如我们之前所说的,调用一个不存在的属性值时,会触发__setattr__的执行。所以,一般将getattr设置为如下样式:
def __getattr__(self, item): return self.__dict__[item]
__delattr__:当删除一个对象的属性值时,会触发delattr的执行。
class Foo: def __init__(self,name): self.name = name def __delattr__(self, item): print('我执行了') f = Foo('alex') f.x = 3 del f.name # 触发delattr的执行 ###输出结果###### 我执行了
一般重写为:
def __delattr__(self, item): del self.__dict__[item]
四、__getitem__,__setitem__,__delitem__
我们在列表中学过这种取元素的方式。比如说lst = [1,2,3,4],取第一个元素 lst[0],又或者在字典中dd ={'name':'xiaohua'} 取元素dd['name']。实际上,这种取元素的方式,与__getitem__,__setitem__,__delitem__三个函数有关。
下面,我们一一来看看上述三个函数的用法:
__getitem__:当我们想要按照 obj[attr]方式调用对象的属性时,触发这个函数的执行
class Foo: def __init__(self,name): self.name = name def __getitem__(self, item): print('我执行了') f = Foo('alex') print(f.__dict__) # 对象的名称空间只有一个属性 f['name'] # 触发getitem执行 #####输出结果######## {'name': 'alex'} 我执行了
从上面结果,可以看出,当我试图以f['name']方式调用属性的时候,就会触发__getitem__执行。一般将__getitem__设置为如下:
def __getitem__(self, item): return self.__dict__[item] print(f['name']) ###正常输出######
__setitem__:当我以f['name'] = 'xiaohua' 方式修改对象属性值的时候,会触发该函数的执行。
class Foo: def __init__(self,name): self.name = name def __setitem__(self, key, value): print('我执行了') f = Foo('alex') print(f.__dict__) f['x'] = 3 # 触发setitem执行 #########输出结果######### 我执行了
一般将setitem设置为如下,当然你也可以按照自己的方式进行设置。
class Foo: def __init__(self,name): self.name = name def __setitem__(self, key, value): self.__dict__[key] = value f = Foo('alex') print(f.__dict__) f['x'] = 3 print(f.__dict__) ###输出结果####### {'name': 'alex'} {'name': 'alex', 'x': 3}
__delitem__:当以del f['name'] 方式删除对象的属性值时,会触发這个函数的执行
class Foo: def __init__(self,name): self.name = name def __delitem__(self, key): print('我执行了') f = Foo('alex') print(f.__dict__) del f['name'] # 触发delitem执行 ####输出结果##### {'name': 'alex'} 我执行了
一般设置为如下方式:
class Foo: def __init__(self,name): self.name = name def __delitem__(self, key): del f.__dict__[key] f = Foo('alex') print(f.__dict__) del f['name'] print(f.__dict__)
五、__str__,__repr__
先来一段代码,再来引入我们的正题:
lst = list([1,2,3,4]) class Foo: def __init__(self,name): self.name = name f = Foo('xiaohua') print(lst) print(f) ######输出结果######### [1, 2, 3, 4] <__main__.Foo object at 0x0000005FE8BC9208>
我们都知道在python里面,list是一种数据类型,而且也是一个类。当我们以list()来创建一个序列时,我们也就创建了一个List对象。如上面的lst,知道了lst是List类型的对象后,我们print(lst)时,为什么没有像f一样,打印出对象的内存地址,而是直接打印出给对象赋的值呢?其实,这一切是因为在list类的内部,实现了__str__功能所导致的。下面,我们通过一些实例,来理解__str__的用法。
class Foo: def __init__(self,name): self.name = name def __str__(self): return '我执行了' f = Foo('xiaohua') print(f) #######输出结果############ 我执行了
看,当我再次打印对象的时候,没有打印出对象的内存地址,而是打印出了我们设定的值。__str__就是帮我们实现这种功能的!我们可以定制自己__str__,让他返回一些有意义的信息。
def __str__(self): return 'name:%s' % self.name print(f) ####输出结果##### name:xiaohua
如上所示,现在我们可以理解,为什么打印列表对象lst的时候,会返回[1,2,3,4]了吧。
注意:__str__:只能返回一个字符串类型
理解了__str__后,__repr__就很好理解了。它和__str__一样,也是在打印对象的时候,会触发這个函数的执行。
六、__new__,__del__,
__new__:创建对象时被调用,比__init__先执行。
class Foo(object): def __init__(self): print('init') def __new__(cls, *args, **kwargs): print('new %s' %cls) return object.__new__(cls, *args, **kwargs) Foo() ###输出结果####### new <class '__main__.Foo'> # 比init先打印 init
从上面,我们可以总结出如下几点:
继承自object的新式类才有__new__
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行:
class A(object): pass class B(A): def __init__(self): print('init') def __new__(cls, *args, **kwargs): print('new %s' % cls) return object.__new__(A, *args, **kwargs) b = B() print(type(b)) 输出结果: new <class '__main__.B'> <class '__main__.A'>
__del__:在对象被删除或者程序执行完毕后,被调用
# 以下代码执行完毕后,自动执行del class B: def __del__(self): print('我执行了') b = B() ######输出结果######### 我执行了
#显式调用del来删除对象时,触发__del__执行 import time class B: def __del__(self): print('我执行了') b = B() del b # 触发__del__执行 time.sleep(5) print('主程序结果') ###输出结果#### 我执行了 #等待5秒 主程序结果