# 定义 class T: a = 123 #类属性 def func(self): #类方法 pass @classmethod def classfunc(cls): pass @staticmethod def staticfunc(): pass print('访问类属性a ' + str(T.a)) T.b = 123 #设置类属性 print('访问类属性b ' + str(T.b)) t = T() print('访问实例属性a ' + str(t.a)) t.b = 123 print('访问实例属性b ' + str(t.b)) # 问题的引申 ''' 1、python中属性的设置是支持动态的 属性不必要非得在类定义时去完成定义,完全可以去动态的设置属性 ''' ''' 2、类中的属性存放在哪里?通过什么样的方式可以获取到? ''' print(T.__dict__.keys()) #['__module__', 'a', 'func', 'classfunc', 'staticfunc', '__dict__', '__weakref__', '__doc__', 'b'] print(t.__dict__.keys()) #['b'] print(id(T.__dict__)) #2541102594568 print(id(t.__dict__)) #2541071252576 ''' 通过查阅官方文档发现,这些属性存在__dict__特殊属性里,类的属性可能与实际存储在类中的对象不同的另一种方式__dict__, 也就是说类与对应实例分别有对应的__dict__ 通过例子可以发现,实例中的__dict__只有一个b的属性 ''' ''' 3、类中属性的查找方式? 首先会在类属性__dict__中查找,当在那里找不到属性名称时,属性搜索在基类中继续。对基类的搜索使用C3方法解析顺序 ''' class TT(T): pass print(TT.a) #输出基类a属性a的值 123 ''' 4、类实例属性的查找方式? 类实例具有作为字典实现的名称空间,该__dict__是搜索属性引用的第一个位置。 当在那里找不到属性,并且实例的类具有该名称的属性时,搜索继续使用类属性。 如果找到的类属性是用户定义的函数对象,则将其转换为实例方法对象,静态方法和类方法对象也被转换。 了解通过其实例检索的类的属性可能与实际存储在类中的对象不同的另一种方式__dict__。 如果没有找到类属性,并且对象的类有一个__getattr__()方法,则调用该方法以满足查找。 ''' t2 = TT() print(t2.a)#输出a的值123 ''' 4、类的特殊属性 object.__dict__ 用于存储对象(可写)属性的字典或其他映射对象。 instance.__class__ 类实例所属的类。 class.__bases__ 类对象的基类的元组。 definition.__name__ 类,函数,方法,描述符或生成器实例的名称。 definition.__qualname__ 类,函数,方法,描述符或生成器实例的限定名称。 版本3.3中的新功能。 class.__mro__ 此属性是在方法解析期间查找基类时考虑的类的元组。 class.mro()¶ 元类可以重写此方法,以自定义其实例的方法解析顺序。它在类实例化时调用,其结果存储在__mro__。 class.__subclasses__() 每个类都保留一个对其直接子类的弱引用列表。此方法返回所有仍然存活的引用的列表 ''' #按照的之前的推断,自定义类属性都被放在__dict__我们可以按照之前的方式去访问一些属性, #但是这其中也有些例外,看例子 #print(t2.__mro__)#我们这里获取类的继承列表,按照惯例,实例中访问不到的属性,会去类中寻找,然而报错了AttributeError: 'TT' object has no attribute '__mro__' print(TT.__mro__)#通过类访问却可以访问到(<class '__main__.TT'>, <class '__main__.T'>, <class 'object'>) ''' 也就是说自定义属性只会在__dict__中寻找,__mro__ 与 __dict___是属于并列、平行属性, 有些属性是类'特有的' 同样特殊属性还有__name__等,我们可以通过dir去获取类的属性,但是这种方式并不能将所有的 属性查找出来,部分特殊属性无法取出来例如__name__、__mro__、__dict__等,详细可以参照官方文档的特殊属性介绍 ''' ''' 5、dir获取对象有效属性的规则 如果没有参数,则返回当前本地范围中的名称列表。使用参数,尝试返回该对象的有效属性列表。 如果对象具有名为的__dir__()方法,则将调用此方法,并且必须返回属性列表。这允许实现自定义__getattr__()或__getattribute__()函数的对象自 定义dir()报告其属性的方式 。 如果对象未提供__dir__(),则该函数会尽力从对象的__dict__属性(如果已定义)和其类型对象中收集信息。结果列表不一定完整,并且在对象具有自定义时可能不准确__getattr__()。 默认dir()机制对不同类型的对象的行为有所不同,因为它尝试生成最相关的信息,而不是完整的信息: 如果对象是模块对象,则列表包含模块属性的名称。 如果对象是类型或类对象,则列表包含其属性的名称,并且递归地包含其基础的属性。 否则,该列表包含对象的属性名称,其类的属性的名称,以及其类的基类的属性的递归。 '''