1. 对象的自省机制
自省是通过一定的机制查询到对象的内部结构
dir(obj)
dir(obj)可以获取一个对象所有的属性与方法, 返回为列表(仅有属性或方法名称)
dir()是 Python 提供的一个 API 函数, dir()函数会自动寻找一个对象的所有属性(包括从父类中继承的属性和方法)
__dict__
__dict__字典中存储的是对象或类的部分属性, 键为属性名, 值为属性值
实例对象的__dict__仅存储与该实例相关的实例属性
类的__dict__存储所有实例对象共享的变量和函数(类属性, 方法等), 类的__dict__并不包含其父类的属性和方法
dir()和__dict__的区别
1.dir()是一个函数, 返回的是 list, 仅有属性名和方法名;
2.__dict__是一个字典, 键为属性名, 值为属性值;
3.dir()用来寻找一个对象的所有属性和方法 (包括从父类中继承的属性和方法), 包括__dict__中的属性和方法,__dict__是 dir() 的子集;
注:? 并不是所有对象都拥有__dict__属性. 许多内建类型就没有__dict__属性, 如 list, 此时就需要用 dir()来列出对象的所有属性和方法
- class Person:
- name = "user"
- class Student(Person):
- city = 'gz'
- def __init__(self, school_name):
- self.school_name = school_name
- if __name__ == "__main__":
- user = Student("慕课网")
- # 通过__dict__查询属性
- print(user.__dict__) # 仅有实例属性
- # {'school_name': '慕课网'}
- user.__dict__['schoole_addr'] = "beijing"
- print(user.schoole_addr)
- # beijing
- print(Student.__dict__) # 仅有类属性, 没有实例属性
- # {'__module__': '__main__', 'city': 'gz', '__init__': <function Student.__init__ at 0x0597DF18>, '__doc__': None}
- print(user.name) # name 是属于 Person 类的属性, 并不是 Student 类的属性
- # user
- print(Person.__dict__) # 父类的类属性和方法
- # {'__module__': '__main__', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
- print(dir(user)) # user 对象的所有属性和方法, 包含从父类继承的
- # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'city', 'name', 'school_name', 'schoole_addr']
2.__getattr__,__getattribute__魔法函数
__getattr__ 只是在查找不到属性的时候调用
__getattribute__访问对象的属性 (obj.attr) 时无条件最先调用该方法, 不建议重写该方法
3. 属性描述符
- __get__
- __set__
- __delete__
实现上述三个魔法函数其中之一即可成为属性描述符, 如果只实现__get__称之为非数据属性描述符, 只有同时实现__get__和__set__才称之为数据属性描述符
- import numbers
- class IntField:
- # 数据描述符
- def __get__(self, instance, owner):
- return self.value
- def __set__(self, instance, value):
- if not isinstance(value, numbers.Integral):
- raise ValueError("int value need")
- if value <0:
- raise ValueError("positive value need")
- self.value = value
- def __delete__(self, instance):
- pass
- # class NonDataIntField:
- # # 非数据属性描述符
- # def __get__(self, instance, owner):
- # return self.value
- class User:
- age = IntField()
- # age = NonDataIntField()
- if __name__ == "__main__":
- user = User()
- user.age = 30 # 调用 age 对象的__set__
- print(user.age) # 调用 age 对象的__get__
4. 属性查找过程
如果 user 是某个类的实例, 那么 user.age(以及等价的 getattr(user,'age')), 首先调用__getattribute__. 如果类定义了__getattr__方法, 那么在__getattribute__抛出 AttributeError 的之前就会调用__getattr__, 而对于描述符 (__get__) 的调用, 则是发生在__getattribute__内部的.
user = User(), 那么 user.age 顺序如下:
(1)如果 "age" 是出现在 User 类或其基类的__dict__中(类属性), 且 age 是 data descriptor, 那么调用其__get__方法, 否则
(2)如果 "age" 出现在 user 的__dict__中 (对象属性), 那么直接返回 obj.__dict__['age'], 否则 --> 如果 age 不是类属性或者 User 不是数据属性描述符, 则去对象属性中查找 age
(3)如果 "age" 出现在 User 或其基类的__dict__中(类属性)
(3.1)如果 age 是 non-data descriptor, 那么调用其__get__方法, 否则
(3.2)返回 class.__dict__['age']
(4)如果 User 有__getattr__方法, 调用__getattr__方法, 否则 -->对象属性和类属性中都没有 age, 则调用 User 类的__getattr__方法
(5)抛出 AttributeError
来源: http://www.bubuko.com/infodetail-2986801.html