isinstance(obj, cls)、issubclass(sub, super)
isinstance(obj, cls)
检查对象obj是否是类cls的对象
#例1
class Foo(object):
pass
f = Foo()
isinstance(f, Foo) # True
#例2
class Foo(object):
pass
class Bar(Foo):
pass
print(isinstance(Bar(), Foo)) #True
f = Foo()
b = Bar()
type(b) == Foo #False
type(f) == Foo #True
'''
注意:type和isinstance的区别:type(子类对象) 不会等于子类的父类,type(子类对象)会等于子类。
isinstance(子类对象,父类) = True
isinstance会把子类对象当做父类的一种实例
'''
issubclass(sub, super)
检查sub类是否是super类的子类
class Foo(object):
pass
class Bar(Foo):
pass
issubclass(Bar, Foo)
类中的魔法函数
__ str __ 和 __ repr __
会在对象被转换为字符串时,转换的结果就是这个函数的返回值
format_dict={
'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School():
def __init__(self, name, addr, type):
self.name = name
self.addr = addr
self.type = type
def __str__(self): # print和str用
return '(%s,%s)' %(self.name,self.addr)
def __repr__(self): # 交互式解释器和repr()
return 'School(%s,%s)' %(self.name,self.addr)
def __format__(self, format_spec):
if not format_spec or format_spec not in format_dict:
format_spec = 'nat'
fmt = format_dict[format_spec]
return fmt.format(obj=self)
s1=School('oldboy','北京','私立')
print('from repr:', repr(s1)) # from repr: School(oldboy,北京)
print('from str:', str(s1)) # from str: (oldboy,北京)
print(s1) # (oldboy, 北京)
print(format(s1,'nat')) # oldboy-北京-私立
print(format(s1,'tna')) # 私立:oldboy:北京
print(format(s1,'tan')) # 私立/北京/oldboy
print(format(s1,'asfdasdffd')) # oldboy-北京-私立
注意:str函数或者print函数,调用:obj.__ str __()
repr或者交互式解释器,调用:obj.__ repr __()
如果 __ str __ 没有被定义, 那么就会使用 __ repr __ 来代替输出
这两个方法的返回值必须是字符串,否则抛出异常
class B:
def __str__(self):
return 'str : class B'
def __repr__(self):
return 'repr : class B'
b=B()
print('%s'%b) # str : class B
print('%r'%b) # repr : class B
__ del __
执行时机:
1、手动删除对象时立马执行,
2、程序结束时自动执行
使用场景:当你的对象在使用过程中,打开了不属于解释器的资源,如:文件、网络端口
# del使用案例
class FileTool:
"""该类用于简化文件的读写操作 """
def __init__(self,path):
self.file = open(path,"rt",encoding="utf-8")
self.a = 100
def read(self):
return self.file.read()
# 在这里可以确定一个事,这个对象肯定不使用了 所以可以放心的关闭问文件了
def __del__(self):
self.file.close()
tool = FileTool("a.txt")
print(tool.read())
__ call __
执行时机:在调用对象时自动执行,(既对象加括号)。当 对象()时
class A:
def __del__(self): #程序运行结束自动执行
print('del run')
def __call__(self, x, y):
print('call run')
print('x', x)
print('y', y)
a = A()
a(1, 2)
'''
call run
x 1
y 2
del run
'''
__ slots __
该属性是一个类属性,用于优化对象内存占用。优化的原理:将不固定的属性,固定了。解释器就不会为这个类创建名称空间,所以__ dict __没了!
从而达到减小开销的作用。
类中出现了__ slots __,将导致这个类的对象无法添加新的数据属性。
class A:
__slots__ = ['name']
def __init__(self, name):
self.name = name
a = A('小花')
print(a.name) # 小花
print(a.__dict__) # AttributeError: 'A' object has no attribute '__dict__'
a.age = 1 # AttributeError: 'A' object has no attribute 'age'
attr系列
class Foo:
x = 1
def __init__(self, y):
self.y = y
def __getattr__(self, item):
print('----> from getattr:你找的属性不存在')
def __setattr__(self, key, value):
print('----> from setattr')
# self.key = value # 这就无限递归了,你好好想想
# self.__dict__[key] = value # 应该使用它
def __delattr__(self, item):
print('----> from delattr')
# del self.item # 无限递归了
self.__dict__.pop(item)
f1 = Foo(10)
__ getattr __
只有在使用 点 . 调用属性且属性不存在的时候才会触发
class A:
x = 10
def __getattr__(self, item): #用.的时候且当属性不存在时触发
print('from __getattr__:你找的属性不存在')
a = A()
print(a.x) # 10
a.y = 2 #这时候是调用那个__setattr__方法,__dict__ = {'y':2}
print(a.z) # z不存在,所以调用__getattr__方法 from __getattr__:你找的属性不存在
print(a.__dict__) {'y':2}
__ setattr __
添加、修改属性时会触发它的执行
class A:
def __setattr__(self, key, value):
print(key) # a
print(value) # 1
self.__dict__[key] = value #这句话不写,对象就永远添加不了值
a = A()
a.a = 'a'
a.a = '1'
print(a.__dict__) # {'a':1}
__ delattr __
删除属性的时候会触发
class A:
def __delattr__(self, item):
print(item) # b
self.__dict__.pop(item) #如果没有这句话,删除对象属性就永远不起作用
a = A()
a.b = 'a'
del a.b
print(a.__dict__)
item系列
__ setitem __
中括号赋值时触发
class A:
def __setitem__(self, key, value):
print('setitem')
print(key) # 1
print(value) # 2
self.__dict__[key] = value #添加进名称空间中
a = A()
a[1] = 2
print(a.__dict__)
__ getitem __
中括号取值时触发
class A:
def __getitem__(self, item):
print(item) # 1
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
a = A()
a[1] = 2
print(a.__dict__) # {1:2}
a[1] = 4
print(a.__dict__) # {1:4}
print(a[1]) # 4
__ delitem __
中括号删除时触发
class A:
def __getitem__(self, item):
print(item)
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
self.__dict__.pop(key)
a = A()
a[1] = 2
print(a.__dict__)
a[1] = 4
print(a.__dict__)
print(a[1])
del a[1] #触发__delitem__
print(a.__dict__)
attr/item总结
attr:对象.属性 的实现原理
item: 对象[属性] 的实现原理
class AttrItem():
def __setattr__(self, key, value): # 用对象.增加修改时,调用此方法
self.__dict__[key] = value
def __getattr__(self, item): # 用对象.取值时,调用此方法
return self.__dict__[item]
def __delattr__(self, item): # del 对象.属性时,调用此方法
self.__dict__.pop(item)
def __setitem__(self, key, value): # 对象[属性],增加修改时,调用此方法
self.__dict__[key] = value
def __getitem__(self, item):
return self.__dict__[item] # 对象[属性]取值时,调用此方法
def __delitem__(self, key): # del 对象[属性] 时,调用此方法
self.__dict__.pop(key)
运算符重载:
当我们需要自定义对象的比较规则时,就可以在子类中覆盖 大于(__ gl __ )、等于( __ eq __ )、小于( __ lt __ ) 等方法
注意:
1、比较的是对象之间的的属性。重写比较方法。
2、other指的是另一个参与比较的对象。
3、大于和小于只要实现一个即可,符号如果不同 解释器会自动交换两个对象的位置
class Student(object):
def __init__(self,name,height,age):
self.name = name
self.height = height
self.age = age
def __gt__(self, other):
return self.height > other.height
def __lt__(self, other):
return self.height < other.height
def __eq__(self, other):
if self.name == other.name and self.age == other.age and self.height == other.height:
return True
return False
stu1 = Student("jack",180,28)
stu2 = Student("jack",180,28)
# print(stu1 < stu2)
print(stu1 == stu2)
迭代器协议
'''
迭代器是指具有__iter__和__next__的对象
我们可以为对象增加这两个方法来让对象变成一个迭代器
'''
class MyRange:
def __init__(self,start,end,step):
self.start = start
self.end = end
self.step = step
def __iter__(self): #调用__iter__ 要返回的对象就是迭代器
return self
def __next__(self):
a = self.start
self.start += self.step
if a < self.end:
return a
else:
raise StopIteration # for循环每循环一次,就调用一次__next__,结束时要返回一个抛出异常让for循环接收。
for i in MyRange(1,10,2):
print(i)