类的内建函数和用来定制类的特殊方法
两个类的内建函数
一:isinstance()
1 class P1(): 2 3 def __init__(self, name): 4 self.name = name 5 pass 6 7 class P2(P1): 8 A = P1('wang') # 定义类属性!! 9 B = P1('zi') 10 11 print(P2.__dict__) 12 for i, v in P2.__dict__.items(): 13 if i =='A': 14 print(v) 15 print(isinstance(v,P1))
l='<__main__.P1 object at 0x01DF0290>'
print(l)
print(isinstance(l, P1))
运行结果:
{'__module__': '__main__', 'A': <__main__.P1 object at 0x01DF0290>, 'B': <__main__.P1 object at 0x01DF0390>, '__doc__': None} <__main__.P1 object at 0x01DF0290> True
<__main__.P1 object at 0x01DF0290>
False
注意第15行,是v! <__main__.P1 object at 0x01DF0290>这种格式只能被存储,并通过变量传递,不能被赋值。
二:super()
class C(P): def __init__(self): P.__init__(self) ###等价于 class C(P): def __init__(self): super(C,self).__init__()
super用于查找是根据基类的mor()函数查找上一级的。
具体解释参考:
http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html
用来定制类的特殊方法(包括__init__构造器和__del__结构器),它们有些有默认的特定行为,而其他的则没有。
可实现:
重载操作符 + - ...
模拟标准类型 (例子二)
一:__len__内建len()函数
class dog(): def __len__(self): return 100 print(len(dog())) # 100
二:__str__ 表示可打印时的输出,__repr__表示运行时的字符串输出,rept()和‘’操纵符号
class RoundFloat2(): def __init__(self,val): assert isinstance(val,float), 'Value must be a float' self.value = round(val,2)
当你
print(RoundFloat2(3.5))
是无法输出正确的数,输出的是<__main__.RoundFloat2 object at 0x01CFB430>
#要定义__str__和__repr__函数 def __str__(self): return (str(self.value) ) __repr__ = __str__
如果
class RoundFloat2(float): RoundFloat2是继承自float标准类的,就不需要重新定制,因为float类中已经定义好了__str__和__repr__。
三:迭代器(__iter__和__next__)
3.0中引用时用*.next()的方式会出错,用next(*)函数或者*.__next__()的方式
a=range(10) i=iter(a) # for j in range(10): # print(i.__next__()) #这样也行 for j in range(10): print(next(i))
可以自己定义一个迭代器,__iter__仅返回self,对象就被声明为迭代器。
class AnyIter(): #建立迭代器(类) def __init__(self, data, safe=False): self.safe = safe self.iter = iter(data) # iter()函数会检查你传递的是不是一个序列,如果是,用__next__函数根据索引从0迭代到序列结束 def __iter__(self): return self def __next__(self, howmany=2): #内建__next__函数 retval = [] for eachItem in range(howmany): retval.append(self.iter.__next__()) #或者用next(*)迭代 return retval for item in AnyIter(range(10)): #AnyIter(range(10))是一个迭代器,for循环语句中每一次执行一次,就会执行__next__()函数直到遍历结束。 print(item) a= AnyIter(range(10)) for j in range(1,5): print(j,':',a.__next__(j)) #主动调用__next__函数,运行结果
结果为:
[0, 1] [2, 3] [4, 5] [6, 7] [8, 9] 1 : [0] 2 : [1, 2] 3 : [3, 4, 5] 4 : [6, 7, 8, 9]
四: 包装 (__getattr__)
授权
1 class Wrap(): 2 def __init__(self,obj): 3 self.__data = obj 4 def get(self): 5 return self.__data 6 def __str__(self): 7 return '%r' % self.__data 8 def __getattr__(self, attr): 9 return getattr(self.__data,attr) 10 11 a = Wrap(3+5j) 12 print(a) 13 print(a.conjugate()) 14 print(getattr(a,'conjugate')) 15 16 b=Wrap((1,2,3)) 17 print(b.index(2)) 18 #print(b[2]) 会报错
用__getattr__实现继承以后,只有当调用的属性或者方法不能搜索到才调用。
因为复数中存在conjuate属性,所以13行可以调用。
第14行试图去调用conjugate属性,没有找到,所以会去__getattr__中找,所以输出结果为:<built-in method conjugate of complex object at 0x002656E0>。
(getattar 和 __getattar__ 没有大联系,只是getattr找不到属性时,会调用__getattr__进行查找)
第18行的切片操纵不存在列表的方法列表中,不是通过__getitem__()特殊方法实现的,所以它不是属性,不能被访问。执行第18行会试图去调用__getitem__函数,但是__getitem__函数没有作为列表实例的方法进行定义。
上面的结果为:
(3+5j) (3-5j) <built-in method conjugate of complex object at 0x002656E0> 1
授权是包装的一个特性,包装是对一个已经存在的对象增加新的、删除不要的或修改已存在的功能。
下面例子,描述了一个包装文件对象的类。
它的用法完全和open()文件对象一样,只是对write函数进行了自定义,其他所有属性都已授权给文件对象。
1 class CapOpen(): 2 def __init__(self,fn,mode='r'): 3 self.file = open(fn,mode) 4 5 def write(self,line): 6 self.file.write(line.upper()) 7 8 def __getattr__(self, item): 9 return getattr(self.file,item) 10 11 def __iter__(self): 12 return self.file
可以进行下面的操纵。
1 f=CapOpen('sdf','w') 2 f.write('delegation example\n') 3 f.write('fayw is godd\n') 4 f.close() 5 f=CapOpen('sdf','r') 6 for eachline in f: 7 print (eachline)
结果为:
DELEGATION EXAMPLE
FAYW IS GODD