Есть ли встроенная функция идентичности в Python? - PullRequest
128 голосов
/ 05 января 2012

Я бы хотел указать на функцию, которая ничего не делает:

def identity(*args)
    return args

Мой вариант использования примерно такой

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

Конечно, я мог бы использовать identity, определенный выше, но встроенное было бы, конечно, работать быстрее (и избежать ошибок, связанных с моими собственными).

Очевидно, map и filter используют None для идентификации, но это специфично для их реализаций.

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

Ответы [ 7 ]

88 голосов
/ 05 января 2012

Проводя еще какое-то исследование, ничего нет, в выпуске 1673203 была запрошена функция, а из Рэймонд Хеттингер сказал, что не будет :

Лучше позволить людям писать свои собственные тривиальные переходы и подумайте о стоимости подписи и времени.

Так что на самом деле лучший способ сделать это (лямбда-выражения избегают называть функцию):

_ = lambda *args: args
  • преимущество: принимает любое количество параметров
  • недостаток: в результате получается коробочная версия параметров

OR

_ = lambda x: x
  • преимущество: не меняет тип параметра
  • недостаток: принимает ровно 1 позиционный параметр
20 голосов
/ 07 декабря 2017

Идентификационная функция, как определено в https://en.wikipedia.org/wiki/Identity_function,, принимает один аргумент и возвращает его без изменений:

def identity(x):
    return x

То, что вы запрашиваете, когда говорите, что хотите, чтобы подпись def identity(*args) была , а не , была строго тождественной функцией, поскольку вы хотите, чтобы она принимала несколько аргументов. Это нормально, но затем вы сталкиваетесь с проблемой, так как функции Python не возвращают несколько результатов, поэтому вам нужно найти способ объединить все эти аргументы в одно возвращаемое значение.

Обычный способ возврата «множественных значений» в Python - это возврат кортежа значений - технически это одно возвращаемое значение, но его можно использовать в большинстве контекстов, как если бы это были множественные значения. Но, делая это здесь, вы получаете

>>> 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,)

И исправление этой проблемы быстро приводит к другим проблемам, как показали различные ответы здесь.

Итак, в итоге, в Python не определена функция идентификации, потому что:

  1. Формальное определение (функция с одним аргументом) не так уж полезно, и написать его тривиально.
  2. Распространение определения на несколько аргументов в целом не является четко определенным, и вам гораздо лучше определить свою собственную версию, которая работает так, как вам нужно для вашей конкретной ситуации.

Для вашего точного случая,

def dummy_gettext(message):
    return message

почти наверняка то, что вы хотите - функция, которая имеет такое же соглашение о вызовах и возвращает как gettext.gettext, которая возвращает свой аргумент без изменений и имеет четкое имя для описания того, что она делает и где она предназначена для использования. Я был бы очень шокирован, если бы производительность была решающим фактором здесь.

18 голосов
/ 05 января 2012

у тебя будет нормально работать.Когда число параметров является фиксированным, вы можете использовать анонимную функцию, например:

lambda x: x
5 голосов
/ 05 января 2012

Нет, нет.

Обратите внимание, что ваш identity:

  1. эквивалентно лямбде * args: args
  2. Соберет свои аргументы - то есть

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

Итак, вы можете использовать lambda arg: arg, если вам нужна функция истинной идентичности.

2 голосов
/ 22 июня 2018

В Python нет встроенной функции идентификации.Имитация функции id *1002* *1003* в будет иметь вид:

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

Пример использования:

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

Поскольку identity ничего не делает, кроме возврата заданных аргументовЯ не думаю, что это медленнее, чем нативная реализация.Это может быть даже быстрее, потому что сохраняет вызов нативной функции.

1 голос
/ 08 декабря 2017

Заглушка функции с одним аргументом

gettext.gettext (пример использования OP) принимает один аргумент, message.Если для этого нужна заглушка, нет причины возвращать [message] вместо message (def identity(*args): return args).Таким образом, оба

_ = lambda message: message

def _(message):
    return message

подходят идеально.

... но встроенный модуль, безусловно, будет работать быстрее (и избежать ошибок, введенных мной).

Ошибки в таком тривиальном случае едва ли актуальны.Для аргумента предопределенного типа, скажем, str, мы можем использовать str() сам в качестве функции тождественности (из-за интернирования строк он даже сохраняет идентичность объекта, см. 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

Build-в функции идентификации объекта

Не путайте функцию идентификации со встроенной функцией id, которая возвращает «идентичность» объекта (то естьуникальный идентификатор для этого конкретного объекта, а не значение этого объекта (по сравнению с оператором ==), адрес его памяти в CPython.

0 голосов
/ 28 апреля 2016

Тема довольно старая. Но все же хотел опубликовать это.

Можно создать метод идентификации для аргументов и объектов. В приведенном ниже примере ObjOut является идентификатором ObjIn. Все остальные примеры выше не имели отношения к dict ** kwargs.

class test(object):
    def __init__(self,*args,**kwargs):
        self.args = args
        self.kwargs = kwargs
    def identity (self):
        return self

objIn=test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n')
objOut=objIn.identity()
print('args=',objOut.args,'kwargs=',objOut.kwargs)

#If you want just the arguments to be printed...
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().args)
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().kwargs)

$ py test.py
args= ('arg-1', 'arg-2', 'arg-3', 'arg-n') kwargs= {'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
('arg-1', 'arg-2', 'arg-3', 'arg-n')
{'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...