面向对象之内置方法续集

接上一篇,内置方法续集:

  六、__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__来代替输出
'''
View Code

  注意:__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}
View Code 

  

  八、__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)
View Code

  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='')
View Code

  九、 __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 ,输出类
View Code

  十、__del__方法

    1、含义:析构方法,当对象在内存中被释放时,自动触发执行。

    2、为什么用__del__方法?

      如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,

即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。

    3、应用场景     

      创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,

    存放于内核空间内存中当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,

    这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源

    4、示例: 

class Foo:

    def __del__(self):
        print('执行到我啦')

f1=Foo()
del f1
print('------->')
'''
#输出结果
执行我到啦
------->
'''
View Code

   十一、 __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__处理
View Code

    使用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__
View Code

  十三、__doc__方法

    1、作用:查看类的描述信息。

    2、示例:

class Foo:
    '我是匆匆'
    pass
class Bar(Foo):
    pass
print(Foo.__doc__) # 我是匆匆
print(Bar.__doc__) # None 该属性无法继承给子类

    

    

    
原文地址:https://www.cnblogs.com/schut/p/8656831.html