• 面向对象之内置方法续集


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

      六、__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 该属性无法继承给子类

        

        

        
  • 相关阅读:
    vue自定义指令,自动调用下载的方法
    electron桌面通知,修改默认通知应用名electron.app.Electron为自己应用的名称
    C++二叉树前中后序遍历(递归&非递归)统一代码格式
    反转链表和反转链表2
    基于partition的递归
    C++归并排序(数组&链表)
    关于C++跨平台
    Visual Studio 2019社区版:错误 MSB6006 “CL.exe”已退出,代码为 2
    腾讯2017校招开发工程师笔试试卷(一)答题解析
    C++面试高频题
  • 原文地址:https://www.cnblogs.com/schut/p/8656831.html
Copyright © 2020-2023  润新知