0

我有这样的课程:

class Tool(object):
    def do_async(*args):
        pass

我想自动生成使用异步方法的非异步方法:

class Tool(object):
    def do_async(*args):
        pass
    def do(*args):
        result = self.do_async(*args)
        return magical_parser(result)

这变得特别棘手,因为每个方法都需要作为对象和类方法都可以访问这通常通过这个神奇的装饰器来实现:

class class_or_instance(object):
    def __init__(self, fn):
        self.fn = fn

    def __get__(self, obj, cls):
        if obj is not None:
            f = lambda *args, **kwds: self.fn(obj, *args, **kwds)
        else:
            f = lambda *args, **kwds: self.fn(cls, *args, **kwds)
        functools.update_wrapper(f, self.fn)
        return f

如何制作这些方法,并确保它们可以作为类和对象方法访问?这似乎可以用装饰器完成,但我不确定如何。

(注意,我事先不知道任何方法名称,但我知道所有需要新朋友的方法都有_async名称末尾都有。)

我想我已经很接近了,但是这种方法没有将函数适当地设置为类/对象方法:

def process_asyncs(cls):

    methods = cls.__dict__.keys()
    for k in methods:
        methodname = k.replace("_async","")
        if 'async' in k and methodname not in methods:

            @class_or_instance
            def method(self, verbose=False, *args, **kwargs):
                response = self.__dict__[k](*args,**kwargs)
                result = self._parse_result(response, verbose=verbose)
                return result

            method.__docstr__ = ("Returns a table object.\n" +
                    cls.__dict__[k].__docstr__)

            setattr(cls,methodname,MethodType(method, None, cls))
4

1 回答 1

3

不要从__dict__;获取其他方法 改为使用getattr(),以便描述符协议可以启动。

并且不要将method函数包装在MethodType()对象中,因为这会中和您放置的描述符method

您需要绑定 k到您生成的函数;闭包k会随着循环而改变:

@class_or_instance
def method(self, verbose=False, _async_method_name=k, *args, **kwargs):
    response = getattr(self, _async_method_name)(*args,**kwargs)
    result = self._parse_result(response, verbose=verbose)
    return result

cls.__dict__[methodname] = method

最后别忘了返回cls;我已将其更改为使用单独的函数来创建新范围以提供新的本地名称_async_method_name而不是关键字参数;*args这避免了使用显式关键字参数的困难:

def process_asyncs(cls):

    def create_method(async_method):

        @class_or_instance
        def newmethod(self, *args, **kwargs):
            if 'verbose' in kwargs:
                verbose = kwargs.pop('verbose')
            else:
                verbose = False
            response = async_method(*args,**kwargs)
            result = self._parse_result(response, verbose=verbose)
            return result
        return newmethod

    methods = cls.__dict__.keys()
    for k in methods:
        methodname = k.replace("_async","")
        if 'async' in k and methodname not in methods:
            async_method = getattr(cls, k)
            setattr(cls, methodname, create_method(async_method))

    return cls
于 2013-08-04T22:48:13.513 回答