web-dev-qa-db-ja.com

Pythonの配列インデックスによる関数の呼び出し

Python out1、out2、out3など)にたくさんの関数があり、渡した整数に基づいてそれらを呼び出したいと思います。

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

これを行う簡単な方法はありますか?

21
Dirk

tl; dr:out(n)ではなくout1(), out2(), ..., outN()関数を記述し、このハックに悩まされないようにしてください。

この質問が実際に出てくる合理的なシナリオは想像できません。問題のアーキテクチャを再検討してください。これを行うにははるかに良い方法があると思われます(リストにそれらを格納することは、インデックス以外の関数には意味がないことを意味するため、たとえば、私が作成している場合にのみ、これを実行することを望みます動的に生成されたサンクの束で、それらの時間的順序が重要である場合など)。特にこの回答を読んでいる初心者ユーザーは、すべてを処理できるより一般的な関数を作成するか、各関数にさらに識別情報を関連付けるか、クラスの一部として貼り付けることなどを検討してください。

そうは言っても、これはあなたがそれを行う方法です。

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

または

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

これは、次の2つのステップを1つのステップにしたものです。

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

または、上記のOPのように関数 'myFunc'のレジストリがない場合は、globals()を使用できますが、これは非常にハックな形式であり、回避する必要があります(これらの関数をモジュールの名前空間で使用可能にする場合を除く) 、その場合は多分それは大丈夫です...しかし、これはおそらくまれなケースであり、サブモジュールでそれらの関数を定義し、次に_from mysubmodule import *_を定義します。

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

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

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

他に2つのアイデアがあります(回答が受け入れられた後に追加され、最初の2つのコメント):

次のようなデコレータを作成することもできます:

_>>> 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):
    # ???
_
39
ninjagecko

実際、私はまさにこの問題を抱えており、それは非常に現実的です。セルの内容を構成するには、各行にまったく異なる方法が必要なテーブルを表示する必要がありました。私の解決策は、空の値を返すクラスを作成し、それをサブクラス化してさまざまな値のメソッドを実装し、各サブクラスを配列にインスタンス化して、行番号に応じてインスタンスのメソッドを呼び出すことでした。グローバル名前空間汚染は、サブクラスをテーブルジェネレータクラスの内部にすることで制限されます。コードは次のようになります。

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
hamiljf
  def array(ar=[]):
     ar = np.array(ar)
     return ar
0
Josh Anish