一个在交流群里讨论过两轮的问题,答案竟然跟一个 PEP 有关
Python 中有没有办法通过类方法找到其所属的类?
这个问题看起来不容易理解,我可以给出一个例子:
class Test:
@xxx
def foo(self):
pass
现在有一个类和一个类方法,其中类方法上有一个装饰器。
我们的问题就是要在装饰器代码中动态地获得 Test 这个类(类名+类对象)。
去年 11 月份的时候,我在微信读者群里提出了这个问题,当时引起了小范围的讨论。
没想到在今年上个月的时候,群里又有人提了同样的问题(我在讨论结束后才看到),而且最终都找到了 stackoverflow 上一个同样的问题:

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
一个在交流群里讨论过两轮的问题,答案竟然跟一个 PEP 有关的更多相关文章
- python学习总结---学习交流群里的问题总结
xml里面的过滤: <record id="action_partner_supplier_form_demo_ms" model="ir.actions.act_ ...
- 为什么 1KB = 1024Byte???群里讨论。
- 我们建了一个 Golang 硬核技术交流群(内含视频福利)
目录 目录 Golang 是什么? 我们为什么选择 Golang? Golang 是云时代的宠儿! 我们搞了一场 Golang 入门直播 Golang 是什么? Golang 是谷歌 2009 年发布 ...
- 新开了一个ABP交流的QQ群(579765441 ),欢迎加入
因为ABP架构设计交流群人数一直爆满,很多想交流ABP的朋友无法加进群里, 刚新建了一个QQ群,群号579765441 (ABP架构设计交流群2),欢迎对ABP感兴趣的朋友加入. 欢迎加QQ群: AB ...
- 2017-8-2新开了一个ABP交流的QQ群(291304962 ),欢迎加入
因为ABP架构设计交流群人数一直爆满,很多想交流ABP的朋友无法加进群里, 刚新建了一个QQ群,群号291304962(ABP架构设计交流群3),欢迎对ABP感兴趣的朋友加入. 欢迎加QQ群: ABP ...
- 欢迎加入.NET Core 技术QQ群一起讨论交流学习
群号:4656606 介绍:本群主要讨论.NET Core及其相关技术,如:IdentityServer4.ABP.Dcoker.Linux.Devops.微服务等,如果你正在使用或者准备使用.NET ...
- 剑指offer40:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
1 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 2 思路和方法 (1)异或:除了有两个数字只出现了一次,其他数字都出现了两次.异或运算中,任 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- 群里分享的react的收藏一下!今日周末,改了个表单验证然后无所事事了!
今日周末,改了个表单验证然后无所事事了,然后把昨天群里分享的react的收藏一下尽管现在还在研究angular和nodeJs毕竟刚刚开始用有点不熟...没准以后会研究一下react毕竟看着下面这张图还 ...
随机推荐
- Java实现一个简单的文件上传案例
Java实现一个简单的文件上传案例 实现流程: 1.客户端从硬盘读取文件数据到程序中 2.客户端输出流,写出文件到服务端 3.服务端输出流,读取文件数据到服务端中 4.输出流,写出文件数据到服务器硬盘 ...
- MVC + EFCore 项目实战 - 数仓管理系统7 - 数据源管理中--新增数据源
上篇我们完成了数据源列表展示功能(还未测试). 本篇我们来新增数据源,并查看列表展示功能. 接上篇: 二.数据源管理功能开发 2.新增数据源 我们用模态对话框来完成数据源的新增,效果如下图: 我们 ...
- NoSQL和SQL怎么选用?
NoSQL 有分很多种,其中key-value NoSQL (Redis, MemcacheD, etc) 的选用相对比较清楚些,大多是当后端Data storage的cache层来用.这篇主要想请教 ...
- python匿名函数和内置函数
一.匿名函数 匿名函数定义lambda a,b,c:(x,y,z) a.b.c相当于形参,多个形参之间用逗号隔开,多个形参不能用括号括起来 (x.y.z)相当于返回值,多个返回值之间用逗号隔开,多个返 ...
- 【JMicro】微服务部署架构及实例
序言 JMicro是一个用Java语言实现的开源微服务全家桶,源码地址:https://github.com/mynewworldyyl/jmicro,Demo地址:http://124.70.152 ...
- File类的基本概念与递归
一.File类 1.概念 File类:是文件和目录路径名的抽象表示形式. 即,Java中把文件或者目录(文件夹)都封装成File对象.也就是说如果我们要去操作硬盘上的文件,或者文件夹只要找到File这 ...
- MacOS入门
原文池建强的blog 对普通用户来说,用好Mac主要有三点: 1.理解OSX的基本结构和特点 2.掌握多手势和快捷键(少量即可,多多益善) 3.用好工具 一.理解OSX的基本结构和特点 Mac OS ...
- CSS两列布局的N种实现
一.什么是两列布局 两列布局分为两种,一种是左侧定宽.右侧自适应,另一种是两列都自适应(即左侧宽度由子元素决定,右侧补齐剩余空间).在CSS面试题里面属于常考题,也是一个前端开发工程师必须掌握的技能, ...
- 关于SqlServer表结构 2(回归基础)
关于SqlServer表结构的问题.先来了解一下SqlServer中的数据类型以及它们的用法 整型: 短整型 smallint 整型 int 长整型 bitint 标识列:identity(它是只读的 ...
- 查看 Linux 系统服务的 5 大方法
Linux 系统服务有时也称为守护程序,是在Linux启动时自动加载并在Linux退出时自动停止的系统任务. 在本文中,良许将为大家介绍如何列出 Linux 系统里所有运行的服务,以及如何检查某个服务 ...