在Python中通过数组索引调用函数

时间:2011-04-18 19:04:20

标签: python delegates

我在Python out1,out2,out3等中有很多函数,并希望根据我传入的整数来调用它们。

def arryofPointersToFns (value):
     #call outn where n = value

有一种简单的方法吗?

4 个答案:

答案 0 :(得分:31)

tl; dr:写一个out(n)函数而不是out1(), out2(), ..., outN(),不要理会这个hack。

我无法想象这个问题会在实践中出现的合理情况。请重新考虑问题的架构;有可能有一个更好的方法来做到这一点(因为将它们存储在列表中意味着除了索引之外的函数没有任何意义;例如,我只能想象如果你创建的话你想要这样做一堆动态生成的thunk,它们的时序有问题,或类似的东西)。特别是你正在阅读这个答案的任何新手用户,考虑制作一个更通用的功能,可以处理所有事情,或者将每个功能与一些更多的识别信息相关联,或者将其作为一个类的一部分,等等。

那就是说,你就是这样做的。

myFuncs = [f0,f1,f2]
myFuncs[2](...) #calls f2

myFuncs = {'alice':f1, 'bob':f2}
myFuncs['alice'](...) #calls f1

这只是一步中的以下两个步骤:

myFuncs = [f0,f1,f2]
f = myFuncs[i]
f(...) #calls fi

或者如果你没有上面提到的OP函数'myFunc'的注册表,你可以使用globals(),虽然它是非常hack形式并且要避免(除非你希望这些函数可用于你的模块命名空间,在这种情况下可能很好......但这种情况可能很少,你可能宁愿在子模块中定义这些函数然后from mysubmodule import *它们,这反过来又略微不赞成):

def fN(n):
    return globals()['f'+str(n)]

def f2():
    print("2 was called!")

fN(2)(...) #calls f2

这里有另外两个想法(在回答被接受后添加,前两个评论):

您还可以创建这样的装饰器:

>>> def makeRegistrar():
...     registry = {}
...     def registrar(func):
...         registry[func.__name__] = func
...         return func  # normally a decorator returns a wrapped function, 
...                      # but here we return func unmodified, after registering it
...     registrar.all = registry
...     return registrar

并像这样使用它:

>>> reg = makeRegistrar()
>>> @reg
... def f1(a):
...  return a+1
... 
>>> @reg
... def f2(a,b):
...  return a+b
... 
>>> reg.all
{'f1': <function f1 at 0x7fc24c381958>, 'f2': <function f2 at 0x7fc24c3819e0>}

然后你可以调用reg.all ['f1']。您可以调整reg装饰器以跟踪索引并执行以下操作:

registry = []
index = int(re.regextofindthenumber(func.__name__))
if not index==len(registry):
    raise Exception('Expected def f{} but got def f{}')
else:
    registry[index] = func

或者,为避免globals(),您可以定义一个类:

class Funcs(object):
    def f1():
        ...
    def f2():
        ...
    def num(n):
        [code goes here]

如果您的功能数量很少,您可以使用['f1','f2','f3'][i]

当然没有进一步的信息,所有这些建议都只是忽略了真正的问题:这种情况永远不会出现,并且可能是严重的架构缺陷的标志,当你可能宁愿拥有某些东西时(使用你的例如:

# a possibly-better world
def out(n):
    # output to N, whatever that means

而不是

# what you have now
def out1():
    # output to 1
def out2():
    # output to 2
def outN(n):
    # ???

答案 1 :(得分:1)

实际上,我确实存在这个问题并且非常现实:我需要显示一个表,其中每一行都需要一种完全不同的方法来组成单元格内容。我的解决方案是创建一个返回空值的类,然后将其子类化并实现不同的值方法,然后将每个子类实例化为一个数组,然后根据行号调用实例的方法。通过使子类成为表生成器类的内部来限制全局命名空间的压缩。代码看起来像这样:

class Table(object):
    class Row(object):
        def name(self):
            return self.__class__.__name__
    class Row1(Row):
        def value(self):
            return 'A'
    class Row2(Row):
        def value(self):
            return 'B'
    class Row3(Row):
        def value(self):
            return 'C'
    def __init__(self):
        self._rows = []
        for row in self.Row.__subclasses__():
            self._row.append(row())
    def number_of_rows(self):
        return len(self._rows)
    def value(self,rownumber):
        return self._rows[rownumber].value()

显然,在一个现实的例子中,每个子类值方法都会有很大不同。包含'name'方法以指示如何使用内部类的任意名称提供行标题。该方法还具有可以容易地实现合适的“尺寸”方法的优点。这些行将以与它们在代码中出现的顺序相同的顺序出现在输出中,但这可能是一个优势。

注意:上面没有经过测试的代码,只是我实际编写的代码的一个例子来说明一种方法。

答案 2 :(得分:1)

一个人可以通过字典访问方法:

def one1():
    print("Method one1 called")
def one2():
    print("Method one2 called")
def one3():
    print("Method one3 called")
methodDictionary = {1: one1, 2:one2, 3: one3}
method1 = methodDictionary[1]
method1()
method2 = methodDictionary[2]
method2()
method3 = methodDictionary[3]
method3()

答案 3 :(得分:0)

  def array(ar=[]):
     ar = np.array(ar)
     return ar