Python 将方法添加到由其他方法生成的类中
我有这样的课程:Python 将方法添加到由其他方法生成的类中,python,Python,我有这样的课程: 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 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
如何创建这些方法,并确保它们可以作为类和对象方法访问?这似乎是装饰师可以做的事情,但我不确定如何做
(请注意,我事先不知道任何方法名称,但我知道所有需要新伙伴的方法在名称末尾都有\u 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))
不要从
目录中获取其他方法;改用getattr()
,这样描述符协议就可以生效了
并且不要将方法
函数包装在MethodType()
对象中,因为这样会抵消您在方法
上放置的描述符
您需要将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
;我改变了这一点,使用一个单独的函数来创建一个新的作用域,以提供一个新的本地名称\u async\u method\u 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
不要从目录中获取其他方法;改用getattr()
,这样描述符协议就可以生效了
并且不要将方法
函数包装在MethodType()
对象中,因为这样会抵消您在方法
上放置的描述符
您需要将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
;我改变了这一点,使用一个单独的函数来创建一个新的作用域,以提供一个新的本地名称\u async\u method\u 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
我试过了,但出现了错误:TypeError:“dictproxy”对象不支持项分配
。我的类有\uuuu元类=abc.ABCMeta
;我真的不知道这是否有必要或与此相关。您在问题中发布的解决方案将受到以下事实的影响:async\u方法
是一个循环中的闭包;所有生成的方法都将指向一个异步方法。有关代码中的async\u方法
名称的错误,以及我为什么将k
绑定到解决方案中的关键字参数,请参阅,以获得更全面的解释。是的,通过创建新范围;使用一个单独的函数,在调用时返回newmethod()
。请参阅我先前评论中的链接问题。是的,这是我最初的答案,但您的编辑缓存了该方法。:-)后期查找也允许您查找实例属性,是的。我已尝试过,但出现错误:TypeError:“dictproxy”对象不支持项分配
。我的类有\uuuu元类=abc.ABCMeta
;我真的不知道这是否有必要或与此相关。您在问题中发布的解决方案将受到以下事实的影响:async\u方法
是一个循环中的闭包;所有生成的方法都将指向一个异步方法。有关代码中的async\u方法
名称的错误,以及我为什么将k
绑定到解决方案中的关键字参数,请参阅,以获得更全面的解释。是的,通过创建新范围;使用一个单独的函数,在调用时返回newmethod()
。请参阅我先前评论中的链接问题。是的,这是我最初的答案,但您的编辑缓存了该方法。:-)后期查找也允许您查找实例属性,是的。作为实例或类方法调用这些方法的语义是什么?当被称为实例方法时,他们是否会将实例用于任何事情?这听起来像是模块级函数的工作,或者如果您真的非常确定这些东西需要是方法,那么可能是staticmethod
。是的,通常这些只是模块级函数,但在某些情况下需要实例。基本上,这是针对一套web查询工具的,通常您可以只使用classmethod,但有时您需要先使用对象登录到服务。也许有更好的方法,但这种方法迄今为止效果良好。(正在进行的工作:astroquery.readthedocs.org)作为实例或类方法调用这些方法的语义是什么?当被称为实例方法时,他们是否会将实例用于任何事情?这听起来像是模块级函数的工作,或者如果您真的非常确定这些东西需要是方法,那么可能是staticmethod
。是的,通常这些只是模块级函数,但在某些情况下需要实例。基本上,这是针对一套web查询工具的,通常您可以只使用classmethod,但有时您需要先使用对象登录到服务。也许有更好的方法,但这种方法迄今为止效果良好。(正在进行的工作:astroquery.readthedocs.org)