zoukankan      html  css  js  c++  java
  • 面向对象相关知识补充(一)

    一、isinstance(obj, cls)

      检查obj是否是类cls的对象。

    class Foo:
        pass
    
    obj = Foo()
    
    print(isinstance(obj,Foo))

    二、issubclass(sub, super)

      检查sub类是否是 super 类的派生类

    class Foo:
        pass
    
    class Bar(Foo):
        pass
    
    issubclass(Bar,Foo)

     三、__setattr__,__getattr__,__delattr__

      上述三个函数,具体如何使用,请看代码:

      __setattr__:对属性进行赋值或者修改的时候被调用。

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setattr__(self, key, value):
            # self.__dict__[key] = value
            print('我执行了')
    
    f = Foo('alex')  # 凡是对属性赋值或者修改操作,都触发__setattr__的执行
    f.x = 3 # 触发__setattr__执行
    print(f.__dict__)
    
    #######输出结果#############
    我执行了
    我执行了
    {}

      从上面结果可以看出,当我们设置属性或者给属性赋值的时候,会调用__setattr__的执行。但为什么对象f的名称空间没有我们设置的name和x两个变量呢?原因是:因为你重写了__setattr__功能,对它并没有进行任何操作,仅仅只有一条语句,而默认的__setattr__会将属性按照键值对写入对象的名称空间。如果自己重写了__setattr__,但是又没有进行任何操作,要想完成对象属性的赋值操作,必须得通过以下方式才能实现:

    f.__dict__['name'] = xiaohua
    
    print(f.name)
    
    ##输出结果###
    xiaohua

      所以,如果我们自己要重写__setattr__方法,必须按照如下方式来做:

        def __setattr__(self, key, value):
            self.__dict__[key] = value

      __getattr__:只有在调用属性时且属性不存在的情况下,触发這个函数的执行。

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            print('没有你要找的元素')
    
    f = Foo('alex')
    f.x = 3
    print(f.__dict__)
    
    #####输出结果######
    {'name': 'alex', 'x': 3}  # 此时对象名称空间有两个属性值

      当我们重写了__getattr__方法后,并且试图调用一个不存在的属性值:

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            print('没有你要找的元素')
    
    f = Foo('alex')
    f.x = 3
    print(f.__dict__)
    f.a  # 调用一个不存在的属性值
    
    ########输出结果########
    没有你要找的元素

      由结果分析,正如我们之前所说的,调用一个不存在的属性值时,会触发__setattr__的执行。所以,一般将getattr设置为如下样式:

        def __getattr__(self, item):
            return self.__dict__[item]

      __delattr__:当删除一个对象的属性值时,会触发delattr的执行。

    class Foo:
        def __init__(self,name):
            self.name = name
        def __delattr__(self, item):
            print('我执行了')
    
    
    f = Foo('alex')
    f.x = 3
    del f.name  # 触发delattr的执行
    
    ###输出结果######
    我执行了

      一般重写为:

        def __delattr__(self, item):
            del self.__dict__[item]

    四、__getitem__,__setitem__,__delitem__

      我们在列表中学过这种取元素的方式。比如说lst = [1,2,3,4],取第一个元素 lst[0],又或者在字典中dd ={'name':'xiaohua'} 取元素dd['name']。实际上,这种取元素的方式,与__getitem__,__setitem__,__delitem__三个函数有关。

      下面,我们一一来看看上述三个函数的用法:

      __getitem__:当我们想要按照 obj[attr]方式调用对象的属性时,触发这个函数的执行

    class Foo:
        def __init__(self,name):
            self.name = name
        def __getitem__(self, item):
            print('我执行了')
    
    f = Foo('alex')
    print(f.__dict__) # 对象的名称空间只有一个属性
    f['name']  # 触发getitem执行
    
    #####输出结果########
    {'name': 'alex'}
    我执行了

      从上面结果,可以看出,当我试图以f['name']方式调用属性的时候,就会触发__getitem__执行。一般将__getitem__设置为如下:

     def __getitem__(self, item):
            return self.__dict__[item]
    
    print(f['name'])
    ###正常输出######

      __setitem__:当我以f['name'] = 'xiaohua' 方式修改对象属性值的时候,会触发该函数的执行。

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setitem__(self, key, value):
            print('我执行了')
    
    f = Foo('alex')
    print(f.__dict__)
    f['x'] = 3  # 触发setitem执行
    
    #########输出结果#########
    我执行了

      一般将setitem设置为如下,当然你也可以按照自己的方式进行设置。

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __setitem__(self, key, value):
             self.__dict__[key] = value
    
    f = Foo('alex')
    print(f.__dict__)
    f['x'] = 3
    print(f.__dict__)
    
    ###输出结果#######
    {'name': 'alex'}
    {'name': 'alex', 'x': 3}

      __delitem__:当以del f['name'] 方式删除对象的属性值时,会触发這个函数的执行

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __delitem__(self, key):
            print('我执行了')
    
    
    f = Foo('alex')
    print(f.__dict__)
    del f['name']  # 触发delitem执行
    
    ####输出结果#####
    {'name': 'alex'}
    我执行了

      一般设置为如下方式:

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __delitem__(self, key):
            del f.__dict__[key]
    
    
    f = Foo('alex')
    print(f.__dict__)
    del f['name']
    print(f.__dict__)

     五、__str__,__repr__

      先来一段代码,再来引入我们的正题:

    lst = list([1,2,3,4])
    class Foo:
        def __init__(self,name):
            self.name = name
    
    f = Foo('xiaohua')
    
    print(lst)
    print(f)
    
    ######输出结果#########
    [1, 2, 3, 4]
    <__main__.Foo object at 0x0000005FE8BC9208>

      我们都知道在python里面,list是一种数据类型,而且也是一个类。当我们以list()来创建一个序列时,我们也就创建了一个List对象。如上面的lst,知道了lst是List类型的对象后,我们print(lst)时,为什么没有像f一样,打印出对象的内存地址,而是直接打印出给对象赋的值呢?其实,这一切是因为在list类的内部,实现了__str__功能所导致的。下面,我们通过一些实例,来理解__str__的用法。

    class Foo:
        def __init__(self,name):
            self.name = name
        def __str__(self):
            return '我执行了'
    
    f = Foo('xiaohua')
    print(f)
    
    #######输出结果############
    我执行了

      看,当我再次打印对象的时候,没有打印出对象的内存地址,而是打印出了我们设定的值。__str__就是帮我们实现这种功能的!我们可以定制自己__str__,让他返回一些有意义的信息。

        def __str__(self):
            return 'name:%s' % self.name
    
      print(f)
    
      ####输出结果#####
      name:xiaohua

      如上所示,现在我们可以理解,为什么打印列表对象lst的时候,会返回[1,2,3,4]了吧。

      注意:__str__:只能返回一个字符串类型

      理解了__str__后,__repr__就很好理解了。它和__str__一样,也是在打印对象的时候,会触发這个函数的执行。

    六、__new__,__del__,

      __new__:创建对象时被调用,比__init__先执行。

    class Foo(object):
        def __init__(self):
            print('init')
    
        def __new__(cls, *args, **kwargs):
            print('new %s' %cls)
            return object.__new__(cls, *args, **kwargs)
    Foo()
    
    ###输出结果#######
    new <class '__main__.Foo'>  # 比init先打印
    init

      从上面,我们可以总结出如下几点:   

        继承自object的新式类才有__new__

        __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供

        __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

        __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

      若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行:

    class A(object):
        pass
    
    class B(A):
        def __init__(self):
            print('init')
    
        def __new__(cls, *args, **kwargs):
            print('new %s' % cls)
            return object.__new__(A, *args, **kwargs)
    b = B()
    print(type(b))
    
    输出结果:
    new <class '__main__.B'>
    <class '__main__.A'>

      __del__:在对象被删除或者程序执行完毕后,被调用

    # 以下代码执行完毕后,自动执行del
    class B:
        def __del__(self):
            print('我执行了')
    b = B()
    
    ######输出结果#########
    我执行了
    #显式调用del来删除对象时,触发__del__执行
    import time
    class B:
        def __del__(self):
            print('我执行了')
    b = B()
    del b # 触发__del__执行
    time.sleep(5)
    print('主程序结果')
    
    ###输出结果####
    我执行了
    #等待5秒
    主程序结果

      

  • 相关阅读:
    Windows下使用Nginx+tomcat配置负载均衡
    Windows系统搭建Mysql Cluster集群
    java.math.BigDecimal cannot be cast to java.lang.String解决方法
    Java从后台重定向(redirect)到另一个项目的方法
    Java代码中获取配置文件(config.properties)中内容的两种方法
    mybatis和redis整合 log4j打印sql语句
    Windows系统安装测试redis
    myeclipse 2014新建maven web 项目步骤
    myeclipse用maven搭建web项目后tomcat启动报找不到jar包解决办法
    《剑指offer》丑数
  • 原文地址:https://www.cnblogs.com/vipchenwei/p/7019887.html
Copyright © 2011-2022 走看看