web-dev-qa-db-ja.com

nargout in Python

Python MATLABでnargoutに相当するものはありますか?戻りパラメーターの数を柔軟に保ちたい場合、nargoutは非常に優れたアプローチだと思います。出力パラメーターの数を調べる方法はありますか?次の疑似Pythonコードのようなもの:

_def var_returns_func(a):
  """
  a is a 1D numpy array
  """
  if nargout==1: return a.sum()
  Elif nargout==2: return a.sum(),a.std()
_

したがって、この関数をmean = var_returns_func(someNumPyarray)として呼び出すと、単一の値が返されるはずです。しかし、それをmean,std = var_returns_func(someNumPyarray)と呼ぶと、2つの値を返すはずです。

これを行うPythonの方法はありますか?それともハッキーな方法ですか?

21
Nik

関数は戻り値で何が行われるのかわからないため、必要な数を知ることができません。できることは、関数の引数としてnargoutを渡し、それを使用して何を返すかを決定することです。

_def f(a, nargout=1):
    if nargout == 1:
        return "one value"
    Elif nargout == 2:
        return "two", "values"
    else:
        raise ValueError, "Invalid nargout!"
_

これは、Python哲学としての「明示的は暗黙的よりも優れている」の例です。2つの引数を出したい場合は、2つの引数を出したいことを明示的に言う必要があります。見た目に基づいて暗黙的に決定する将来的には、結果で何が行われるかを確認することはPythonでは推奨されていません。a = f(x)およびwantを実行して、で2要素のタプルを取得することは完全に可能です。

あなたのような例では、もっと良い方法がたくさんあります。 1つは、mean, std = a.mean(), a.std()、より一般的にはx, y = someFunc(a), otherFunc(a)を実行することです。この特定の値の組み合わせが一般的に必要であり、重複させたくない両方の操作で共有される高価な計算がある場合は、両方を明確に返す3番目の関数を作成し、x, y = funcThatReturnsTwoThings(a)を実行します。これらはすべて、異なることを行う場合に関数を分離しておく明示的な方法です。

19
BrenBarn

MATLABでnargoutについて話すことができません。それがわからないため、正しく使用する方法が想像できません。ただし、ビューをPython関数(またはメソッド)が実際に行うこと)に変更することもできます。

実際には、Pythonは常に正確に1つの値を返します。または、Noneであるか、特定の型の単一の値であるか、Tuple型の単一のオブジェクトです。

returnコマンドがない場合、関数本体が終了すると、関数はNoneを返します。これは、本文の最後に引数なしでreturnを明示的に記述した場合、または本文の最後に_return None_を記述した場合と同じです。

引数なしで_return None_(Noneは変数に格納できます)またはreturnを使用する場合、Noneは呼び出し元に返されます。

_return single_の場合、singleオブジェクトが呼び出し元に返されます。

_return v1, v2, v3_の場合、実際にはタプル_(v1, v2, v3)_を返します。括弧を書く必要がないのは単なる構文糖衣です。

この場合のresult1, result2, result3 = f()は、単なる別の構文糖衣です。 f()はタプルを返し、その要素は指定された変数に自動的に抽出されます。あなたは実際に:

_result1, result2, result3 = (v1, v2, v3)
_

または

_t = f()                           # where t is the (v1, v2, v3)
result1, result2, result3 = t
_

実際、Pythonでは、他の言語では通常のように出力引数を定義できません。引数オブジェクトのアドレスを渡しており、渡されたオブジェクトを変更できるかどうかを考えると、変更することはできますが、たとえば、最初にNone値を持っていた渡された引数に新しい結果を取得することはできません。の出力引数を介してPython変数を割り当てることはできません。関数-Pythonにはそのようなメカニズムはありません。

関数内から新しく作成された値(オブジェクト)を返す唯一の自然で直接的な方法は、returnコマンドを使用することです。ただし、Python関数は、返される引数の数を制限しません(まあ、タプルの場合は後で要素に分割できる単一の引数です)。

実際に返されたものを呼び出し元のコードでテストする場合は、次の値が返された場合に特別なことを行う独自の関数を作成できます:Nonesingle、のタプルある程度の長さ(len(t)を使用して、返されたタプルtの要素数を取得できます)。関数は、singleのタイプまたは各タプル要素のタイプをテストし、それに応じて機能することもできます。

9
pepr

Matlabでは、出力引数の数は実際には関数への入力の1つです。これはPythonの場合には当てはまらないため、これを異なる方法で反映するように関数のインターフェースを設定しました。

たとえば、upper()を文字列のグループに適用する関数を次に示します。ユーザーは、入力の数が出力の数と等しいことを期待できます。構文もMatlabのものと非常に似ています。

>>> def var_returns_f(*args):
...     return [str.upper() for str in args]
... 
>>> 
>>> a, b = var_returns_f('one', 'two')
>>> 
>>> a
'ONE'
>>> b
'TWO'
3
Leo

私がしがちなのは、関数がすべてを(タプルの要素として)返すようにしてから、必要なものだけを解凍することです。

def my_func():
    # do stuff...
    return mean, stddev, otherstat, a, b

mu, sig, _, a, _ = myfunc()

ここではすべてを返しますが、呼び出しスコープで使用する変数に1番目の2番目と4番目の変数のみを割り当てます。 _変数は、私が望まない/必要としない変数のプレースホルダーとして機能する使い捨てです。

3
RBF06

私は奇妙な考えを持っています...

def nargout():
   import traceback
   callInfo = traceback.extract_stack()
   callLine = str(callInfo[-3].line)
   split_equal = callLine.split('=')
   split_comma = split_equal[0].split(',')
   return len(split_comma)

def fun():
   this = nargout()
   if this == 1:
       return 3
   else:
       return 3, 4

a = fun()
a, b = fun()

私は今Matlabが本当に恋しいです:D


改善点:

def nargout(*args):
   import traceback
   callInfo = traceback.extract_stack()
   callLine = str(callInfo[-3].line)
   split_equal = callLine.split('=')
   split_comma = split_equal[0].split(',')
   num = len(split_comma)
   return args[0:num] if num > 1 else args[0]

def fun(nparray):
   return nargout(np.mean(nparray), np.std(nparray))

arr = np.array([3, 4, 5])
mean = fun(arr)
mean, std = fun(arr)
2
yiping jiao