获取指定成员Python本身有getattr和setattr方法。作为基本的反射能力,类成员和实例成员可以通过名字来访问。例如:classA:class_mem_x:int=8def__init__(self,p):self.instance_mem_p=p#print('self.yin__init__:{}'.format(self.instance_mem_p))a=A(3)print('getattrinstance_mem_p:{}'.format(getattr(a,'instance_mem_p')))print('getattrclass_mem_x:{}'.format(getattr(a,'class_mem_x')))setattr(a,'instance_mem_p'',5)print('a.instance_mem_paftersetattr:{}'.format(a.instance_mem_p))output:getattrinstance_mem_p:3getattrclass_mem_x:8a.instance_mem_paftersetattr:5它们可以访问类成员和实例成员,就像用'.'直接访问的效果一样。但是这两个方法都必须指定成员名,如果要写的代码不知道传入的对象有哪些成员,是无法获取到的。遍历实例成员所以python也为每个对象提供了__dict__内部变量(类型为dict)来获取所有实例成员:print('a.__dict__:{}'.format(a.__dict__))输出一个.__dict__:{'instance_mem_p':5}可以看出,实例成员其实是存储在一个dict中的,这点和js很像。但是这个方法获取不到类成员,A类的类成员class_mem_x不在其中。遍历类成员Python提供了一个方法叫dir,可以获取对象的所有属性,返回结果是一个属性名数组:print('dir(a):{}'.format(dir(a)))输出目录(a):['__annotations__','__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__','class_mem_x','instance_mem_p']可以看出类属性和实例属性都在里面,烦的是全内置属性也被列出。如果我们要去除它们,我们必须使用双破折号作为前缀和前缀来区分它们。即使去掉内置属性,也没有办法区分类成员和实例成员。当然,结合上面__dict__内置属性的内容,去掉实例成员,也可以得到类成员。这是一个小部件方法:defget_class_attr_names(obj):return[attr_nameforattr_nameindir(obj)if(notattr_name.startswith('__')andattr_namenotinobj.__dict__)]print('get_class_attr_names:{}'.好像没有办法直接获取类型定义来获取成员变量类型。毕竟python不是强类型,而是所谓的duck-typing语言。只能先获取成员属性的值,再使用类型函数判断类型。type函数的基本用法如下:type(a.class_mem_x)输出返回值为Types类型,那么可以使用下面的小函数获取各个属性的类型:defget_obj_attr_types(obj):return[(attr_name,type(getattr(obj,attr_name)))forattr_nameindir(obj)ifnotattr_name.startswith('__')]输出get_obj_attr_types:[('class_mem_x',),('instance_mem_p',),('test',)]返回值是由元组元素组成的数据,元组由name和类型对。在获取类成员方面的改进有了type函数判断类型,还可以对之前的get_class_attr_names做一个小的改进——因为dir函数实际上返回的是类方法,而__dict__内置属性中并没有类方法。如果要添加method删除它,就得使用类型判断,所以精确的类成员如下:importsysfromtypesimportMethodTypeclassA:class_mem_x:int=8def__init__(self,p):self.instance_mem_p=p#print('self.yin__init__:{}'.format(self.instance_mem_p))deftest(self):passa=A(3)defget_class_attr_names(obj):return[attr_nameforattr_nameindir(obj))if(notattr_name.startswith('__')andattr_namenotinobj.__dict__andtype(getattr(obj,attr_name))!=MethodType)]打印('get_class_attr_names:{}'.format(get_class_attr_names(a)))outputget_class_attr_names:['class_mem_x']注意:MethodType不是字符串,而是类,需要引入types模块。get_type_hints获取类信息从python3.5开始,typing模块提供了一个更好的方法get_type_hints来获取类信息。它的优点是可以直接获取类成员定义的类型——如果定义为str,赋值为None,也可以正确获取类型。下面看下和自定义现实的对比结果importsysfromtypesimportMethodTypefromtypingimportget_type_hintsclassA:class_mem_x:int=8class_mem_y:str=Nonedef__init__(self,p):self.instance_mem_p=p#print('self.y在__init__:{}'.format(self.instance_mem_p))deftest(self):passa=A(3)defget_class_attr_names(obj):return[attr_nameforattr_nameindir(obj)if(notattr_name.startswith('__')andattr_namenotinobj.__dict__andtype(getattr(obj,attr_name))!=MethodType)]class_attr_names=get_class_attr_names(a)defget_all_types(obj,names):return[(name,type(getattr(obj,name)))fornameinnames]print('get_all_types:{}'.format(get_all_types(a,class_attr_names)))print('get_type_hints:{}'.format(get_type_hints(a)))sys.exit()输入get_all_types:[('class_mem_x',),('class_mem_y',)]get_type_hints:{'class_mem_x':,'class_mem_y':}从结果可以明显看出区别:get_all_types返回的y属性类型是NoneType,而get_type_hints返回的是str集合对象的泛型类型。对于集合对象,如list、dict,其类型更为复杂。首先封装了typing模块,分别是List和Dict。如果有如下成员定义:importsysfromtypingimportget_type_hints,List,DictclassA:class_mem_x:List[int]=[3,5,7]class_mem_y:Dict[str,int]={'key1':9,'key2':26}a=A()print('get_type_hints:{}'.format(get_type_hints(a)))sys.exit()输出为:get_type_hints:{'class_mem_x':typing.List[int],'class_mem_y':typing.Dict[str,int]}获取集合对象元素的type_hint。集合对象的type_hint本身就是一个类型对象。要在代码中准确知道它的原始类型和元素类型,需要用到两个内部变量:__origin__和__args__上述示例之后的代码:x_types=get_type_hints(a)['class_mem_x']print('a.__origin__:{},a.__args__:{}'.format(x_types.__origin__,x_types.__args__))输出为:a.__origin__:,a.__args__:(,)其中__origin__为泛型对应的原始类型,如list或dict;__args__是泛型参数数组,对于list来说,它只有一个元素,表示列表中存放的是什么类型的数据。如果是dict,应该有两个参数,分别表示key和value的数据类型。