接上一篇,内置方法续集:
六、__str__,__repr__ 和 __format__
1、作用:__str__,__repr__ 改变对象的字符串显示
__format__ 自定制格式化字符串
2、示例:
#!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong format_dict={ 'way1':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'way2':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'way3':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name = name self.addr = addr self.type = type def __repr__(self): return 'School(%s,%s)'%(self.name,self.addr) def __str__(self): return '(%s,%s)'%(self.name,self.addr) def __format__(self, format_spec): if not format_spec or format_spec not in format_dict: format_spec = 'way1' fmt =format_dict[format_spec] return fmt.format(obj=self) s1 = School('lufei','上海','培训机构') print('from repr:',repr(s1)) # from repr: School(lufei,上海) print('from str:',str(s1)) # from str: (lufei,上海) print(s1) # (lufei,上海) print(format(s1,'way2'))# 培训机构:lufei:上海 print(format(s1,'way3')) # 培训机构/上海/lufei print(format(s1,'abcdef')) # 培训机构/上海/lufei ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 '''
注意:__str__和__repr__方法的返回值必须是字符串,否则抛出异常。
七、slots的用法
1、__slots__是什么?
__slots__是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)。
2、使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)。
3、使用__slots__方法的好处?
字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4、注意:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。
大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。它更多的是
用来作为一个内存优化工具。
5、示例:
#!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong class Test: __slots__ = ['name','age'] f1 = Test() f1.name = 'cc' f1.age = 21 print(f1.__slots__) # ['name', 'age'] #print(f1.__dict__) 报错,f1不再有__dict__ # f1.sex = 'male' 报错,f1不能再添加属性 print(f1.__slots__) # ['name', 'age'] f2 = Test() f2.name = 'zm' f2.age = 19 print(f2.__slots__) # ['name', 'age'] #f1与f2都没有属性字典__dict__了,统一归__slots__管,节省内存 print(Test.__dict__)# {'__module__': '__main__', '__slots__': ['name', 'age'], 'age': <member 'age' of 'Test' objects>, 'name': <member 'name' of 'Test' objects>, '__doc__': None}
八、__next__和__iter__实现迭代器协议
1、关于__next__和__iter__方法的几点解释
Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator,
Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出StopIteration异常。同时,Iterator自己也是一种Iterable,
所以也需要实现Iterable的接口,也就是__iter__,这样在for当中两者都可以使用。Iterator的__iter__只需要返回自己就行了。
这样,下面的代码就可以工作:
for i in my_list:
...
for i in iter(mylist):
...
for i in (v for v in mylist if v is not None):
...
2、示例1--迭代器:
class Range: def __init__(self,n,stop,step): # n为起点,stop为终点,step为步长 self.n=n self.stop=stop self.step=step def __next__(self): if self.n >= self.stop: raise StopIteration x=self.n self.n+=self.step return x def __iter__(self): return self for i in Range(1,7,3): # print(i)
3、示例2--斐波拉契数列:
# 斐波那契数列 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='')
九、 __module__和__class__
1、__module__ 表示当前操作的对象在那个模块、__class__ 表示当前操作的对象的类是什么
2、示例:
#lib/a.py #!/usr/bin/env python3 #-*- coding:utf-8 -*- # write by congcong class C: def __init__(self): self.name = 'cc' # index.py #from lib.a import C obj = C() print(obj.__module__) # 输出 lib.a,即输出模块 print(obj.__class__) # 输出lib.a.C ,输出类
十、__del__方法
1、含义:析构方法,当对象在内存中被释放时,自动触发执行。
2、为什么用__del__方法?
如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,
即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。
3、应用场景
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,
存放于内核空间内存中当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,
这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源
4、示例:
class Foo: def __del__(self): print('执行到我啦') f1=Foo() del f1 print('------->') ''' #输出结果 执行我到啦 -------> '''
十一、 __enter__和__exit__方法
with open('a.txt') as f: pass # 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法 class Open: def __init__(self,filepath,mode='r',encoding='utf-8'): self.filepath=filepath self.mode=mode self.encoding=encoding def __enter__(self): # print('enter') self.f=open(self.filepath,mode=self.mode,encoding=self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): ''' with语句中代码块出现异常,则with后的代码都无法执行 如果__exit__()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行 :param exc_type: 异常类型 :param exc_val: 异常值 :param exc_tb: 追溯信息 :return: ''' # print('exit') self.f.close() return True def __getattr__(self, item): #属性不存在时触发 return getattr(self.f,item) with Open('a.txt','w') as f: print(f) f.write('aaaaaa') f.wasdf #抛出异常,交给__exit__处理
使用with语句的好处:
使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,
你无须再去关心这个问题。
十二、__call__方法
1、使用方法:对象后面加括号,触发执行。
2、注意事项:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;
而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()。
3、示例:
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
十三、__doc__方法
1、作用:查看类的描述信息。
2、示例:
class Foo:
'我是匆匆'
pass
class Bar(Foo):
pass
print(Foo.__doc__) # 我是匆匆
print(Bar.__doc__) # None 该属性无法继承给子类