【问题标题】:Creating methods at run time in python在python中运行时创建方法
【发布时间】:2016-12-08 22:48:22
【问题描述】:

我对 python 很陌生,我正在尝试编写一个简单的 REST api 调用实现。我的目标是能够在运行时创建类的方法,并能够使用方法名称作为 API 调用的基础。例如 list_virtual_networks 将变成 GET 到http://localhost:8080/virtual-networks 等。我还想练习一些更高级的面向对象技术。这是我的方法:

def _api_call_wrapper(wrapped_function):
    def wrapper_function(*args, **kwargs):
        handler_name = wrapped_function.__name__
        agent_logger.info('Got function name {}'.format(handler_name))
        <do something>
        return res
return wrapper_function

class API(HTTPConnection):
    def __init__(self, host, port):
        <do something>

    def __getattr__(self, name):
    @_api_call_wrapper
    def handler(self, *args, **kwargs):
        self.request('GET', self.last_url)
        return self.getresponse()
    handler.__name__ = name
    setattr(self, name, handler)
    agent_logger.info('Returning method with name {}'.format(self.name))

if __name__ == '__main__':
    api = API(127.0.0.1, 8080)
    api.list_virtual_networks()

这是我在日志中看到的:

2016-12-08 23:05:03,034 - AgentLogger - INFO - 在 0x1073c8d70 处返回名称为函数 wrapper_function 的方法>

2016-12-08 23:05:03,034 - AgentLogger - INFO - 名称为 None 的返回方法

我希望我已经足够清楚地解释我想要实现的目标。有没有办法至少以我正在尝试的方式大致解决它?

【问题讨论】:

  • 你正在尝试一些困难的东西,因为它对 python 很陌生
  • 真正想做什么?您确定动态创建方法对于您正在尝试做的事情是必要的吗?
  • 对于我现在要解决的当前问题,这不是 100% 必要的。当然,我可以手动定义所有 API 调用方法,或者只定义一种通用方法,可以在其输入上获取 URL 和 HTTP 方法的类型并发送 REST 调用。我会说是更“科学”的兴趣驱使我以这种方式实施它。在我看来,它可能是一个非常灵活的实现,我将来也可以重用。

标签: python rest decorator


【解决方案1】:

在编写函数包装器时,一个好用的工具是 Python 的 stdlib 提供的 functools 库中的 wraps 函数:https://docs.python.org/3/library/functools.html#functools.wraps(尤其是你想做的“重命名”事情)

from functools import wraps

def _api_call_wrapper(wrapped_function):
    @wraps(wrapped_function)
    def wrapper_function(*args, **kwargs):
        handler_name = wrapped_function.__name__
        agent_logger.info('Got function name {}'.format(handler_name))
        <do something>
        return res
return wrapper_function

【讨论】:

  • 我可以使用的模块集非常有限,因为该脚本将在我无法控制的服务器上运行,并且我无法在那里安装我选择的模块,有使用已经存在的东西。不过谢谢你的回复,我试试这个。
  • 其实functools库根本不需要安装,因为它存在于Python 2/3的Python stdlib中,所以只要你使用python,你已经这个模块安装;)
  • 谢谢。在我回复之前的评论后不久,我也发现了这一点。
【解决方案2】:

我找到了解决方案。我添加了一个装饰器,用于重命名函数

def _function_rename(new_name):
  def decorator(f):
    f.__name__ = new_name
    return f

return decorator

然后我将这个装饰器应用到处理函数,在 __getattr__ 中定义,除了我已经应用的装饰器:

def __getattr__(self, name):
    @_api_call_wrapper
    @_function_rename(name)
    def handler(*args, **kwargs):
        self.request(*args, **kwargs)
        return self.getresponse()

    return handler

现在,当调用未在类中定义的方法时,会为其分配一个在处理函数中定义的修饰代码。

【讨论】:

    猜你喜欢
    • 2012-06-14
    • 1970-01-01
    • 2017-06-19
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    相关资源
    最近更新 更多