zoukankan      html  css  js  c++  java
  • python面向对象基础(三)内置方法 __xx__

    __str__和__repr__,__format__

    改变对象的字符串显示__str__,__repr__

    自定制格式化字符串__format__

    #_*_coding:utf-8_*_
    
    format_dict={
        '格式1':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
        '格式2':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
        '格式3':'{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 format_spec
            if not format_spec or format_spec not in format_dict:
                format_spec='格式1'
            fmt=format_dict[format_spec]
            return fmt.format(obj=self)
    
    s1=School('清华','北京','公立')
    print('from repr: ',repr(s1))
    print('from str: ',str(s1))
    print(s1)
    
    '''
    str函数或者print函数--->obj.__str__()
    repr或者交互式解释器--->obj.__repr__()
    如果__str__没有被定义,那么就会使用__repr__来代替输出
    '''
    '''
    注意:这三个方法的返回值必须是字符串,否则抛出异常
    '''
    print(format(s1,'格式1'))
    print(format(s1,'格式2'))
    print(format(s1,'格式3'))
    print(format(s1,'xxx'))

    class B:
    
         def __str__(self):
             return 'str : class B'
    
         def __repr__(self):
             return 'repr : class B'
    
    
    b=B()
    print('%s'%b)
    print('%r'%b)

    __del__

    析构方:当对象在内存中被释放的同时自动触发执行该方法。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    del f1
    # 执行我啦
    print('------->')
    f1
    # NameError: name 'f1' is not defined

     

    item系列

    __getitem__\__setitem__\__delitem__

      ==》__dict__

    在Python中,如果我们想实现创建类似于序列和映射的类,可以通过重写魔法方法__getitem__、__setitem__、__delitem__方法去模拟。

    这些魔术方法的原理就是:当我们对类的属性item进行下标的操作时,首先会被__getitem__()、__setitem__()、__delitem__()拦截,从而进行我们在方法中设定的操作,如赋值,修改内容,删除内容等等。

    对类的属性item进行下标的操作==>obj["属性"]

    class A:
        def __init__(self,name):
            self.name=name
    
        def __getitem__(self, item):
            print("呵呵你看不到")
    
        def __setitem__(self, key, value):
            self.__dict__[key]=value
            print('设置了 obj 属性 [%s] 为 %s'%(key,value))
            
        def __delitem__(self, key):
            print('del obj[%s]时,我执行'%key)
            self.__dict__.pop(key)
        
        def __delattr__(self, item):
            print('del obj.%s时,我执行'%item)
            self.__dict__.pop(item)
        
        def __setattr__(self, item,value):
            print("调用了__setattr__方法")
            self.__dict__[item]=value
            
        def daren(self):
            pass
        
        
    
    a=A('斌哥')
    #这个过程也调用了__setattr__方法
    
    print(a.__dict__)
    # {'name': '斌哥'}
    
    a.name
    #==>'斌哥'
    
    print(a['name'])
    #调用了__getitem__方法
    # 呵呵你看不到
    # None
    
    a['age']=18
    #=触发=__setitem__>设置了 obj 属性 [age] 为 18
    a.age=19
    #=触发=__setitem__>调用了__setattr__方法
    a['appear']='很帅'
    # #=触发=>设置了 obj 属性 [appear] 为 很帅
    
    del a.appear
    #触发__delattr__==>del obj.appear时,我执行
    del a['age']
    #触发__delitem__==>del obj[age]时,我执行
    a.school='nc'
    print(a.__dict__)
    # {'school': 'nc', 'name': '斌哥'}
    # 结论:感觉属性维护了一个doc字典
    
    
    # 结论 : obj.属性 调用 使用的是xxattr()方法
    #xxitem()方法提供了 访问属性一个【】接口

     

    __dict__

    发现dict是一个mappingproxy类型,为何不是一个简单的python dict呢?

    >>> class A(object): pass
    ...
    >>> A.__dict__
    mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})

    不清楚,回头研究下。

    Python的实例有自己的__dict__,它对应的类也有自己的__dict__   (但是有些特殊的对象是没有__dict__属性的)

    class A:
        def __init__(self,name):
            self.name=name
        def __len__(self):
            return len(self)
    a=A('斌哥')
    print(A.__dict__)
    # {'__doc__': None, '__module__': '__main__', '__len__': <function A.__len__ at 0x0000014FF1C71EA0>,
    #  '__init__': <function A.__init__ at 0x0000014FF1BE1730>, '__weakref__': <attribute '__weakref__' of 'A' objects>, 
    # '__dict__': <attribute '__dict__' of 'A' objects>}
    
    print(a.__dict__)
    # {'name': '斌哥'}
    
    class B(A):
        def __init__(self,age,name):
            super().__init__(name)
            self.age=age
        def __len__(self):
            return len(self)
    b=B(18,"bb")
    print(B.__dict__)
    print(b.__dict__)
    
    # {'__doc__': None, '__module__': '__main__', 
    #  '__init__': <function B.__init__ at 0x0000014FF1CB1A60>,
    # '__len__': <function B.__len__ at 0x0000014FF1CB1730>}
    # 
    # {'name': 'bb', 'age': 18}
    class A:
        a = 0
        b = 1
    
        def __init__(self):
            self.a = 2
            self.b = 3
    
        def test(self):
            print('a normal func.')
    
        @staticmethod
        def static_test(a):
            print('a static func.'+a)
    
        @classmethod
        def class_test(cls):
            print('a calss func.')
    
    
    obj = A()
    print(A.__dict__)
    print(obj.__dict__)
    A.static_test("1")
    A.class_test()

     

    1.类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的

    2.对象的属性(不含类的)保存在实例__dict___

    3.子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中。对象也这样。

    4.内置的数据类型没有__dict__属性

    __dir__

    dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

    dir([object])

    参数说明:

    • object -- 对象、变量、类型。
    class A(object): pass
    a=A()
    a.name="wqbin"
    
    print(A.__dict__)
    print(a.__dict__)
    print(a.__dir__())

     

     Note:dir是最大范围的收集一个类或者一个对象的属性,所以是包含__dict__.keys

    __call__

    对象后面加括号,触发执行。

    对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class C:
    
        def __init__(self):
            print("__init__")
        
        def __call__(self, *args, **kwargs):
    
            print('__call__')
    
    
    obj = C() # 执行 __init__
    obj()       # 执行 __call__

    为什么函数对象可以触发?

    f = abs
    
    print(dir(f))

    __len__

    果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。

    要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __len__(self):
            return len(self.__dict__)
    a = A()
    print(len(a))
    #2

    __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))
    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):
            # return str(self.a)+'哈哈'+str(self.b)
            
            return int(str(1024)+str(self.a)+str(self.b))
    a = A()
    print(hash(a))
    # TypeError: __hash__ method should return an integer

    __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) #true

    == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。默认会调用对象的 __eq__()方法。

  • 相关阅读:
    【MongoDB 工具篇】MongoDB Compass介绍
    【MongoDB 安全篇】MongoDB权限、角色管理
    【MongoDB 安全篇】MongoDB用户管理
    【MongoDB 基础篇】MongoDB增、删、改、查操作
    【MongoDB 安装篇】安装MongoDB单实例
    【Oracle 11g学习路线】
    MySQL自动化安装脚本
    Python条件判断
    Python数据类型
    MySQL服务器OOM导致数据库crash recovery
  • 原文地址:https://www.cnblogs.com/wqbin/p/10382750.html
Copyright © 2011-2022 走看看