基于列表中的值调用Python中的不同函数

时间:2015-05-18 00:53:13

标签: python list python-2.7

我有一个脚本,它将度量列表作为输入,然后从数据库中提取这些度量以使用它们执行各种操作。

我的问题是不同的客户端获得指标的不同子集,但我不想在每次添加新客户端时编写新的IF块。所以现在,我有一个大的IF块,根据相应的度量是否在列表中调用不同的函数。什么是最优雅或 Pythonic 处理此方法?

设置和功能定义:

clientOne = ['churn','penetration','bounce']
clientTwo = ['engagement','bounce']

def calcChurn(clientId):
    churn = cursor.execute(sql to get churn)
    [...]
    return churn

def calcEngagement(clientId):
    engagement = cursor.execute(sql to get engagement)
    [...]
    return engagement

想象一下类似格式的其他三个函数,因此有一个函数对应于每个唯一度量。现在这里是脚本中的代码块,它包含指标列表:

def scriptName(client, clientId):
    if churn in client:
        churn = calcChurn(clientId)
    if engagement in client:
        engagement = calcEngagement(clientId)
    if penetration in client:
    [...]

3 个答案:

答案 0 :(得分:10)

通常,您要创建名称到函数的映射,并使用它来计算您想要的东西:

client_action_map = {
  'churn': calcChurn,
  'engagement': calcEngagement,
  ...
}

def scriptName(actions, clientId):
    results = {}
    for action in actions:
        results[action] = client_action_map[action](clientId)
    return results

答案 1 :(得分:3)

您可以使用静态方法创建一个类,并使用getattr来获取正确的方法。它与mgilson建议的类似,但你基本上可以免费获得dict:

class Calculators:

    @staticmethod
    def calcChurn():
        print("called calcChurn")

    @staticmethod
    def calcEngagement():
        print("called calcEngagement")

    @staticmethod
    def calcPenetration():
        print("called calcPenetration")

stats = ["churn", "engagement", "penetration", "churn", "churn", "engagement", "undefined"]

def capitalise(str):
    return str[0].upper() + str[1:]

for stat in stats:
    try:
        getattr(Calculators, "calc" + capitalise(stat))()
    except AttributeError as e:
        print("Unknown statistic: " + stat)
  

叫做calcChurn
  叫做calcEngagement
  叫做calcPenetration
  叫calcChurn
  叫calcChurn
  叫做calcEngagement
  未知统计数据:未定义

答案 2 :(得分:0)

将所需的调用封装在对象中也许是有意义的。

如果您的客户端成为对象是有意义的,特别是如果许多客户端调用相同的函数集来获取指标,那么您可以创建一组Client子类,这些子类调用预定义的一组获取指标的功能。

它比映射字典重一点。

''' Stand alone functions for sql commands.
    These definitions however dont really do anything.
'''


def calc_churn(clientId):
    return 'result for calc_churn'


def calc_engagement(clientId):
    return 'result for calc_engagement'


''' Client base object '''


class Client(object):
    ''' Base object allows list of functions
    to be stored in client subclasses'''

    def __init__(self, id):
        self.id = id
        self.metrics = []
        self.args = []

    def add_metrics(self, metrics, *args):
        self.metrics.extend(metrics)
        self.args = args

    def execute_metrics(self):
        return {m.__name__: m(*self.args) for m in self.metrics}


''' Specific sub classes '''


class Client1(Client):

    def __init__(self, id):
        ''' define which methods are called for this class'''

        super(Client1, self).__init__(id)
        self.add_metrics([calc_churn], id)


class Client2(Client):

    def __init__(self, id):
        ''' define which methods are called for this class'''

        super(Client2, self).__init__(id)
        self.add_metrics([calc_churn, calc_engagement], id)


''' create client objects and  '''

c1 = Client1(1)
c2 = Client2(2)

for client in [c1, c2]:
    print client.execute_metrics()

您将从execute_metrics获得的结果是dict将函数名称映射到该客户端的结果。