0

具体的には、別の関数を呼び出す 1 つの関数があるが、2 番目の関数のシグネチャが不明な場合です。

*args と **kwargs をこれに似たものに使用できることは知っていますが、常に機能する方法で完全に正しく理解できないようです。

したがって、たとえば、次のようなものはほとんど機能します。

class Invoker():
  def __init__(self, call):
    self._call = call
  def call(self, *args, **kwargs):
    self._call(*args, **kwargs)

..しかし、いくつかのテストを書くと、次の出力が得られます。

1 -> 2  ('Hello')
1 -> 2  ((3, 'Hello'))
1 -> 2  ('Hello'), ({'left': 'right'})
1 -> 2  ((3,)), ({'value': 'Hello'})
call5() got multiple values for keyword argument 'value'
call5() got multiple values for keyword argument 'value'

このコードから:

# Known argument list: works fine
def call(x, y, value=None):
  print("%d -> %d  (%r)" % (x, y, value))

invoker = Invoker(call)
invoker.call(1, 2, value="Hello")

# Unknown argument list with no kwargs: works fine
def call2(x, y, *args):
  print("%d -> %d  (%r)" % (x, y, args))

invoker = Invoker(call2)
invoker.call(1, 2, 3, "Hello")

# Unknown kwargs with default value: works fine
def call3(x, y, value=None, **kwargs):
  print("%d -> %d  (%r), (%r)" % (x, y, value, kwargs))

invoker = Invoker(call3)
invoker.call(1, 2, value="Hello", left="right")

# Unknown args and kwargs: works fine
def call4(x, y, *args, **kwargs):
  print("%d -> %d  (%r), (%r)" % (x, y, args, kwargs))

invoker = Invoker(call4)
invoker.call(1, 2, 3, value="Hello")

# Default value with unknown args: fails
try:
  def call5(x, y, value=None, *args):
    print("%d -> %d  (%r), (%r)" % (x, y, value, args))

  invoker = Invoker(call5)
  invoker.call(1, 2, 3, value="Hello")
except Exception, e:
  print(e)

# Default value with unknown args and kwargs: fails
try:
  def call6(x, y, value=None, *args, **kwargs):
    print("%d -> %d  (%r), (%r), (%r)" % (x, y, value, args, kwargs))

  invoker = Invoker(call5)
  invoker.call(1, 2, 3, value="Hello", left="right")
except Exception, e:
  print(e)

実行時以外は呼び出されるメソッドのシグネチャが不明な場合、常に機能する別のメソッドを呼び出すメソッドを作成するにはどうすればよいですか?

4

2 に答える 2

5

問題は、引数を動的に渡すことではありません。問題は、その関数に対して無効な引数セットを使用して関数を呼び出そうとしていることです。

たとえば、call5で定義する を見てくださいdef call5(x, y, value=None, *args)。この関数には 3 つの引数があり、そのうちの 1 つにはデフォルトがあり、次に*argsキャッチオールがあります。

(1, 2, 3)次に、3 つの位置引数とキーワード引数を指定して、この関数を呼び出そうとしますvalue="Hello"。これは、この関数の有効な引数セットではありません。これを動的な方法で行おうとしているという事実は、ただのニシンです。文字通り実行しようとしても機能せずcall5(1, 2, 3 value="Hello")call5(1, 2, value="Hello", 3)構文エラーです。この関数は、3 つの位置引数とキーワード指定の「値」引数を受け入れることができません。

任意の関数を呼び出すことができる「呼び出し元」のような関数を定義できますが、位置引数とキーワード引数の一部の組み合わせがその関数に対して有効でない可能性があるという事実は変わりません。これは動的呼び出し構造のアーティファクトではありません。関数がどのように機能するかだけです。関数は、署名に合った引数で呼び出される必要があります。あまりにも多くの引数を渡すと、関数は失敗します。署名に可変引数が含まれている場合、ある程度の余裕はありますが、関数が特定の数の引数を必要とする可能性があるという事実は変わりません。それよりも少ない数を渡すと、関数は失敗します。引数の任意のタプルとディクテーションを渡して、任意の関数で機能させることは期待できません。

または、別の言い方をすれば、インボーカー機構が署名が何であるかを知る必要なく、任意の関数を呼び出す汎用インボーカーを作成できますが、インボーカーを使用して引数を渡す人は誰でも、関数の署名が何であるかを知る必要があります。最終的に呼び出される関数です。

于 2013-06-19T06:45:41.517 に答える