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

Consider a simple function like

def increment(self):

self.count += 1

which is run through Cython and compiled into an extension module. Suppose now I'd like to make this function a method on a class. For example:

class Counter:

def __init__(self):

self.count = 0

from compiled_extension import increment

Counter.increment = increment

Now this will not work, as the calling convention at the C level will be broken. For example:

>>> c = Counter()

>>> c.increment()

Traceback (most recent call last):

File "", line 1, in

TypeError: increment() takes exactly one argument (0 given)

But in Python 2, we can convert the function to an unbound method by doing:

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

How can I accomplish this same thing in Python 3?

One simple way is to use a slim wrapper:

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)

Is there a more efficient way to do it?

解决方案

First thing is getting the names correctly:

>>> def increment(obj):

... obj.count += 1

...

>>> class A(object):

... def __init__(self):

... self.count = 0

...

>>> o = A()

>>> o.__init__

>

>>> increment

So proper names are functions and bound methods. Now you can look for how to Bind an Unbound Method and you will probably end up reading about descriptors:

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.

You can easily transform function to method by just using different invocation of __get__

>>> increment.__get__(None, type(None))

>>> increment.__get__(o, type(o))

>

And it works like a charm:

>>> o = A()

>>> increment.__get__(None, type(None))(o)

>>> o.count

1

>>> increment.__get__(o, type(o))()

>>> o.count

2

You can easily add these newly bounded methods to objects:

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

Or create your own descriptor that will will convert function to bound method:

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>

print(o.count) # 1

o.add(5)

# Getting <__main__.b object at>

print(o.count) # 6

And you also can see that this is nicely consistent with function/bound method principles:

Class dictionaries store methods as functions. In a class definition, methods are written using def and lambda, the usual tools for creating functions. The only difference from regular functions is that the first argument is reserved for the object instance. By Python convention, the instance reference is called self but may be called this or any other variable name.

To support method calls, functions include the __get__() method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound or unbound methods depending whether they are invoked from an object or a class.

And functions becomes bound method during instance initialization:

>>> B.add

# Getting None

>>> o.add

# Getting <__main__.b object at>

>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值