Python有没有办法通过类方法找到它所属的类?这个问题好像不太好理解,我可以举个例子:我们的问题是在装饰器代码中动态获取Test类(类名+类对象)。去年11月份,我在微信读者群里提出了这个问题,当时引起了不小的讨论。没想到今年最后一个月,群里又有人问了同样的问题(讨论后才看到),最后在stackoverflow上找到了同样的问题:stackoverflow上的问题说的很清楚:GetdefiningclassofunboundPython3中的methodobject。不过,unboundmethod这个名字已经不常见了,不展开详细讨论。有兴趣的同学可以看看。这个问题的关键是使用了Python3.3中引入的__qualname__属性,通过它可以得到上层类的名字。铺垫了这么多,让我们进入本文的正题:什么是__qualname__属性?为什么Python3要特别介绍呢?下面是PEP-3155的翻译摘录,清楚地解释了这个属性的来龙去脉。完整内容可以在Github仓库查看:https://github.com/chinesehuazhou/peps-cn/blob/master/StandardsTrack/3155--%E7%B1%BB%E5%92%8C%E6%96%B9%E6%B3%95%E7%9A%84%E7%89%B9%E5%AE%9A%E5%90%8D%E7%A7%B0.md-------------------摘录开始--------------------原理Python很长时间不支持嵌套类的内省了。给定一个类对象,不可能知道它是在类中还是在顶层模块中定义的;而且,如果是前者,就不可能知道它是在哪个类中定义的。虽然嵌套类通常被认为是不好的用法,但这不应该成为不支持内层自省的理由。Python3因放弃旧的未绑定方法而受到侮辱。在Python2中,给出如下定义:classC:deff():pass你可以从C.f对象中得到它所属的类:>>>C.f.im_class这个用法在Python3没有更多内容:>>>C.f.im_classTraceback(最近调用最后一次):文件“”,第1行,在AttributeError:'function'objecthasnoattribute'im_class'>>>dir(C.f)['__annotations__','__call__','__class__','__closure__','__code__','__defaults__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__get__','__getattribute__','__globals__','__gt__','__hash__','__init__','__kwdefaults__','__le__','__lt__','__module__','__name__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__']这限制了用户可用的内省功能。在将程序移植到Python3时,它可能会产生一些实际问题,例如在Twisted的核心代码中,它多次使用这种内省方法。此外,这限制了对pickle序列化的支持。提案此PEP提议向函数和类添加一个__qualname__属性。对于顶级函数和类,__qualname__属性等于__name__属性。对于嵌套类、方法和嵌套函数,__qualname__属性包含指向顶级模块下对象的虚线路径。函数的本地命名空间由名为的组件在虚线路径中表示。函数和类repr()和str()被修改为使用__qualname__而不是__name__。嵌套类示例>>>classC:...deff():pass...classD:...defg():pass...>>>C.__qualname__'C'>>>C.f.__qualname__'C.f'>>>C.D.__qualname__'C.D'>>>C.D.g.__qualname__'C.D.g'嵌套函数示例>>>deff():...defg():pass...returng...>>>f.__qualname__'f'>>>f().__qualname__'f..g'不足之处对于嵌套函数(以及定义在函数内部的类),由于函数的命名空间无法从外部获取,所以不能以动态编程方式遍历虚线路径。与空的__name__相比,它对人类读者有些帮助。与__name__属性一样,__qualname__属性是静态计算的,不会自动反弹。讨论剥离模块名称与__name__一样,__qualname__不包含模块的名称。这使得它独立于模块别名和重新绑定,也可以在编译时进行评估。恢复未绑定方法恢复未绑定方法仅解决了此PEP解决的部分问题,而且成本更高(额外的对象类型和额外的间接而不是额外的属性)。------------------摘录结束--------------------后记去年我在读ddtlibraryaboutparameters在优化测试源码的时候,偶然想到了文章开头的问题,但是没有做进一步的整理(貌似感兴趣的人不多)。没想到群里又出现了同样的讨论,让我意识到这个问题的价值。前几天无意中发现__qualname__属性有专门的PEP,于是抽空翻译了一下——既是一种知识梳理,也是给大家的一次“科普”。可能其他人也会遇到同样的问题,希望对大家有所帮助。更多PEP的中文翻译可以在Github上找到:https://github.com/chinesehua...