web-dev-qa-db-ja.com

Pythonに組み込みのアイデンティティ関数がありますか?

私は何もしない関数を指し示したい:

def identity(*args)
    return args

私のユースケースはこのようなものです

try:
    gettext.find(...)
    ...
    _ = gettext.gettext
else:
    _ = identity

もちろん、上記で定義したidentityを使用することもできますが、ビルトインは確かに高速に動作します(そして、自分で導入したバグを回避します)。

明らかに、mapfilterはIDにNoneを使用しますが、これは実装に固有のものです。

>>> _=None
>>> _("hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
129
rds

さらなる調査を行っても何もありません。機能は issue 1673203 で尋ねられました。そして、 から't be

人々が自分で取るに足らないパススルーを書いて、署名と時間コストについて考えることができるようにした方が良い。

したがって、それを行うより良い方法は実際には(ラムダは関数の命名を避けます)です:

_ = lambda *args: args
  • 利点:任意の数のパラメーターを取ります
  • 欠点:結果はパラメーターの箱入りバージョンです

OR

_ = lambda x: x
  • 利点:パラメーターのタイプを変更しません
  • 欠点:位置パラメーターを1つだけ取る
89
rds

https://en.wikipedia.org/wiki/Identity_function で定義されているID関数は、1つの引数を取り、変更せずに返します。

_def identity(x):
    return x
_

署名def identity(*args)が必要だと言ったときに求めているのは、not厳密に恒等関数であり、必要なものです複数の引数。それは問題ありませんが、Python関数は複数の結果を返さないため、これらの引数をすべて1つの戻り値に詰め込む方法を見つける必要があります。

Pythonで「複数の値」を返す通常の方法は、値のタプルを返すことです-技術的には1つの戻り値ですが、複数の値であるかのようにほとんどのコンテキストで使用できます。ここでそれを行うことはあなたが得ることを意味します

_>>> def mv_identity(*args):
...     return args
...
>>> mv_identity(1,2,3)
(1, 2, 3)
>>> # So far, so good. But what happens now with single arguments?
>>> mv_identity(1)
(1,)
_

そして、thatの問題を修正すると、ここでのさまざまな答えが示すように、他の問題がすぐに発生します。

したがって、要約すると、Pythonで定義されている恒等関数はありません。

  1. 正式な定義(単一の引数関数)はそれほど有用ではなく、書くのは簡単です。
  2. 定義を複数の引数に拡張することは一般的には明確に定義されておらず、特定の状況に応じて必要な方法で機能する独自のバージョンを定義する方がはるかに適切です。

正確な場合、

_def dummy_gettext(message):
    return message
_

ほぼ間違いなくあなたが望むものです-同じ呼び出し規約を持ち、引数を変更せずに返す_gettext.gettext_と同じ関数を返します。ここでパフォーマンスが重要な考慮事項である場合、私はかなりショックを受けるでしょう。

22
Paul Moore

あなたのはうまくいきます。パラメーターの数が修正されたら、次のような匿名関数を使用できます。

lambda x: x
18
tback

いいえ、ありません。

identity

  1. lambda * args:argsと同等です
  2. その引数をボックス化します-つまり.

    In [6]: id = lambda *args: args
    
    In [7]: id(3)
    Out[7]: (3,)
    

そのため、lambda arg: arg真の恒等関数が必要な場合。

NB:この例は、組み込みのid関数(おそらく使用することはないでしょう)をシャドウします。

5
Marcin

Pythonには組み込みのID関数はありません。 Haskellのid関数 の模倣は次のようになります。

identity = lambda x, *args: (x,) + args if args else x

使用例:

identity(1)
1
identity(1,2)
(1, 2)

identityは与えられた引数を返すこと以外は何もしないので、ネイティブ実装よりも遅いとは思いません。ネイティブ関数の呼び出しが保存されるため、さらに高速になる可能性があります。

2

単一引数関数のスタブ

_gettext.gettext_ (OPの使用例の例)は、単一の引数messageを受け入れます。スタブが必要な場合、messagedef identity(*args): return args)の代わりに_[message]_を返す理由はありません。したがって、両方

__ = lambda message: message

def _(message):
    return message
_

完全にフィットします。

...しかし、ビルトインは確かに高速に動作します(そして、私自身によって導入されたバグを避けます)。

このような些細なケースのバグはほとんど関係ありません。事前定義型の引数、たとえばstrの場合、str()自体をアイデンティティ関数として使用できます( string interning によりオブジェクトのアイデンティティも保持されるため、id以下に注意してください)、そのパフォーマンスをラムダソリューションと比較します。

_$ python3 -m timeit -s "f = lambda m: m" "f('foo')"
10000000 loops, best of 3: 0.0852 usec per loop
$ python3 -m timeit "str('foo')"
10000000 loops, best of 3: 0.107 usec per loop
_

マイクロ最適化が可能です。たとえば、次の Cython コード:

test.pyx

_cpdef str f(str message):
    return message
_

次に:

_$ pip install runcython3
$ makecython3 test.pyx
$ python3 -m timeit -s "from test import f" "f('foo')"
10000000 loops, best of 3: 0.0317 usec per loop
_

ビルトインオブジェクトID関数

アイデンティティ関数と、オブジェクトの「アイデンティティ」を返す組み込み関数 id と混同しないでください(_==_演算子と比較して、そのオブジェクトの値ではなく、その特定のオブジェクトの一意の識別子を意味します)、CPythonのメモリアドレス。

1
saaj