Python:如何从__getattr__动态获取kwargs

时间:2017-11-01 11:56:31

标签: python api dynamic call getattr

上下文:我正在尝试动态地为存储产品构建一个简单的(只读)python API客户端。

情况: api服务器有这样的端点:

  • [GET] / monitor / host?nodeId = xxx [& region = xxx]
  • [GET] / monitor / nodelist?[region = xxx]
  • [GET] / system / version
  • [GET] /用法

我的想法是为每个端点创建类(监视器,系统,用法等),然后获取“子端点”(粗体显示:/ monitor / host 或/ monitor / nodelist 等)动态...然后,我仍然需要获取所有网址的参数(这些参数始终是可选的,只能是: nodeId 和/或区域等)...我的用法如下:

client = WhateverStorageApi()
client.monitor.host(hostId='node01', region='eu-west-1') 
# the above would generate a str: /monitor/host?nodeId=node01&region=eu-west-1

我的问题是:__ getattr__不知道任何** kwargs,并且__ call__仅适用于每当我打电话给一个班级时,这就引出了一个问题:是否还有其他众所周知的方法来实现这一目标?或者我的使用想法完全没有意义?例如,我想出了:

class Monitor(object):

    base_url = 'monitor'

    def __getattr__(self, endpoint, **kwargs):

        base_call = '/{base_url}/{endpoint}'.format(
            base_url=Monitor.base_url,
            endpoint=endpoint
        )

        if 'nodeId' in kwargs.keys():
            base_call += '?nodeId={node_id}'.format(
                node_id=kwargs['nodeId']
            )

        if 'region' in kwargs.keys():
            base_call += '?region={region}'.format(
                region=kwargs['region']
            )

        # do something with base_call

(我知道......它根本不起作用)

1 个答案:

答案 0 :(得分:0)

我找到了解决方案:

class Monitor(object):

    base_url = 'monitor'

    def __getattr__(self, endpoint):

        def handler(**kwargs):
            return self._inner_getattr(endpoint, **kwargs)
        return handler

    @staticmethod
    def _inner_getattr(endpoint, **kwargs):

        base_call = '/{base_url}/{endpoint}'.format(
            base_url=Monitor.base_url,
            endpoint=endpoint
        )

        if 'nodeId' in kwargs.keys():
            base_call += '?nodeId={node_id}'.format(
                node_id=kwargs['nodeId']
            )

        if 'region' in kwargs.keys():
            base_call += '?region={region}'.format(
                region=kwargs['region']
            )

        return base_call


a = Monitor()
print a.node(nodeId="bla", region="blabla")

输出:

/monitor/node?nodeId=bla?region=blabla