• python学习之 getattr vs __get__ vs __getattr __ vs __getattribute__ vs __getitem__


     1. getattr、setattr、hasattr

      getattr比较常用,与setattr和hasattr一起出现,他们也是最容易理解的,下面是他的用法:

    class Profile():
         name="xiaoxin"
    def sex(self): return "male"p=Profile() hasattr(p, "name") # 判断属性是否存在 >>> True hasattr(p, "age") # 判断属性是否存在 >>> False
    getattr(p, "name") # 获取属性值
    >>> xiaoxin
    getattr(p, "sex")
    >>> <bound method Profile.sex of <__main__.Profile object at 0x7f22608f9710>>
    getattr(p, "age", 14) # 如果属性不存在,则返回默认值
    >>> 14
    setattr(p, "age", "26") # 为属性赋值,并没有返回值 hasattr(p, "age") # 属性存在了 >>> True

    2. __get__ 、 __set__、 __delete__

      提起__get__, 就不能不说  __set__, __delete__ , 一个类,只要其内部定义了方法 __get__, __set__, __delete__ 中的一个或多个,就可以称其为描述符。如果同时定义了__get__()__set__(),其被认为是一个数据描述符。只定义__get__()的描述符被称为非数据描述符。

      描述符常被用来作类型检查, 下面看它的具体用法:

    class Integer:
        def __init__(self, name):
            self.name = name
    
        def __get__(self, instance, owner):
        
    if instance is None: return self else: return instance.__dict__[self.name] def __set__(self, instance, value):
        
    if not isinstance(value, int): raise TypeError('excepted an int') instance.__dict__[self.name] = value def __delete__(self, instance):
        
    del instance.__dict__[self.name] class Point: x = Integer('x') y = Integer('y') def __init__(self, x, y): self.x = x self.y = y

    p = Point(2, 3)
    p.x
    >> 2
    p.y
    >> 3
    p = Point(2.5, 3)
    >> TypeError: excepted an int

      需要注意的是,对象属性的访问顺序:实例属性>类属性>父类属性>__getattr__(),当Python解释器发现实例对象的字典中,有与描述符同名的属性时,描述符优先,会覆盖掉实例属性。

     3. __getattr__ 、__setattr__ 、__delattr__

      从对象中读取某个属性时,首先需要从self.__dicts__中搜索该属性,如果__dict__中没有该属性, 再从__getattr__中拿到返回值。当设置属性时,则会触发__setattr__方法,在这里可以进行类型验证(描述符只会对定义的描述符属性进行类型验证, 而__setattr__会对所有属性进行类型验证)

    class Point:
    
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __getattr__(self, item):
            print(f'getattr {item}')
            return None
    
        def __setattr__(self, key, value):
            print(f'setattr {key}:{value}')
            if isinstance(value, int):
                return object.__setattr__(self, key, value)
    
        def __delattr__(self, item):
            print(f"delattr {item}")
            del self.__dict__[item]

    p = Point(2, 3)

    >>> setattr x:2
    >>> setattr y:3

    p.x

    >>> 3

    p.c

    >>> getattr c

    >>> None

    p.c = 9

    >>> setattr c:9

    p.c

    >>> 9

    4. __getattribute__ 

       无论调用属性还是方法,都是先强制调用 __getattribute__ 方法,然后再传回属性的值或者是 函数(方法)的引用。

    class Point:
    
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __getattribute__(self, item):   # 在 __getattribute__ 方法里面不要在出现self.**这种调用,因为每次调用类的属性都会强制调用 __getattribute__ ,会造成递归调用
            return 'i get you ' if item == 'x' else object.__getattribute__(self, item)
    
        def __getattr__(self, item):
            print(f'getattr {item}')
            return None
    p = Point(2, 3)
    p.x
    >>> i get you
    p.y
    >>> 3
    p.c # 首先调用 __getattribute__ , 里面实现了 查找__dict__里面有没有这个键,如果没有再调用 __getattr__方法
    >>> getattr c
    >>> None

     5. __getitem__、__setitem__、__delitem__

    这三个方法主要用于对集合的操作

    可变集合需要实现: __len__  __getitem__    __setitem__  __delitem__
    不可变集合需要实现: __len__  __getitem__
    __len__:返回集合长度
    __getitem__(self, item) 使用索引访问元素
    __setitem__(self, key, value) 对索引赋值,使用 self[key] = value 。
    __delitem__(self, key) 删除索引值 del self[key]
    __contains__ 实现in运算符,如果没有实现这个方法python也会调用__getitem__来使in运算符可用

    class TemTest:
    
        def __init__(self,):
            self.x = [i for i in range(10)]
    
        def __len__(self):
            return len(self.x)
    
        def __getitem__(self, item):return self.x[item]
    
        def __setitem__(self, key, value):
            self.x[key] = value
    
        def __delitem__(self, key):
            del self.x[key]
    
        def __contains__(self, item):
            return item in self.x
    
        def __repr__(self):
            return '{}'.format(self.x)
    test=TemTest() #实例化
    print(len(test)) #返回长度
    print(test[0])   #打印下标0的值
    print(test[:3])  #切片
    test[3]=10       #将下标3的值替换为10
    print(test)
    del test[3]      #删除下标3的值
    print(test)
    print(1 in test)  #测试in运算符
    print(3 in test)  
    10
    0
    [0, 1, 2]
    [0, 1, 2, 10, 4, 5, 6, 7, 8, 9]
    [0, 1, 2, 4, 5, 6, 7, 8, 9]
    True
    False

    参考博文:https://www.cnblogs.com/flashBoxer/p/9645939.html 

  • 相关阅读:
    数据结构和算法大纲
    内存碎片产生原因及处理技术
    相关资源
    busybox hexdump 命令使用
    http协议中content-length 以及chunked编码分析
    libtool工具的使用
    音视频学习相关资源
    winpcap
    ipkg包管理
    system返回值校验
  • 原文地址:https://www.cnblogs.com/jiaxiaoxin/p/10741262.html
Copyright © 2020-2023  润新知