首页 > 其他分享 >一个在交流群里讨论过两轮的问题,答案竟然跟一个 PEP 有关

一个在交流群里讨论过两轮的问题,答案竟然跟一个 PEP 有关

时间:2022-10-14 14:07:57浏览次数:77  
标签:两轮 __ 群里 ... Python PEP qualname class 属性

Python 中有没有办法通过类方法找到其所属的类?

这个问题看起来不容易理解,我可以给出一个例子:

class Test:
@xxx
def foo(self):
pass

现在有一个类和一个类方法,其中类方法上有一个装饰器。

我们的问题就是要在装饰器代码中动态地获得 Test 这个类(类名+类对象)。

去年 11 月份的时候,我在微信读者群里提出了这个问题,当时引起了小范围的讨论。

没想到在今年上个月的时候,群里又有人提了同样的问题(我在讨论结束后才看到),而且最终都找到了 stackoverflow 上一个同样的问题:

一个在交流群里讨论过两轮的问题,答案竟然跟一个 PEP 有关_github

stackoverflow 上的问题提得很明确:​​Get defining class of unbound method object in Python 3​​ 。但是 unbound method 的叫法已经不常见了,详细的讨论也就不展开了,感兴趣的同学可以去查阅。

这个问题的关键是要使用在 Python 3.3 中引入的__qualname__ 属性,通过它可以获取上层类的名称。

铺垫了这么多,开始进入本文的正题了:__qualname__ 属性是什么东西?为什么 Python 3 要特别引入它呢?

下文是 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 的支持很不够。给定一个类对象,根本不可能知道它是在某个类中定义的,还是在顶层模块中定义的;而且,如果是前者,也不可能知道它具体是在哪个类中定义的。虽然嵌套类通常被认为是不太好的用法,但这不应该成为不支持内层自省的理由。

Python 3 因为丢弃了以前的未绑定方法(unbound method),而受到了侮辱性的伤害。

在 Python 2 中,给出以下定义:

class C:
def f():
pass

你可以从​​C.f​​ 对象中获得其所属的类:

>>> C.f.im_class
<class '__main__.C'>

这种用法在 Python 3 中已经没有了:

>>> C.f.im_class
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '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__']

这就限制了用户可以使用的自省能力。当将程序移植到 Python 3 时,它可能会产生一些实际的问题,例如在 Twisted 的核心代码中,就多次使用到了这种自省方法。此外,这还限制了对 pickle ​​序列化的支持​​ 。

提议

本 PEP 提议在函数和类中添加 __qualname__ 属性。

对于顶层的函数和类,__qualname__ 属性等于__name__ 属性。对于嵌套的类、方法和嵌套函数,__qualname__ 属性包含一个点式路径(dotted path),通向顶层模块下的对象。函数的局部命名空间在点式路径中由名为 <locals> 的组件表示。

函数和类的 repr() 和 str() 被修改为使用__qualname__ 而不再是__name__。

嵌套类的示例

>>> class C:
... def f(): pass
... class D:
... def g(): pass
...
>>> C.__qualname__
'C'
>>> C.f.__qualname__
'C.f'
>>> C.D.__qualname__
'C.D'
>>> C.D.g.__qualname__
'C.D.g'

嵌套函数的示例

>>> def f():
... def g(): pass
... return g
...
>>> f.__qualname__
'f'
>>> f().__qualname__
'f.<locals>.g'

不足之处

对于嵌套函数(以及在函数内部定义的类),由于无法从外部获得函数的命名空间,因此点式路径无法以动态编程的方式遍历。相比于空的__name__,它对于人类读者还是有些帮助的。

跟__name__属性一样,__qualname__ 属性是静态计算的,不会自动地重新绑定。

讨论

去除模块名称

跟__name__一样,__ qualname__ 不包含模块的名称。这使得它不受制于模块别名和重新绑定,也得以在编译期进行计算。

恢复 unbound 方法

恢复 unbound 方法只能解决此 PEP 解决了的部分问题,而且代价更高(额外的对象类型和额外的间接寻址,不如用额外的属性)。

-------------------摘录结束--------------------

后记

去年我在阅读​​ddt​​​ 库关于​​参数化测试的源码​​ 时,偶然想到了文章开头的问题,但是没有作进一步的梳理(似乎感兴趣的人也不多)。没想到的是在群里又出现了同样的讨论,这让我意识到这个问题是有价值的。

前几天,我偶然间发现__qualname__ 属性有一个专门的 PEP,所以我就抽空把它翻译出来了——既是一种知识梳理,也是给大家做一个“科普”吧。说不定什么时候,还有人会遇到同样的问题呢,希望对大家有所帮助。

更多的 PEP 中文翻译内容,可在 Github 查阅:​​https://github.com/chinesehuazhou/peps-cn​



标签:两轮,__,群里,...,Python,PEP,qualname,class,属性
From: https://blog.51cto.com/u_14244765/5756382

相关文章

  • [译] PEP 255--简单的生成器
     我正打算写写Python的生成器,然而查资料时发现,引入生成器的PEP没人翻译过,因此就花了点时间翻译出来。如果在阅读时,你有读不懂的地方,不用怀疑,极有可能是我译得不到位。......
  • python 编码规范起源:PEP8 编码规范中文版
     PEP:8标题:Python代码的样式指南版:c451868df657最后修改:​​2016-06-0810:43:53-0400(2016年6月8日星期三)​​作者:GuidovanRossum<guidoatpython.org>,BarryWarsaw<b......
  • 【Golang开发面经】深信服(两轮技术面)
    文章目录​​写在前面​​​​一面​​​​了解过切片和数组吗?有什么区别?​​​​那这样初始化可以吗?有什么问题?​​​​用过map吧?怎么遍历map?​​​​那遍历map是有序的......
  • 群里问题:BP的文本修改
    货铺QQ群号:834508274下面开始干货:群里今天有人问下面的问题:BP里的这个注释的标题在哪里改?我当时给他分享了两篇文章,因为我开电脑也没进系统看啥的,所以只是说仅供参考而已。......
  • 为什么有的员工干一点活就要拍照,发到公司的工作群里?
    员工干点活就要拍照发群里,很多公司都出现这样的现象。不仅如此,凡事与工作有关的信息,哪怕打扫个卫生,领导就在身边,也要到群里请示。一切的工作,都要在群里体现出来。这不是正常......
  • Educational Codeforces Round 135 (Rated for Div. 2) - E. Red-Black Pepper
    exgcdProblem-E-Codeforces题意给\(n\;(n<=3*10^5)\)个菜,每个菜可以加红辣椒或黑辣椒,分别可以获得\(c[i],d[i]\)分;有\(m\;(m<=3*10^5)\)个商店,第i个商店包......
  • pep9求三数和
    伪代码Setsumto0ReadnumSetsumtosun+numReadnumSetsumtosun+numReadnumSetsumtosun+numWritesum机械码 ......
  • 引用 | pip install keybert | ERROR: Could not build wheels for tokenizers which
    window10安装keybert出错以下错误:runningbuild_extrunningbuild_rusterror:can'tfindRustcompilerIfyouareusinganoutdatedpipversion,it......
  • PEP8规范
    PEP8规范pycharm中很多时候会有各种颜色提示还有波浪线 只要不是红线一般都不影响代码运行​对比图1中的两段代码你会发现,它们所包含的代码时完全相同的,......
  • 六、python基础知识之变量常量、索引取值和PEP8规范
    目录一、变量与常量1.什么是变量?2.什么是常量?变量的基本使用变量使用的语法结构与底层原理变量名的命名规范和命名风格变量的命名风格常量的基本使用二、索引取值三、PEP......