Вызов функций по индексу массива в Python - PullRequest
16 голосов
/ 18 апреля 2011

У меня есть несколько функций в Python out1, out2, out3 и т. Д., И я хотел бы вызывать их на основе целого числа, которое я передаю.

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

Есть ли простой способ сделать это?

Ответы [ 3 ]

31 голосов
/ 18 апреля 2011

tl; dr: написать функцию out(n) вместо out1(), out2(), ..., outN() и не беспокоиться об этом хаке.

Я не могу представить разумный сценарий, когда этот вопрос возникнет на практике. Пожалуйста, пересмотрите архитектуру проблемы; вероятно, есть гораздо лучший способ сделать это (поскольку их хранение в списке подразумевает, что в функциях нет ничего значащего, кроме индекса; например, я могу только представить, что вы захотите сделать это, если вы создаете группа динамически генерируемых thunks, где их временное упорядочение имеет значение, или что-то подобное). Особенно для начинающих пользователей, которые читают этот ответ, подумайте над созданием более общей функции, которая может обрабатывать все, или связыванием с каждой функцией более идентифицирующей информации или прикреплением ее как части класса и т. Д.

Тем не менее, вот как ты это сделаешь.

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

или если у вас нет реестра функций 'myFunc', подобного описанному выше OP, вы можете использовать globals (), хотя это чрезвычайно хакерская форма, и ее следует избегать (если вы не хотите, чтобы эти функции были доступны в пространство имен вашего модуля, в этом случае, может быть, это нормально ... но это, вероятно, редко, и вы, вероятно, предпочтительнее определить эти функции в подмодуле, чем 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 голос
/ 03 мая 2018

На самом деле, у меня есть именно эта проблема, и она вполне реалистична: мне нужно было отобразить таблицу, где для каждой строки требуется совершенно другой метод составления содержимого ячейки. Мое решение состояло в том, чтобы создать класс, который возвращает пустое значение, затем создать его подкласс и реализовать различные методы значения, затем создать экземпляр каждого подкласса в массиве, а затем вызвать метод экземпляра в зависимости от номера строки. Глобальное распространение пространства имен ограничено созданием подклассов внутри класса генератора таблиц. Код выглядит примерно так:

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' включен, чтобы указать, как обеспечить заголовок строки, если это необходимо, используя произвольное имя внутреннего класса. Этот подход также имеет то преимущество, что можно легко реализовать подходящий метод «размера». Строки будут отображаться в выходных данных в том же порядке, в котором они появляются в коде, но это может быть преимуществом.

Осторожно: вышеприведенный код не является проверенным кодом, это лишь точный пример моего фактического кода, изложенного для иллюстрации подхода.

0 голосов
/ 12 октября 2017
  def array(ar=[]):
     ar = np.array(ar)
     return ar
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...