zoukankan      html  css  js  c++  java
  • 面向对象:类的内置方法

    __str__和__repr__
    实例化一个对象,该对象的返回值是一个指向这个类的内存地址
    class A:
        pass
    a = A()
    print(a)
    
    #打印:
    <__main__.A object at 0x000001FA526DA108>
    自定义__str__和__repr__方法:
    class Func:
        pass
        def __str__(self):
            return '我是自定义的str'
        def __repr__(self):
            return '我是自定义的repr'
    a = Func()
    print(a)
    print(repr(a))
    print(str(a))
    
    #打印:
    我是自定义的str
    我是自定义的repr
    我是自定义的str

     结论:

    什么时候执行__str__:遇到print(obj),'%s'%obj,str(obj)的时候
    什么时候执行__repr__:遇到repr(obj),'%r'%obj的时候
    执行__str__时,首先找类中是否有自定义的__str__方法,若没有,则找自定义的__repr__方法,若类中没有这两个自定义方法,则向父类查找,不管在哪里找,执行__str__时,先找__str__方法,再找__repr__方法
    执行__repr__时,若类中没有自定义的__repr__方法,则向父类查找,不会找__str__的自定义方法或者父类的__str__
    所以,一个类中需要自定义__str__和__repr__时,首先考虑的应该是__repr__,因为他可以被str使用
     使用场景:实例化一个对象,对象的返回值默认是指向这个类的一个内存地址,当打印这个对象时,遇到print会执行这个类的内置函数__str__,若在类中自定义__str__这个方法,则可以设置成其他更直观的返回值,返回值必须为字符串类型
    class Teacher:
        def __init__(self,name,course):
            self.name = name
            self.course = course
        def __repr__(self):
            return '我是老师%s,教%s的'%(self.name,self.course)
    
    aike = Teacher('aike','python')
    print(aike)
    print(str(aike))
    print(repr(aike))
    
    #打印:
    我是老师aike,教python的
    我是老师aike,教python的
    我是老师aike,教python的
    __len__:在外部调用len方法,传入实例化的对象,实际上执行的是这个类的__len__方法,当类里自定义过__len__方法,外部用对象使用len时,会先找自定义的__len__方法,而这个自定义的__len__方法需要实现什么功能,可以自己自定义,返回值必须为int的数据类型
    class A:
        pass
        def __len__(self):
            print('执行了我')
            return 2
    a = A()
    print(len(a))
    
    #打印:
    执行了我
    2
    例::
    class Grade:
        def __init__(self,teacher):
            self.teacher = teacher
            self.student = []
    three_grade = Grade('aike')
    three_grade.student.append('chen')
    three_grade.student.append('chen')
    three_grade.student.append('chen')
    print(len(three_grade.student))#没有自定义的len方法,向父类找
    
    #打印:
    3
    
    
    class Grade:
        def __init__(self,teacher):
            self.teacher = teacher
            self.student = []
        def __len__(self):
            return len(self.student)
    
    three_grade = Grade('aike')
    three_grade.student.append('chen')
    three_grade.student.append('chen')
    three_grade.student.append('chen')
    print(len(three_grade))#调用的是自定义的len方法
    
    #打印:
    3
    __del__:称为构析函数,主要作用是在删除一个对象之前进行一些收尾工作;同理,类中有自定义的del方法时,优先执行自定义的,没有则向父类找,需要注意的是,尽管自定义的del方法没有实现删除操作,但执行完后依然会执行父类的del方法进行删除操作  
    class A:
        pass
    a = A()
    del a
    print(a)#报错,a已经删除
    class A:
        pass
        def __del__(self):
            print('删除之前执行了我,执行之后依然进行删除操作')
    a = A()
    del a
    print(a)#报错,a已经删除,但类中自定义的del方法会执行

    __call__:在实例化一个类时,在后边加上(),执行的就是call方法,它没有返回值,所以没有真正实例化一个对象出来,所以call方法中的操作不会影响到其它对象

    class Person:
        def __init__(self,name,money):
            self.name = name
            self.__money = money
    
        def __call__(self, money):
            self.__money += money
            print(self.__money)
    
        @property
        def money(self):
            return self.__money
    
    aike = Person('aike',1000)(100)
    print(aike)#执行call无返回值
    # print(aike.money)#报错,没有aike这个对象
    aike1 = Person('aike',1000)
    print(aike1.money)
    
    #打印:
    1100
    None
    1000
    __getitem__,__setitem__,__delitem__:
    打印一个实例化的对象时默认是打印这个对象的内存地址(可以用双下__str__或者__repr__方法更直观的打印这个对象,而不是打印内存地址,但只能以字符串的数据类型打印,因为返回值只能是字符串的数据类型)
    而一个对象是以字典的形式存在内存当中,所以可以以字典的形式对他进行增删改查,以字典的形式操作便需要实现__getitem__,__setitem__,__delitem__方法
    import json
    class Teacher:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
            self.studet = []
        def __repr__(self):
            return json.dumps(self.__dict__) #序列化,以字符串的数据类型返回对象的属性
    
        def __getitem__(self, item): #通过key查找
            return self.__dict__[item]
    
        def __setitem__(self, key, value): #修改或者添加
           self.__dict__[key] = value #没有该对象则添加,有则修改值
           #self.__dict__.setdefault(key,value) #setdefault  没有该对象则添加,有则不修改
    
        def __delitem__(self, key):  #与__del__方法不一样,__del__没有实现删除方法,依然会找父类进行删除操作,而__delitem__没有实现删除操作,不会进行删除,证明父类object没有__getitem__,__setitem__,__delitem__方法
            print('执行我了')
            # del self.__dict__[key]
            self.__dict__.pop(key)
    
    aike = Teacher('aike','man')
    aike['age'] = 18 #添加,受到__setitem__的具体实现影响
    print(aike['age'])
    print(aike.age) #成功添加属性
    
    aike['name'] = '艾克' #添加,受到__setitem__的具体实现影响
    print(aike.name)
    print(aike['name'])
    print(aike['sex'])
    
    del aike['name']
    # print(aike['name'])#报错,已经被删除
    print(aike) #以字典形式的操作会影响对象的属性
    
    #打印:
    18
    18
    艾克
    艾克
    man
    执行我了
    {"sex": "man", "studet": [], "age": 18}
    结论:以字典的形式操作对象需要实现__getitem__,__setitem__,__delitem__方法,增删改查的操作的具体实现可以自定义,比如在修改时可以使用字典的setdefault方法实现没有该对象则添加,有则不修改的操作
    而在进行删除操作时,__delitem__方法与__del__方法不一样,__del__没有实现删除方法,依然会找父类进行删除操作,而__delitem__没有实现删除操作,不会进行删除,证明父类object没有__getitem__,__setitem__,__delitem__方法

    __new__:
    实例化一个对象时,类会执行内置__new__方法创建一个对象self,再执行__init__方法添加属性
    class Teacher:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
        def __new__(cls, *args, **kwargs):
            print('先执行的我')
            return object.__new__(cls)
    
    aike = Teacher('aike','man')
    print(aike.__dict__)
    
    #打印:
    先执行的我
    {'name': 'aike', 'sex': 'man'}
    利用__new__方法实现单例模式
    每实例化一个对象都会new一次,每个对象都会新建一个新的内存地址,那么可以自定义new方法实现单例模式,即每创建一个对象都继用实例化的第一个对象的内存地址,不管对哪个对象进行操作,都是操作同一个对象
    class Teacher:
        __new_teacher = False #私有化一个属性
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
        def __new__(cls, *args, **kwargs):#实现了不管如何创建对象,都是返回这个私有属性,这个私有属性一直是第一次实例化的对象
            if cls.__new_teacher: #如果私有化属性不为空
                return cls.__new_teacher    #返回这个属性(对象)
            else:
                cls.__new_teacher = object.__new__(cls)  #否则就创建一个对象赋值给私有化的属性
                return cls.__new_teacher    #返回这个属性(对象)
    
    aike = Teacher('aike','man')
    aike1= Teacher('aike','man')
    print(aike)#内存地址一样
    print(aike1)#内存地址一样
    aike.name = '艾克'
    print(aike.name)#艾克
    print(aike1.name)#艾克
    
    
    #打印:
    <__main__.Teacher object at 0x000001C184484D48>
    <__main__.Teacher object at 0x000001C184484D48>
    艾克
    艾克

    __eq__:对象碰到==,执行的是__eq__

    默认情况下:

    class A:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
    a = A('aike','')
    b = A('aike','')
    print(a == b)#默认比较的是内存地址
    
    #打印:
    Flase

    可以自定义实现:

    class A:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
        def __eq__(self, other):
            # if self.sex == other.sex and self.name == other.name:
            if self.__dict__ == other.__dict__:
                return True
            else:
                return False
    
    a = A('aike','')
    b = A('aike','')
    print(a == b)#默认比较的是内存地址
    
    #打印:
    True

    __hash__:对一个不可变数据类型hash时,执行的是类的内置方法__hash__,该方法同样可以自定义要求实现

    正常情况下hash的是对象的内存地址:
    class Teacher:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
    aike = Teacher('aike','man')
    aike1= Teacher('aike','man')
    
    print(hash(aike))
    print(hash(aike1))
    
    #打印:
    -9223371930212113252
    -9223371930212113244

    自定义实现:

    class Teacher:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
        def __hash__(self):
            return hash(self.name+self.sex) #实现在外部hash返回字符串的hash值
    
    aike = Teacher('aike','man') #属性相同
    aike1= Teacher('aike','man')#属性相同
    
    print(hash(aike))
    print(hash(aike1))
    
    #打印:
    -2452999456034038120 #哈希值相同
    -2452999456034038120 #哈希值相同
  • 相关阅读:
    eval()一个有意思的PHP函数
    PHP error_reporting() 函数
    网络编程基础--协程--greenlet切换---gevent自动识别 IO ---
    网络编程基础--多线程---concurrent.futures 模块---事件Event---信号量Semaphore---定时器Timer---死锁现象 递归锁----线程队列queue
    rpm -qa 查找文件
    Linux Gvim shell 创建第一个shell脚本
    centos7修改网卡名称为eth0-技术流ken
    pxe+kickstart自动化批量安装系统详解-技术流ken
    cobbler单台服务器实现批量自动化安装不同版本系统-技术流ken
    cobbler批量安装系统使用详解-技术流ken
  • 原文地址:https://www.cnblogs.com/aizhinong/p/11483283.html
Copyright © 2011-2022 走看看