zoukankan      html  css  js  c++  java
  • 面向对象 ,特殊成员和魔法方法

    特殊成员,类的双下__方法:

    一: isinstance 和 issubclass

    class Foo(object):
        pass
    
    obj = Foo()
    
    print(isinstance(obj, Foo))  #判断这个类,是不是这个对象的实例
    
    
    
    class Foo(object):
       pass
    
    class Bar(Foo):
        pass
    
    print(issubclass(Bar, Foo)) #判断子类与父类的继承关系
    

    二: ==item系列: getitem, setitem, delitem

    class Foo:
    
        def __getitem__(self, item): #这个item是直接就出来的,必须要有这个
            print('getitem  a ')
            return self.__dict__[item] #self是指f1实例化的自己,__dict__是指存在那个空间里的字典,
            						 这个item就是传进来的'name'字符串形式.
        def __setitem__(self, key, value):
            print('setitem  b ')
            self.__dict__[key] = value   
    
        def __delitem__(self, key):
            print('delitem  c')
            self.__dict__.pop(key)#
    f1 = Foo()
    print(f1.__dict__) #开始的时候__dict__里面并没有存放任何的值
    
    
    # # 赋值操作
    f1['name'] = 'egon'#相当于字典的赋值,就直接触发__setitem__方法,还需要再__setitem__里面设置一下, self.__dict__[key] = value这样就将['name'] = 'egon'赋值进去了
    print(f1.__dict__)  #此时打印的结果就为 setitem  b   {'name': 'egon'}
    
    f1['age'] = 18  #再来增加一个
    print(f1.__dict__)  #{'name': 'egon', 'age': 18}
    
    # # 删除操作
    del f1['age'] #同样需要删除时,就直接触发__delitem__方法,还需要再__delitem__里面设置一下,self.__dict__.pop(key),这样字典age这个key对于的value值就被删除了
    print(f1.__dict__)   #{'name': 'egon'}
    
    # 访问,获取
    print(f1['name']) #以对象和字典key的结合方式,触发__getitem__方法. 还需要再__getitem__里面设置一下, return self.__dict__[item],这样就通过字典的形式访问到值
    
    # 总结:
    # 所以item系列是有访问,赋值,删除的基本功能的.但是它具有有个特点是必须要通过字典的方式来操作.
    
    #  而__hasattr__,__getattr__,__setattr__,__delattr__  这attr系列也同样具备访问,赋值,删除的基本功能的.
    # 但是attr系列是 通常叫反射:是通过字符串映射到对象的属性,是通过字符串访问到类,对象属性的一种方法,注意区分
    
    
    # 点的方式操作属性就是跟getattr相关,中括号的方式操作属性就是跟item相关
    

    三: attr系列: getattr, setattr, delattr

    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
    
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
    
    
        def __setattr__(self, key, value):
            print('----> from setattr')
            # self.key=value #这就无限递归了,你好好想想
            # self.__dict__[key]=value #应该使用它
    
        def __delattr__(self, item):
            print('----> from delattr')
            # del self.item #无限递归了
            self.__dict__.pop(item)
    
    #__setattr__添加/修改属性会触发它的执行
    f1=Foo(10)
    print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z=3
    print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性
    

    四:___getattr__和 _getattribute

    1.getattr :单独作为的方法使用时,是调用不存在的属性时,会自动触发getattr方法,并运用getattr里的方法.
    class Foo:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是我')
            # return self.__dict__[item]
    
    f=Foo(10)
    print(f.x,)
    f.xxxxxx #不存在的属性访问,触发__getattr__
    

    2.getattribute:

    
    class Foo1:
        def __init__(self,x):
            self.x=x
    
        def __getattribute__(self, item):
            print('不管是否存在,我都会执行')
    
    f1=Foo1(10)
    f1.x
    f1.xxxxxx1  #不存在的属性访问,触发__getattr__
    

    3.俩者同时出现:

    class Foo1:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是我')
            # return self.__dict__[item]
    
        def __getattribute__(self, item):
            print('不管是否存在,我都会执行')
    
    f1=Foo1(10)
    
    f1.xxxxxx1  #当__getattribute__与__getattr__同时存在,只会执行__getattrbute__
    

    4.先执行__getattribute__

    class Foo2:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是我')
            # return self.__dict__[item]
        def __getattribute__(self, item):
            print('不管是否存在,我都会执行')
            raise AttributeError('哈哈')
    f1=Foo2(10)
    
    f1.xxxxxx2
    打印结果:
    不管是否存在,我都会执行
    执行的是我
    
    总结:#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__
    # 除非__getattribute__在执行过程中抛出异常AttributeError
    

    五: __repr__方法和 __str__方法

    repr_与__str__都是用来.控制输出de,输出的结果是return的值,此时return的值必须为字符串的形式

    repr方法

    class B:
      def __init__(self,age):
        self.age = age
      def __repr__(self ):
        return self.age
        
    b = B('18')
    print(b.__dict__)  #{'age': '18'}
    print( b)  #repr(b)---> b.__repr__() #意思是说在方法里面有__repr__方法之后,你实例化一个对象,会自动触发这个repr方法
    

    __str__方法

    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return  self.name #返回一个值
            # return  'name:%s ,age:%s' % (self.name,self.age)  #返回俩个值
    obj1 = People('egon',18)
    print(obj1)
    # print(obj1.__dict__) #{'name': 'egon', 'age': 18}
    #这样打印对象的时候,就自动触发__str__方法,将obj对象里面的值调出来
    # 如果不加__str__方法,直接打印对象会<__main__.People object at 0x00000000027FEBE0>,只是一个内存地址而已
    # 加了__str__方法后,就会直接打印通过对象直接打印他的值
    
    

    那么要是俩种方法都同时存在于呢,优先级是哪个,看例1:

    class B:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __repr__(self):
            return '第三季度涉及到'
    
        def __str__(self ):
            return self.age
    
    f2 = B('egon','18')#必须为字符串
    print(f2)
    # !!!__repr_与__str__都是用来.控制输出de,输出的结果是return的值,此时return的值必须为字符串的形式
    # str函数或者print函数--->obj.__str__()
    # repr或者交互式解释器--->obj.__repr__()
    # 如果__str__没有被定义,那么就会使用__repr__来代替输出
    # 注意:这俩方法的返回值必须是字符串,否则抛出异常
    
    # #实例化对象的时候,都必须为字符串
    # # 一般情况下建议用repr
    

    例2:

    class Course:#创建一个课程类,他有自己的属性,但是创建课程这个动作是管理员来完成的,所以是由管理员来做这个事情
        def __init__(self, name, price, period, kind):
            self.name = name
            self.price = price
            self.period = period
            self.kind = kind
        def __repr__(self):
            s = ''
            for k in self.__dict__:  #循环这个课程类的信息,他存在内存的dict字典
                s += '%s:%s
    '%(k,self.__dict__[k])
            return s
    print(Course)  #他会自动调用__reor__方法
    

    六:format

    1.用法1

    class Date:
        def __init__(self,mon,day,year):
    
            self.year = year
            self.mon = mon
            self.day = day
    
    
        def __format__(self, format_spec): #自动出现format_spec
    
            return '{0.year}{0.mon}{0.day}'.format(self)
    
    d1= Date(2018,8,8)
    print(d1) #<__main__.Date object at 0x00000000027FD940>
    print(format(d1))  # 820188
    
    return self.day  #这样写是错误的
    ypeError: __format__ must return a str, not int会报错,是因为return的是必须是字符串,而self.day,实例化的是int类型
    
    ormat_dict1 = {
        'ymd':'{0.year}{0.mon}{0.day}',
        'm-d-y':'{0.mon}:{0.day}:{0.year}',
        'y-m-d':'{0.year}-{0.mon}-{0.day}'
    }  #定义这样三种格式的字典
    
    class Date:
        def __init__(self,mon,day,year):
            self.mon = mon
            self.day = day
            self.year = year
    
        def __format__(self, format_spec): #如果下面不传参数的话,那format_spec就会变成空格也不会报错,但是要是传参数呢
            fm = format_dict1[format_spec]  #如果他的选择是'ymd'的话,fm就等于是从format_dict的字典里面,去选择.取到最终的格式而ymd==format_spec
            return fm.format(self)  #就返回fm里面的格式
    
    
    d2= Date(2018,8,8)
    print(format(d2,'ymd')) #用户如果传的是ymd,那么就传给了format_spec ,即ymd==format_spec
    

    七: len

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __len__(self):
            return len(self.__dict__)
    a = A()
    print(len(a))
    #类内部定义了__len__方法后,打印对象的长度.eg:print(len(对象名))就触发内部的__len__方法.
    

    八: call,对象后面加括号,触发执行,执行时调用这个类下面的__cal__l方法==

    class Foo:
        def __init__(self):
            pass
        def __call__(self, *args, **kwargs):
            print('__call__',pppp)
    
    obj = Foo() # 执行 __init__
    obj()       # 执行 __call__
    
    #类内部定义__call__方法后,直接实例化一个对象后,直接用对象名(),
    就可以触发__call__,打印__call__里的所有信息
    
    

    九:moduleclass

      module 表示当前操作的对象在那个模块

      class 表示当前操作的对象的类是什么

    class C:
    
        def __init__(self):
            self.name = ‘SB'
    
    from lib.aa import C
    
    obj = C()
    print obj.__module__  # 输出 lib.aa,即:输出模块
    print obj.__class__      # 输出 lib.aa.C,即:输出类
    

    十:__del 析构方法只在实例被删除的时候才会触发__del__方法

    f  = open('txt文件名')
    f.read()
    f.close()  回收操作系统的资源
    # 拿到一个f 的对象的话,涉及到俩方面的资源
    # 1.如果是一个赋值,那一定是应用程序的资源
    # 2.后边的是一个操作系统的资源,在程序关闭之前把操作系统的资源关闭掉
    # 就是我们在学习文件操作的时候一定要记得关闭文件,如果程序结束了,操作系统的资源即文件没有关掉,那么这资源就剩下了,就占内存空间
    对于# __del__方法的引导
    '''
    # __del__方法,具体如下
    # class Open:
    #     def __init__(self,filename):
    #         print('open file...')  #模拟打开文件
    #         self.filename = filename
    #
    #     def __del__(self):
    #         print('回收操作系统资源')
    #
    # f = Open('settings.py') #f是变量
    #
    # print('======表示程序结束====')
    
    '''
    open file...
    ======表示程序结束====
    回收操作系统资源
    
    看打印的顺序,简单结论说:
    当f这个实例化对象去执行文件打开操作的时候,就模拟打开文件了,所以打印 open file...[就是去打开一个文件执行操作]
    然后打开文件后,执行了相关的操作之后,句模拟打印======表示程序结束====,程序结束之后,程序自动的会回收f这个变量,但是遗留下文件资源
    但是这个文件还没有关闭呀,所以,造类里面设置了__del__之后就自动的将文件关闭,这样一个功能,为了节省内存空间嘛
    
    老师总结:在对象被删除的时候,会自动先触发__del__方法,再把对象删掉
    

    十一:迭代器协议: _iternext

    例子:说明类对象得到一个数,通过内置的迭代器方法,将得到的数进行迭代输出,并设置到一定数之后就停止输出
    class Bar:
        def __init__(self,a):
            self.a = a
    
        def __iter__(self):
            return self
    
        def __next__(self): #执行一次就返回前俩个的和
            self.a += 1 #让a得到的数字17进行迭代+1,或者说是进行累加1
            if self.a == 21: #如果a得到的数等于21
                raise StopIteration('终止了') #就停止+1的操作,抛出异常,这个异常并不是报错,只是跟程序本身说停止叠加1的操作,并不是真的报错
            return self.a
    
    c = Bar(17)
    for i in c:
        print(i)
    
    
    
    把一个类对象变成一个可迭代的,且类里面必须要有__iter__方法,表示可迭代,要知道光可以迭代并没有实际用处,
    根据之前学习迭代器的理论,得知,next是取下一个值的,所以此时运用到类对象的时候,就提供了相应的内置方法,__next__来取值.
    
    

    实例1.实现斐波那契数列

    class Fib:
        def __init__(self):
            self.a = 1
            self.b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.a > 100:
                raise StopIteration('可以停止了')
            self.a, self.b = self.b, self.a + self.b  # 主要在这里,结合a,b = b, a理解,等于一个交换值
            return self.a
    f1 = Fib()
    print(next(f1))
    print(next(f1))
    print(next(f1))
    print(next(f1))
    print(next(f1))
    print('===================================')
    
    for i in f1:
        print(i) #如果单纯这样写出来的结果就是无限循环的数列.所以需要再__next__方法里面加上判断
    

    十二: 单例模式: new

    创造一个对象,一个类始终只有一个实例
    # __new__: 单例模式,创造一个对象,一个类始终只有一个实例
    #             当你第一次实例化这个类的时候,就创建一个实例化的类,当你再来			 实例化的时候,就用之前创建的对象
    #        (如果之前已经有创建一个对象了,就不再创建了,会在__new__里去控制
              ,如果你来一个新的不同的对象,你来一个我就new一个,可以理解为创造一个具体的实物手机,你来一个实物手机我就创建一个实物手机,但你要在同一个实物手机的基础上做不同的处理,比如换手机壳的操作,手机壳只能戴一个,你换各种颜色的手机壳可以,但是你只能讲前面一个手机壳去掉,这里就理解为覆盖掉)
    
    class A:
    
        _instance = False
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance: #如果没有创建这个对象
                cls._instance = object.__new__(A) #就去创建一个新的对象
                return cls._instance #将创建的对象返回
    
            else: #如果有这个对象,就不再创建新的对象,且如果有不同对象有相同属性的话,那么后一个对象的属相会覆盖前一个对象相同的属性,相当于相同属性之间,只有一块内存空间
                return cls._instance
    
    
    
    
    egon = A('egon',18)
    nezha = A('nezha',25)
    
    print(nezha)
    print(egon)
    
    print(egon.name) #nezha
    print(nezha.name)#nezha  不同对象会覆盖前一个相同属性的值,
    
    egon.cloth = '衣服'
    print(nezha.cloth)
    print(egon.cloth)
    

    十三: eq

    判断俩个对象的属性的值是否相等,用==去触发__eq__的执行

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __eq__(self,obj):
            if  self.a == obj.a and self.b == obj.b:
                return True
    a = A()
    b = A()
    print(a == b)
    有__eq__,判断的是俩个对象的属性是否相等
    无__eq__,判断的是内存地址
    

    十四: __hash__判断一个对象是否可哈希,且是根据内存地址去哈希的

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):
            return hash(str(self.a)+str(self.b))
    a = A()
    print(hash(a))
    
  • 相关阅读:
    LINUX学习-Mysql集群-一主多从
    LINUX学习-Mysql集群-主主备份
    LINUX学习-Mysql集群-主从服务器备份
    LINUX学习-Nginx+JDK+Tomcat+Mysql搭建JAVA WEB
    LINUX学习-Nginx实现https
    LINUX学习-Nginx服务器的反向代理和负载均衡
    LINUX学习-PHP安装
    LINUX学习-Mysql安装
    Lens in Scala
    scala中的 Type Lambda
  • 原文地址:https://www.cnblogs.com/sunny7/p/9727288.html
Copyright © 2011-2022 走看看