在 Python 2 中,可以将任意可调用对象转换为类的方法。重要的是,如果 callable 是用 C 实现的 CPython 内置,您可以使用它来创建用户定义类的方法,这些方法本身就是 C 层,调用时不调用字节码。
如果您依赖 GIL 提供“无锁”同步,这有时会很有用;由于 GIL 只能在操作代码之间交换,如果代码的特定部分中的所有步骤都可以推送到 C 中,则可以使其以原子方式运行。
在 Python 2 中,您可以执行以下操作:
import types
from operator import attrgetter
class Foo(object):
... This class maintains a member named length storing the length...
def __len__(self):
return self.length # We don't want this, because we're trying to push all work to C
# Instead, we explicitly make an unbound method that uses attrgetter to achieve
# the same result as above __len__, but without no byte code invoked to satisfy it
Foo.__len__ = types.MethodType(attrgetter('length'), None, Foo)
在 Python 3 中,不再有未绑定的方法类型,并且types.MethodType
只接受两个参数并只创建绑定方法(这对于 Python 特殊方法(如__len__
,__hash__
等)没有用处,因为特殊方法通常直接在类型上查找,不是实例)。
在 Py3 中是否有一些我缺少的方法来实现这一点?
我看过的东西:
functools.partialmethod
(似乎没有 C 实现,所以它不符合要求,并且在 Python 实现和比我需要的更通用的用途之间,它很慢,在我的测试中大约需要 5我们,而直接约 200-300 ns Python 定义或attrgetter
在 Py2 中,开销增加了大约 20 倍)- 试图使
attrgetter
之类遵循非数据描述符协议(不可能的 AFAICT,不能在 a__get__
等中进行猴子补丁) - 试图找到一种方法来子类化
attrgetter
给它一个__get__
,但当然,__get__
需要以某种方式委托给 C 层,现在我们回到了我们开始的地方 - (特定于
attrgetter
用例)__slots__
首先使用使成员成为描述符,然后尝试以某种方式从数据的结果描述符转换为跳过绑定的最后一步并将实际值获取为使其可调用的东西的东西所以真正的价值检索被推迟了
我不能发誓我没有错过任何这些选项。任何人有任何解决方案?允许完全骇客;我知道我在这里做病态的事情。理想情况下,它应该是灵活的(让您从 a class
、Python 内置函数(如hex
、len
等)或任何其他未在 Python 层定义的可调用对象中创建行为类似于未绑定方法的东西)。重要的是,它需要附加到类,而不是每个实例(既可以减少每个实例的开销,也可以为 dunder 特殊方法正常工作,这些方法在大多数情况下会绕过实例查找)。