转换内建函数类型方法类型(在Python 3)(Convert builtin function t

2019-07-29 13:02发布

考虑像一个简单的功能

def increment(self):
    self.count += 1

这是通过用Cython运行和编译成的扩展模块。 假设现在我想使这个功能在一个类的方法。 例如:

class Counter:
    def __init__(self):
        self.count = 0

from compiled_extension import increment
Counter.increment = increment

现在,这是行不通的,因为在C级调用约定将被打破。 例如:

>>> c = Counter()
>>> c.increment()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: increment() takes exactly one argument (0 given)

但是在Python 2中,我们可以将功能做转换为不受约束的方法:

Counter.increment = types.MethodType(increment, None, Counter)

我怎样才能做到同样的事情在Python 3?

一个简单的方法是使用超薄包装:

from functools import wraps
def method_wraper(f):
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wraps(f)(wrapper)

Counter.increment = method_wrapper(increment)

有没有更有效的方式来做到这一点?

Answer 1:

第一件事情是正确获取名称:

>>> def increment(obj):
...     obj.count += 1
...
>>> class A(object):
...     def __init__(self):
...         self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>

所以,正确的名称是功能约束方法 。 现在,你可以看看如何绑定一个不受约束的方法 ,你最终可能会念叨描述

一般而言,描述符是用“结合行为”,一个属性的访问已被描述符协议方法重写的对象属性。 这些方法都是__get____set____delete__ 。 如果任何的这些方法为对象定义,它被说成是一个描述符。

您可以轻松地只是用不同的调用转换函数方法__get__

>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>

它就像一个魅力:

>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2

您可以轻松地添加这些新方法约束的对象:

def increment(obj):
    obj.count += 1

def addition(obj, number):
    obj.count += number

class A(object):
    def __init__(self):
        self.count = 0

o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6

或创建自己的描述符 ,将将函数转换为绑定方法

class BoundMethod(object):
    def __init__(self, function):
        self.function = function

    def __get__(self, obj, objtype=None):
        print('Getting', obj, objtype)
        return self.function.__get__(obj, objtype)

class B(object):
    def __init__(self):
        self.count = 0

    inc = BoundMethod(increment)
    add = BoundMethod(addition)


o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5) 
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6

而且你还可以看到,这是很好的有一致的功能 / 绑定的方法原理 :

类字典存储方法作为函数。 在一个类定义,方法是使用高清和lambda,用于创建功能通常的工具编写的。 从正则函数的唯一区别是,第一个参数是保留给对象实例。 通过Python的约定,该实例引用所谓的自我,但可以被称为这个或任何其他变量名。

为了支持方法调用,函数包括__get__()为属性存取期间结合方法的方法。 这意味着,所有的功能都是非数据描述符,其根据返回它们是否是从对象或类调用结合或未结合的方法。

功能变得实例的初始化过程中绑定的方法

>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>


Answer 2:

导入扩展这样的:

import compiled_extension

在你的类你写的:

def increment: return compiled_extension.increment()

这似乎更具可读性和可能更有效。



文章来源: Convert builtin function type to method type (in Python 3)