Python中如何访问与方法同名的类变量?同名成员访问冲突如何解决
核心前提说明
你提供的原始代码中,类变量name已经被后续定义的同名方法覆盖:Python解析类定义时会按从上到下的顺序执行代码,所有变量、方法都会存入类的__dict__属性字典,同名键的后续赋值会直接覆盖之前的内容,因此Example类的__dict__中name最终对应的值是方法函数,最初定义的字符串类变量已经被清除。
如果需要同时访问同名的变量和方法,可以参考以下两种方案:
方案1:给实例添加独立的name属性
利用实例属性查找优先级高于类属性的特性,给实例单独赋值name,访问时直接返回变量值,需要调用方法时主动从类的属性字典调取:
c1 = Example() # 给实例添加name属性 c1.name = "Its a Variable" # 访问变量,输出:Its a Variable print(c1.name) # 调用方法,输出:Its a Method print(Example.__dict__['name'](c1))
方案2:调整类定义顺序,优先保留类变量
把类变量的定义放到方法之后,覆盖类命名空间中方法对应的name键,调用方法时主动从类属性字典取函数执行:
class Example(): def name(self): return "Its a Method" # 类变量定义在后,覆盖同名方法的绑定 name = "Its a Variable" c1 = Example() # 直接访问拿到类变量,输出:Its a Variable print(c1.name) # 调用方法,输出:Its a Method print(Example.__dict__['name'](c1))
1. 类的命名空间规则
Python在解析类定义时,会创建一个专属的字典对象(即类的__dict__属性)存储类的所有成员:变量赋值、方法定义都会作为键值对存入这个字典,同一个键如果被多次赋值,后面的值会直接覆盖前面的值。你原始代码中先给name赋值字符串,随后def name(self)的本质就是给类字典的name键赋值为函数对象,因此最初的字符串类变量被直接覆盖。
2. 实例属性查找规则
当你通过实例.属性名访问内容时,Python会按以下优先级查找:
- 第一步:优先查询实例自身的
__dict__字典,如果存在对应键直接返回值,终止查找 - 第二步:实例自身没有对应键,就查询实例所属类(即
实例.__class__)的__dict__字典 - 第三步:类字典中没有找到,就按方法解析顺序(MRO)查询所有父类的
__dict__字典 - 第四步:所有位置都未找到则抛出
AttributeError
你原始代码中实例c1自身没有name属性,因此会查找到类字典中的name对应的函数,Python会自动将这个函数和实例绑定为绑定方法对象,也就是你看到的<bound method Example.name of <__main__.Example object at 0x7f430d8de490>>结果。
内容的提问来源于stack exchange,提问作者Himanshu Shakyawar

