一、isinstance(obj,cls)和issubclass(sub, super)
1.1 isinstance
isinstance(obj,cls)检查obj是否是类cls的对象 包括继承关系
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 print (isinstance(obj, Foo)) # True
1.2 issubclass
issubclass(sub, super)检查sub类是否是super类的派生类 判断类与类之间的继承关系
1 class Foo(object): 2 pass 3 4 5 class Bar(Foo): 6 pass 7 8 9 print (issubclass(Bar, Foo)) # True
二、特殊方法
跟运算符无关的特殊方法:
类别 | 方法名 |
字符串 / 字节序列表示形式 | __repr__、 __str__、 __format__、 __bytes__ |
数值转换 | __abs__、 __bool__、 __complex__、 __int__、 __float__、 __hash__、 __index__ |
集合模拟 | __len__、 __getitem__、 __setitem__、 __delitem__、__contains__ |
迭代枚举 | __iter__、 __reversed__、 __next__ |
可调用模拟 | __call__ |
上下文管理 | __enter__、 __exit__ |
实例创建和销毁 | __new__、 __init__、 __del__ |
属性管理 | __getattr__、 __getattribute__、 __setattr__、 __delattr__、 __dir__ |
属性描述符 | __get__、 __set__、 __delete__ |
跟类相关的服务 | __prepare__、 __instancecheck__、 __subclasscheck__ |
类名 | 方法名和对应的运算符 |
一元运算符 | __neg__ -、 __pos__ +、 __abs__ abs() |
众多比较运算符 | __lt__ <、 __le__ <=、 __eq__ ==、 __ne__ !=、 __gt__ >、 __ge__ >= |
算术运算符 | __add__ +、 __sub__ -、 __mul__ *、 __truediv__ /、 __floordiv__ //、 __mod__ %、 __divmod__ |
反向算术运算符 | __radd__、 __rsub__、 __rmul__、 __rtruediv__、 __rfloordiv__、 __rmod__、 __rdivmod__、 __rpow__ |
增量赋值算术运算符 | __iadd__、 __isub__、 __imul__、 __itruediv__、 __ifloordiv__、 __imod__、 __ipow__ |
位运算符 | __invert__ ~、 __lshift__ <<、 __rshift__ >>、 __and__ &、 __or__ |、 __xor__ ^ |
反向位运算符 | __rlshift__、 __rrshift__、 __rand__、 __rxor__、 __ror__ |
增量赋值位运算符 | __ilshift__、 __irshift__、 __iand__、 __ixor__、 __ior__ |
2.1 __setattr__, __delattr__, __getattr__
- __setattr__ 添加/修改属性会触发它的执行
-
__delattr__ 删除属性的时候会触发
-
__getattr__ 只有在调用属性且属性不存在的时候才会触发
1 # 三者的用法演示 2 class Foo: 3 x = 1 4 def __init__ (self, y): 5 self.y = y 6 7 def __getattr__ (self, item): 8 print ( ' ----> from getattr:你找的属性不存在 ' ) 9 10 def __setattr__ (self, key, value): 11 print ( ' ----> from setattr ' ) 12 # self.key=value # 这就无限递归了,你好好想想 13 self. __dict__ [key] = value # 应该使用它 14 15 def __delattr__ (self, item): 16 print ( ' ----> from delattr ' ) 17 # del self.item #无限递归了 18 self. __dict__ .pop(item) 19 20 # __setattr__ 添加/修改属性会触发它的执行 21 f1=Foo(10 ) 22 print (f1. __dict__ ) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 23 f1.z=3 24 print (f1. __dict__ ) 25 26 # __delattr__ 删除属性的时候会触发 27 f1. __dict__ [ ' a ' ]=3 # 我们可以直接修改属性字典,来完成添加/修改属性的操作 28 del f1.a 29 print (f1. __dict__ ) 30 31 # __getattr__ 只有在使用点调用属性且属性不存在的时候才会触发 32 f1.xxxxxx
2.2 __getattribute__
__getattribute__ : 不管有没有属性都会执行到,当__getattribute__和__getattr__同时存在时,只有当__getattribute__抛出AttributeError的异常时,才会执行到__getattr__,否则会一直执行__getattribute__
1 class Foo(object): 2 3 def __init__ (self, x): 4 self.x = x 5 6 def __getattr__ (self, item): 7 print ( " 执行的是__getattr__ " ) 8 9 def __getattribute__ (self, item): 10 print ( " 执行的是getattribute " ) 11 raise AttributeError( " 抛出异常了 " ) # 只有抛出AttributeError的异常时,找不到属性才会执行__getattr__方法 12 13 14 f1 = Foo(10 ) 15 f1.x 16 f1.xxx
2.3 __getitem__、__setitem__、__delitem__
-
__getitem__ 以字典形式获取属性时,触发__getitem__
-
__setitem__ 以字典形式设置属性时,触发__setitem__
-
__delitem__ 删除字典的key值时,会触发__delitem__
1 class Foo(object): 2 3 def __getitem__ (self, item): 4 print ( " getitem----->%s " % item) 5 return self. __dict__ .get(item) 6 7 def __setitem__ (self, key, value): 8 print ( " setitem---->%s %s " % (key, value)) 9 self. __dict__ [key] = value 10 11 def __delitem__ (self, key): 12 print ( " delitem----->%s " % key) 13 self. __dict__ .pop(key) 14 15 16 f1 = Foo() 17 print (f1. __dict__ ) 18 19 f1[ ' name ' ] = ' zhangsan ' 20 print (f1. __dict__ ) 21 22 print (f1[ ' name ' ]) 23 24 del f1[ ' name ' ] 25 26 print (f1. __dict__ )
2.4 __str__、__repr__、__format__
1 class School(object): 2 3 def __init__ (self, name, age): 4 self.name = name 5 self.age = age 6 7 def __str__ (self): 8 return ' 名字是%s,年龄是%s ' % (self.name, self.age) 9 10 def __repr__ (self): # 只有当__str__没有定义时,才会执行 11 return ' aaa ' 12 13 14 f1 = School( ' alex ' , ' 23 ' ) 15 print (f1) 16 17 # 在子类中使用__str__,先找子类的__str__,没有的话向上找,只要父类不是object,就执行父类的__str__ 18 # 但是如果除了object之外的父类都没有__str__方法,就执行子类的__repr__方法,如果子类也没有,还要向上找父类的__repr__方法 19 # 一直找不到,再执行object类中的__str__方法
__format__ 格式化对象的字符串格式:
1 date_dic = { 2 ' ymd ' : ' {0.year}:{0.month}:{0.day} ' , 3 ' dmy ' : ' {0.day}/{0.month}/{0.year} ' , 4 ' mdy ' : ' {0.month}-{0.day}-{0.year} ' , 5 } 6 7 8 class Date(object): 9 def __init__ (self, year, month, day): 10 self.year = year 11 self.month = month 12 self.day = day 13 14 def __format__ (self, format_spec): 15 if not format_spec or format_spec not in date_dic: 16 format_spec = ' ymd ' 17 fmt = date_dic[format_spec] 18 return fmt.format(self) 19 20 21 d1 = Date(2016, 12, 29 ) 22 print (format(d1)) 23 print ( ' {:mdy} ' .format(d1)) 24 print (format(d1, ' ymd ' ))
2.5 __slots__
1 class Foo(object): 2 # 创建完后,该类就不具有__dict__属性 3 __slots__ = [ ' name ' , ' age ' ] 4 5 6 f1 = Foo() 7 f1.name = ' alex ' 8 f1.age = 18 9 print (f1.name) 10 11 f1.gender = ' male ' # 会报错 'Foo' object has no attribute 'gender'
2.6 __doc__
该属性的无法被继承
1 class Foo: 2 """ 3 我是描述信息 4 """ 5 pass 6 7 8 class Bar(Foo): 9 pass 10 11 12 print (Foo. __doc__ ) # 我是描述信息 13 print (Bar. __doc__ ) # None
2.7 __module__和__class__
1 # !/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class C: 5 6 def __init__ (self): 7 self.name = ‘SB ' 8 9 # lib/aa.py
1 from lib.aa import C 2 3 obj = C() 4 print (obj. __module__ ) # 输出 lib.aa,即:输出模块 5 print (obj. __class__ ) # 输出 lib.aa.C,即:输出类
2.8 __del__
1 class Foo(object): 2 3 def __init__ (self, name): 4 self.name = name 5 6 def __del__ (self): 7 print ( " 我被删除了 " ) 8 9 10 f1 = Foo( ' alex ' ) 11 del f1
2.9 __call__
class Foo(object): def __call__ (self, *args, ** kwargs): print ( " hello world " ) f1 = Foo() f1() Foo()()
2.10 描述符(__get__、__set__、__delete__)
class Foo(object): # 在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符 def __get__ (self, instance, owner): pass def __set__ (self, instance, value): pass def __delete__ (self, instance): pass
2.描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中
1 class Foo(object): 2 3 def __get__ (self, instance, owner): 4 print ( " get方法 " ) 5 6 def __set__ (self, instance, value): 7 print ( " set方法 " ) 8 # instance.__dict__['x'] = value 9 10 def __delete__ (self, instance): 11 print ( " delete方法 " ) 12 13 14 class Bar(object): 15 16 x = Foo() 17 18 19 b1 = Bar() 20 b1.x = 1 # 触发__set__方法的执行 21 print (b1. __dict__ ) # dict中为空 22 b1.x # 触发__get__方法的执行 23 del b1.x # 触发__delete__方法的执行
-
数据描述符:至少实现了__get__()和__set__()
-
非数据描述符:没有实现__set__()
-
描述符本身应该定义成新式类,被代理的类也应该是新式类
-
必须把描述符定义成这个类的类属性,不能为定义到构造函数中
-
要严格遵循该优先级,优先级由高到底分别是
-
类属性
-
数据描述符
-
实例属性
-
非数据描述符
-
找不到的属性触发__getattr__()
类属性>数据描述符
1 # 描述符Str 2 class Str: 3 def __get__ (self, instance, owner): 4 print ( ' Str调用 ' ) 5 def __set__ (self, instance, value): 6 print ( ' Str设置... ' ) 7 def __delete__ (self, instance): 8 print ( ' Str删除... ' ) 9 10 11 class People: 12 name= Str() 13 def __init__ (self,name,age): # name被Str类代理,age被Int类代理, 14 self.name= name 15 self.age= age 16 17 18 # 基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典 19 20 # 那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错 21 People.name # 恩,调用类属性name,本质就是在调用描述符Str,触发了__get__() 22 23 People.name= ' egon ' # 那赋值呢,我去,并没有触发__set__() 24 del People.name # 赶紧试试del,我去,也没有触发__delete__() 25 # 结论:描述符对类没有作用-------->傻逼到家的结论 26 27 ''' 28 原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级 29 People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__() 30 31 People.name='egon' # 那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__() 32 del People.name #同上 33 '''
数据描述符>实例属性
1 # 描述符Str 2 class Str: 3 def __get__ (self, instance, owner): 4 print ( ' Str调用 ' ) 5 def __set__ (self, instance, value): 6 print ( ' Str设置... ' ) 7 def __delete__ (self, instance): 8 print ( ' Str删除... ' ) 9 10 11 class People: 12 name= Str() 13 def __init__ (self,name,age): # name被Str类代理,age被Int类代理, 14 self.name= name 15 self.age= age 16 17 18 p1=People( ' egon ' ,18 ) 19 20 21 # 如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性 22 p1.name= ' egonnnnnn ' 23 p1.name 24 print (p1. __dict__ ) # 实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了 25 del p1.name
实例属性 > 非数据描述符
1 class Foo: 2 def func(self): 3 print ( ' 我胡汉三又回来了 ' ) 4 5 f1 = Foo() 6 f1.func() # 调用类的方法,也可以说是调用非数据描述符 7 # 函数是一个非数据描述符对象(一切皆对象么) 8 print (dir(Foo.func)) 9 print (hasattr(Foo.func, ' __set__ ' )) 10 print (hasattr(Foo.func, ' __get__ ' )) 11 print (hasattr(Foo.func, ' __delete__ ' )) 12 # 有人可能会问,描述符不都是类么,函数怎么算也应该是一个对象啊,怎么就是描述符了 13 # 笨蛋哥,描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么 14 # 函数就是一个由非描述符类实例化得到的对象 15 # 没错,字符串也一样 16 17 f1.func= ' 这是实例属性啊 ' 18 print (f1.func) 19 20 21 del f1.func # 删掉了非数据 22 f1.func()
再次验证:实例属性>非数据描述符
1 class Foo: 2 def __set__ (self, instance, value): 3 print ( ' set ' ) 4 def __get__ (self, instance, owner): 5 print ( ' get ' ) 6 class Room: 7 name= Foo() 8 def __init__ (self,name,width,length): 9 self.name= name 10 self.width= width 11 self.length= length 12 13 14 15 16 # name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级 17 # 对实例的属性操作,触发的都是描述符的 18 r1=Room( ' 厕所 ' ,1,1 ) 19 r1.name 20 r1.name= ' 厨房 ' 21 22 23 24 class Foo: 25 def __get__ (self, instance, owner): 26 print ( ' get ' ) 27 28 class Room: 29 name= Foo() 30 def __init__ (self,name,width,length): 31 self.name= name 32 self.width= width 33 self.length= length 34 35 36 37 # name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级 38 # 对实例的属性操作,触发的都是实例自己的 39 r1=Room( ' 厕所 ' ,1,1 ) 40 r1.name 41 r1.name= ' 厨房 '
非数据描述符>找不到
1 class Foo: 2 def func(self): 3 print ( ' 我胡汉三又回来了 ' ) 4 5 6 def __getattr__ (self, item): 7 print ( ' 找不到了当然是来找我啦 ' ,item) 8 9 10 f1= Foo() 11 f1.xxxxxxxxxxx # 找不到,调用__getattr__方法
1 class Typed(object): 2 def __init__ (self,name,expected_type): 3 self.name= name 4 self.expected_type= expected_type 5 6 def __get__ (self, instance, owner): 7 print ( ' get---> ' ,instance,owner) 8 if instance is None: 9 return self 10 return instance. __dict__ [self.name] 11 12 def __set__ (self, instance, value): 13 print ( ' set---> ' ,instance,value) 14 if not isinstance(value,self.expected_type): 15 raise TypeError( ' Expected %s ' % str(self.expected_type)) 16 instance. __dict__ [self.name]= value 17 18 def __delete__ (self, instance): 19 print ( ' delete---> ' ,instance) 20 instance. __dict__ .pop(self.name) 21 22 23 class People(object): 24 name=Typed( ' name ' ,str) 25 age=Typed( ' name ' ,int) 26 salary=Typed( ' name ' ,float) 27 def __init__ (self,name,age,salary): 28 self.name= name 29 self.age= age 30 self.salary= salary 31 32 p1=People(123,18,3333.3 ) 33 p1=People( ' egon ' , ' 18 ' ,3333.3 ) 34 p1=People( ' egon ' ,18,3333)
6.类装饰器
1 # 检查对象属性的类型 2 class Typed(object): 3 def __init__ (self, name, expected_type): 4 self.name = name 5 self.expected_type = expected_type 6 7 def __get__ (self, instance, owner): 8 print ( ' get---> ' , instance, owner) 9 if instance is None: 10 return self 11 return instance. __dict__ [self.name] 12 13 def __set__ (self, instance, value): 14 print ( ' set---> ' , instance, value) 15 if not isinstance(value,self.expected_type): 16 raise TypeError( ' Expected %s ' % str(self.expected_type)) 17 instance. __dict__ [self.name] = value 18 19 def __delete__ (self, instance): 20 print ( ' delete---> ' , instance) 21 instance. __dict__ .pop(self.name) 22 23 24 def typeassert(** kwargs): 25 def decorate(cls): 26 print ( ' 类的装饰器开始运行啦------> ' ,kwargs) 27 for name,expected_type in kwargs.items(): 28 setattr(cls,name,Typed(name,expected_type)) 29 return cls 30 return decorate 31 32 # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) 33 @typeassert(name=str,age=int,salary= float) 34 class People: 35 def __init__ (self,name,age,salary): 36 self.name= name 37 self.age= age 38 self.salary= salary 39 40 41 print (People. __dict__ ) 42 p1 = People( ' egon ' , 18, 3333.3)
1 class LazyProperty(object): 2 3 def __init__ (self, func): 4 self.func = func 5 6 def __get__ (self, instance, owner): 7 # print(self.func) 8 # print(instance) 9 # print(owner) 10 # print("haha") 11 return self.func(instance) 12 13 14 class Room(object): 15 16 def __init__ (self, name, width, length): 17 self.name = name 18 self.width = width 19 self.length = length 20 21 @LazyProperty # 相当于 area = LazyProperty(area) 22 def area(self): 23 return self.width * self.length 24 25 26 r1 = Room( " 卧室 " , 2, 3 ) 27 print (r1.area)
实现缓存计算的功能
1 class Lazyproperty: 2 def __init__ (self,func): 3 self.func= func 4 5 def __get__ (self, instance, owner): 6 print ( ' 这是我们自己定制的静态属性,r1.area实际是要执行r1.area() ' ) 7 if instance is None: 8 return self 9 else : 10 print ( ' ---> ' ) 11 value = self.func(instance) 12 setattr(instance, self.func. __name__ ,value) # 计算一次就缓存到实例的属性字典中 13 return value 14 15 class Room: 16 def __init__ (self,name,width,length): 17 self.name= name 18 self.width= width 19 self.length= length 20 21 @Lazyproperty # area=Lazyproperty(area) 相当于'定义了一个类属性,即描述符' 22 def area(self): 23 return self.width * self.length 24 25 r1=Room( ' alex ' ,1,1 ) 26 print (r1.area) # 先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法 27 print (r1.area) # 先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
做了一点小改动,缓存计算的功能就失效了
1 # 缓存不起来了 2 3 class Lazyproperty: 4 def __init__ (self,func): 5 self.func= func 6 7 def __get__ (self, instance, owner): 8 print ( ' 这是我们自己定制的静态属性,r1.area实际是要执行r1.area() ' ) 9 if instance is None: 10 return self 11 else : 12 value= self.func(instance) 13 instance. __dict__ [self.func. __name__ ]= value 14 return value 15 # return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情 16 17 def __set__ (self, instance, value): 18 print ( ' hahahahahah ' ) 19 20 class Room: 21 def __init__ (self,name,width,length): 22 self.name= name 23 self.width= width 24 self.length= length 25 26 @Lazyproperty # area=Lazyproperty(area) 相当于定义了一个类属性,即描述符 27 def area(self): 28 return self.width * self.length 29 30 print (Room. __dict__ ) 31 r1=Room( ' alex ' ,1,1 ) 32 print (r1.area) 33 print (r1.area) 34 print (r1.area) 35 print (r1.area) # 缓存功能失效,每次都去找描述符了,为何,因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
2.11 上下文管理协议(__enter__和__exit__)
上下文管理协议: 即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
1 # 上下文管理协议 2 class Open: 3 def __init__ (self,name): 4 self.name= name 5 6 def __enter__ (self): 7 print ( ' 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 ' ) 8 # return self 9 10 def __exit__ (self, exc_type, exc_val, exc_tb): 11 print ( ' with中代码块执行完毕时执行我啊 ' ) 12 13 14 # with Open--》触发Open.__enter__,拿到返回值 15 # as f ---> f = __enter__的返回值 16 # with Open('a.txt') as f =======> f = Open('a.txt') 17 with Open( ' a.txt ' ) as f: 18 print ( ' =====>执行代码块 ' ) 19 # print(f,f.name)
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
1 class Open: 2 def __init__ (self,name): 3 self.name= name 4 5 def __enter__ (self): 6 print ( ' 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 ' ) 7 8 def __exit__ (self, exc_type, exc_val, exc_tb): 9 print ( ' with中代码块执行完毕时执行我啊 ' ) 10 print (exc_type) 11 print (exc_val) 12 print (exc_tb) 13 14 15 16 with Open( ' a.txt ' ) as f: 17 print ( ' =====>执行代码块 ' ) 18 raise AttributeError( ' ***着火啦,救火啊*** ' ) 19 print ( ' 0 ' *100) # ------------------------------->不会执行
如果__exit__()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
1 class Open(object): 2 3 def __init__ (self, name): 4 self.name = name 5 6 def __enter__ (self): 7 print ( " 执行enter " ) 8 return self 9 10 def __exit__ (self, exc_type, exc_val, exc_tb): 11 print ( " 执行exit " ) 12 print (exc_type) 13 print (exc_val) 14 print (exc_tb) 15 return True # 包容了with中的异常,返回true,会正常结束with语句,会继续执行with后的语句;如果不包容异常,则出现异常就会停止 16 17 18 with Open( ' aa ' ) as f: 19 print (f) 20 raise Exception( " aa " ) 21 22 print ( " bbb " )
2.12 __dict__
1 class Province: 2 3 country = ' China ' 4 5 def __init__ (self, name, count): 6 self.name = name 7 self.count = count 8 9 def func(self, *args, ** kwargs): 10 print ' func ' 11 12 13 # 获取类的成员,即:静态字段、方法、 14 print Province. __dict__ 15 # 输出:{'country': 'China', '__module__': '__main__', 'func':, '__init__': 16 17 18 obj1 = Province( ' HeBei ' ,10000 ) 19 print obj1. __dict__ 20 # 获取 对象obj1 的成员 21 # 输出:{'count': 10000, 'name': 'HeBei'} 22 23 24 obj2 = Province( ' HeNan ' , 3888 ) 25 print obj2. __dict__ 26 # 获取 对象obj1 的成员 27 # 输出:{'count': 3888, 'name': 'HeNan'}, '__doc__': None}
2.13 __new__ 构造方法
__init__ 初始化方法
1 class Single(object): 2 3 __instance = None 4 5 def __new__ (cls, *args, ** kwargs): 6 if cls. __instance is None: 7 cls. __instance = object. __new__ (cls) 8 return cls. __instance 9 10 11 def __init__ (self): 12 print ( " init " ) 13 14 15 # 开辟一个空间,属于对象的 16 # 把对象的空间传给self,执行init 17 # 将这个对象的空间返回给调用者 18 obj = Single() 19 obj2 = Single() 20 print (id(obj), id(obj2)) 21 22 23 # 单例:如果一个类,从头到尾只能有一个实例,那么这个类就是一个单例类
2.14 __len__
1 class A: 2 def __init__ (self): 3 self.a = 1 4 self.b = 2 5 6 7 def __len__ (self): 8 return len(self. __dict__ ) 9 a = A() 10 print (len(a))
2.15 __hash__
1 class A: 2 def __init__ (self): 3 self.a = 1 4 self.b = 2 5 6 7 def __hash__ (self): 8 return hash(str(self.a)+ str(self.b)) 9 a = A() 10 print (hash(a))
2.16 __eq__
1 class A: 2 def __init__ (self): 3 self.a = 1 4 self.b = 2 5 6 7 def __eq__ (self,obj): 8 if self.a == obj.a and self.b == obj.b: 9 return True 10 a = A() 11 b = A() 12 print (a == b)
2.17 __bool__
bool(x) 的背后,调用的就是__bool__()方法. 如果不存在 __bool__ 方法, 那么 bool(x) 会尝试调用 x.__len__()。 若返回 0, 则 bool 会返回False; 否则返回 True。
from math import hypot class Vector: """ 二维向量 """ def __init__ (self, x, y): self.x = x self.y = y def __repr__ (self): return ' Vector(%s, %s) ' % (self.x, self.y) def __abs__ (self): return hypot(self.x, self.y) def __bool__ (self): return bool(abs(self)) def __add__ (self, other): x = self.x + other.x y = self.y + other.y return Vector(x, y) def __mul__ (self, other): return Vector(self.x * other, self.y * other)
三、加工数据类型
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
1 class List(list): 2 3 def show_middle(self): 4 mid_index = int(len(self) / 2 ) 5 return self[mid_index] 6 7 # 对append方法进行重写,只允许添加字符串类型 8 def append(self, p_object): 9 if type(p_object) is str: 10 super(List, self).append(p_object) 11 else : 12 print ( ' 只能添加字符串类型 ' ) 13 14 15 l1 = List( " hello world " ) 16 print (type(l1)) 17 print (l1.show_middle()) 18 19 l1.append( " aa " ) 20 print (l1)
1 class FileHandle(object): 2 3 def __init__ (self, filename, mode= ' r ' , encoding= ' utf-8 ' ): 4 # self.filename = filename 5 self.file = open(filename, mode, encoding= encoding) 6 self.mode = mode 7 self.encoding = encoding 8 9 def write(self, data): 10 t = time.strftime( ' %Y-%m-%d %X ' ) 11 self.file.write( ' %s %s ' % (t, data)) 12 13 def __getattr__ (self, item): 14 return getattr(self.file, item) 15 16 17 f1 = FileHandle( ' a.txt ' , ' w ' ) 18 print (f1.file) 19 # print(f1.read) 20 f1.write( " aabbcc " ) 21 f1.close()
1 # _*_coding:utf-8_*_ 2 3 # 我们来加上b模式支持 4 import time 5 class FileHandle: 6 def __init__ (self,filename,mode= ' r ' ,encoding= ' utf-8 ' ): 7 if ' b ' in mode: 8 self.file= open(filename,mode) 9 else : 10 self.file=open(filename,mode,encoding= encoding) 11 self.filename= filename 12 self.mode= mode 13 self.encoding= encoding 14 15 def write(self,line): 16 if ' b ' in self.mode: 17 if not isinstance(line,bytes): 18 raise TypeError( ' must be bytes ' ) 19 self.file.write(line) 20 21 def __getattr__ (self, item): 22 return getattr(self.file,item) 23 24 def __str__ (self): 25 if ' b ' in self.mode: 26 res= " <_io.BufferedReader name='%s'> " % self.filename 27 else : 28 res= " <_io.TextIOWrapper name='%s' mode='%s' encoding='%s'> " % (self.filename,self.mode,self.encoding) 29 return res 30 31 32 f1=FileHandle( ' b.txt ' , ' wb ' ) 33 # f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气 34 f1.write( ' 你好啊 ' .encode( ' utf-8 ' )) 35 print (f1) 36 f1.close()