English 中文(简体)
将内置函数类型转换为方法类型( Python 3)
原标题:Convert builtin function type to method type (in Python 3)

将简单的函数当做

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 中,我如何能完成同样的事情? < strong>

一个简单的方法就是使用一个微薄的包装纸:

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)

是否有更有效的办法做到这一点?

问题回答

第一件事就是把名字正确化:

>>> 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>

正确的名称是 < 强力 > 函数 < / 强力 > 和 < 强力 > 受约束的方法 < / 强力 > 。 现在你可以寻找如何 < a href=" https:// stackoverflow.com/ a/ 10154/05/ 1149736" @ em > Bind 一种未受约束的方法 , 你可能会最后读到 < a href=" https://docs. python. org/3/howto/ descripor. html" rel=" nofollown noreferrer" @em> descritors :

In general, a descriptor is an object attribute with "binding behavior", one whose attribute access has been overridden by methods in the descriptor protocol. Those methods are __get__, __set__, and __delete__. If any of those methods are defined for an object, it is said to be a descriptor.

您可以使用不同的调用

>>> 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

或者创建您自己的 < em> 描述符 < / em >, 将 < em> 函数 < / em > 转换为 < em > 受约束方法 < / em > :

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

您也可以看到,这与“https://docs.python.org/3/howto/descriptionor.html#formations-and-methods” rel=“不跟随 noreferrer"_em > follow / bound 方法 原则 相当一致:

分类词典存储方法作为函数。 在分类定义中, 方法是使用用于创建函数的常用工具 def 和 lambda 来写入的。 与常规函数的唯一区别是, 第一个参数是保留给对象实例。 根据 Python Convention, 例引用被称为自我, 但可以称为此或其它变量名称 。

为了支持方法调用, 函数包括 属性存取期间绑定方法的 方法。 这意味着所有函数都是非数据描述符, 返回约束或非约束方法, 取决于从对象还是从类别中引用的方法 。

测试初始化时 功能 变成 受约束的方法 :

>>> 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>>

导入像这样的扩展名 :

import compiled_extension

在班上写道:

def increment: return compiled_extension.increment()

这似乎更易读,可能更有效率。





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签