首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将内置函数类型转换为方法类型(在Python 3中)

将内置函数类型转换为方法类型(在Python 3中)
EN

Stack Overflow用户
提问于 2012-05-24 09:05:57
回答 2查看 2.9K关注 0票数 18

考虑一个简单的函数,比如

代码语言:javascript
复制
def increment(self):
    self.count += 1

它通过Cython运行并编译成扩展模块。假设现在我想让这个函数成为一个类上的方法。例如:

代码语言:javascript
复制
class Counter:
    def __init__(self):
        self.count = 0

from compiled_extension import increment
Counter.increment = increment

现在,这将不起作用,因为C级别的调用约定将被打破。例如:

代码语言:javascript
复制
>>> 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中,我们可以通过执行以下操作将函数转换为未绑定的方法:

代码语言:javascript
复制
Counter.increment = types.MethodType(increment, None, Counter)

我如何在Python3中完成同样的事情?

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

代码语言:javascript
复制
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)

有没有更有效的方法呢?

EN

回答 2

Stack Overflow用户

发布于 2014-12-17 18:44:14

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

代码语言:javascript
复制
>>> 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__调用,就可以轻松地将函数转换为方法

代码语言:javascript
复制
>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>

它的作用就像一个护身符:

代码语言:javascript
复制
>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2

您可以轻松地将这些新绑定的方法添加到对象中:

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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

您还可以看到,这与/ principles非常一致

类字典将方法存储为函数。在类定义中,方法是使用def和lambda编写的,这是创建函数的常用工具。与常规函数的唯一区别是,第一个参数是为对象实例保留的。根据Python约定,实例引用称为self,但也可以称为this或任何其他变量名。

为了支持方法调用,函数包括用于在属性访问期间绑定方法的__get__()方法。这意味着所有函数都是非数据描述符,它们返回绑定或未绑定的方法,这取决于它们是从对象还是从类中调用的。

在实例初始化过程中,函数会成为绑定方法:

代码语言:javascript
复制
>>> 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>>
票数 4
EN

Stack Overflow用户

发布于 2014-07-18 04:47:25

像这样导入扩展:

代码语言:javascript
复制
import compiled_extension

在你的课堂上,你可以这样写:

代码语言:javascript
复制
def increment: return compiled_extension.increment()

这看起来更具可读性,也可能更高效。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10729909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档