python中的__getattr__、__getattribute__、__setattr__、__delattr__、__dir__

__getattr__:
     属性查找失败后,解释器会调用 __getattr__ 方法.

class TmpTest:
    def __init__(self):
        self.tmp = 'tmp123'
    def __getattr__(self, item):
        raise AttributeError('{} object has no attribute {}'.format(type(self), item))
a=TmpTest()

print(a.tmp)
结果:
    tmp123

print(a.tmpnone)
结果:
    Traceback (most recent call last):
      File "D:/pythonScript/leetcode/leetcode.py", line 12, in <module>
        print(a.tmpnone)
      File "D:/pythonScript/leetcode/leetcode.py", line 7, in __getattr__
        raise AttributeError(msg.format(tmp_cls, item))
    AttributeError: <class '__main__.TmpTest'> object has no attribute tmpnone

 a.tmpnone 表达式执行顺序:
       1、首先会检查a实例有没有名为tmpnone的属性
       2、到类(a.__class__)中查找
       3、顺着继承树继续查找.
       4、调用a所属类中定义的 __getattr__ 方法,传入self和属性名称的字符串形式(如 'tmpnone').


__getattribute__:
 1、尝试获取指定的属性时总会调用这个方法,寻找的属性是特殊属性或特殊方法时除外.
    2、点号与 getattr 和 hasattr 内置函数会触发这个方法.
    3、调用 __getattribute__ 方法且抛出 AttributeError 异常时,才会调用 __getattr__ 方法.
    4、为了在获取实例的属性时不导致无限递归,__getattribute__ 方法的实现要使用 super().__getattribute__(name)

class TmpTest:

    def __getattr__(self, item):
        print("getting __getattr__ {}".format(item))
        self.__dict__[item] = '__getattr__'
        return '__getattr__'

    def __getattribute__(self, item):
        print ("getting __getattribute__ {}".format(item))
        if item=='x':
            raise AttributeError
        return object.__getattribute__(self, item)

    def __setattr__(self, key, value):
        print("getting __setattr__ {}".format(key))
        return object.__setattr__(self, key, value)

a=TmpTest()
a.x='getattr'
print (a.x)

结果:
getting __setattr__ x   
getting __getattribute__ x       #抛出异常
getting __getattr__ x            #执行__getattr__
getting __getattribute__ __dict__  
__getattr__


__setattr__:
    尝试设置指定的属性时会调用这个方法.点号和 setattr 内置函数会触发这个方法.例如我们上面的例子a.x='getattr'和 setattr(a, 'x', "getattr") 都会触发 TmpTest.__setattr__(a, 'x', "getattr") 方法.,
    如果实现了 __getattr__ 方法,最好同时定义 __setattr__ 方法

__delattr__:
    只要使用del语句删除属性,就会调用这个方法.例如,del a.x 语句触发 Class.__delattr__(a, 'x') 方法
    实现方法:

    def __delattr__(self, item):
        print ("getting __delattr__ {}".format(item))
        del self.__dict__[item]


dir():
    1、在没有参数的情况下,返回当前作用域内的名称列表。
    2、如果对象有一个名为dir()的方法,那么这个方法就会被调用
    3、模块对象,返回模块的属性列表
    4、类对象,返回累的属性名称和基类的属性列表

看下官方的文档例子:

    >>> import struct
    >>> dir()   # show the names in the module namespace  
    ['__builtins__', '__name__', 'struct']
    
    >>> dir(struct)   # show the names in the struct module
    ['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__',
     '__initializing__', '__loader__', '__name__', '__package__',
     '_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
     'unpack', 'unpack_from']
     
    >>> class Shape:
    ...     def __dir__(self):
    ...         return ['area', 'perimeter', 'location']
    >>> s = Shape()
    >>> dir(s)
    ['area', 'location', 'perimeter']

 

posted @ 2018-09-21 13:12  丁壮  阅读(834)  评论(0编辑  收藏  举报