在Python 3+中以编程方式向类添加方法

问题描述 投票:0回答:1

我有一个类,提供API的简单接口。我想为每个路由在该类上定义一个方法。

由于大多数路由都是相同的,因此很多功能可以分解为更通用的功能,许多路由只是该功能的部分应用版本

class MyAPIWrapper:

    def _get_results(self, route, **params):
        # Do the important stuff here
        results = ...
        return results

    def get_customers(self):
        return self._get_results(self, 'customers')

    def get_transactions(self):
        return self._get_results(self, 'transactions')

    # etc, etc, etc

但是,很明显,这仍然导致类定义中有相当数量的样板。

另一种方法是添加一种新方法,以编程方式添加每个路径的方法:

import functools

class MyAPIWrapper:

    def __init__(self):
        self._init_route_methods()

    def _get_results(self, route, **params):
        # Do the important stuff here
        results = ...
        return results

    def _init_route_methods(self):
        for route in ['customers', 'transactions', ...]:
            route_fn = functools.partial(self. _get_results, route)
            setattr(self, f'get_{route}', route_fn)

这样做的好处是可以减少样板量,并且可以轻松添加/删除路径。然而,在初始化时添加方法对我来说感觉有些不优雅。

是否有更好和/或更惯用的方法来做到这一点?

python python-3.x oop
1个回答
2
投票

您可能会惊讶于这会解决问题:

class MyAPIWrapper:
    def _get_results(self, route, **params):
        # Do the important stuff here
        return route

    for route in ['customers', 'transactions']:
        exec("""
    def get_{0}(self):
        return self._get_results('{0}')
    """.strip().format(route))
MyAPIWrapper().get_customers()    # return customers
MyAPIWrapper().get_transactions() # return transactions

优点

  • 良好的可读性
  • 最小的代码更改

缺点

请注意,execsetattr(MyAPIWrapper,'get_%s'%route, ...)有一点开销,这只会影响你在循环中创建数百万种方法。

如果要对许多不同的APIWrapper类执行相同的操作,请考虑使用类decorator

© www.soinside.com 2019 - 2024. All rights reserved.