파이썬에 내장 기능이 있습니까?


145

아무것도하지 않는 함수를 가리키고 싶습니다.

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

6
무슨 소리 야 map and filter use None for the identity?
매트 펜윅

15
@ 매트 펜윅 :map(None, [1, 2, 3])
그렉

6
반환 값을 확인하십시오. args 변수는 (이 시나리오에서) 하나의 값 시퀀스이므로 선언에서 별표를 생략하거나 반환을 위해 압축을 푸십시오.
Dirk

11
@GregHewgill : 슬프게도 Python 3.x에서는 작동하지 않습니다.
Ethan Furman

6
@GregHewgill 내 나쁜. 인터넷 검색 후 문서에서 가져 왔습니다. 그러나 Python2.x 문서는 항상 우선입니다 ...
rds

답변:


99

좀 더 연구를하고, 아무도, 기능이 거기 요구하지 않았다되는 문제 1673203 그리고에서 레이몬드 Hettinger는 없을 것이라고 말했다 :

사람들이 자신의 사소한 패스 스루를 작성하고 서명 및 시간 비용에 대해 생각하게하는 것이 좋습니다.

그래서 그것을하는 더 좋은 방법은 실제로 (람다는 함수의 이름을 피하는 것입니다) :

_ = lambda *args: args
  • 장점 : 여러 매개 변수를 사용합니다
  • 단점 : 결과는 박스 버전의 매개 변수입니다.

또는

_ = lambda x: x
  • 장점 : 매개 변수의 유형을 변경하지 않습니다
  • 단점 : 정확히 1 개의 위치 매개 변수 사용

13
이것은 신원 함수가 아닙니다.
Marcin

1
@Marcin 의견을 보내 주셔서 감사합니다. 나는 누군가를 오도하지 않기 위해 두 가지 장점 / 단점을 추가했습니다. 그리고 지금, 나는 정말로 많은 매개 변수를 받아들이고 진정한 정체성 인 내장 함수가 있어야한다고 생각합니다. :
rds

7
좋은 대답입니다. 그러나 여러 매개 변수를 사용할 때 진정한 아이덴티티 함수는 무엇을 반환합니까?
Marcin

5
@Marcin : 단지 그가 질문 한 것에 따라가는 것도 아닙니다.
Ethan Furman

4
예, lambda x: x하나의 문자열 매개 변수에 대해 작동 하는 간단한 ID 기능이 있습니다. @Marcin 내가 할 수 있기를 바랍니다 lambda *args: *args:-)
rds

28

https://en.wikipedia.org/wiki/Identity_function에 정의 된대로 identity 함수 는 단일 인수를 사용하여 변경되지 않은 상태로 반환합니다.

def identity(x):
    return x

서명을 원할 때 요구하는 def identity(*args)것은 여러 인수를 취하기를 원하기 때문에 엄격하게 ID 함수 가 아닙니다 . 괜찮습니다.하지만 파이썬 함수는 여러 결과를 반환하지 않으므로 문제가 발생하므로 모든 인수를 하나의 반환 값으로 구성하는 방법을 찾아야합니다.

파이썬에서 "다중 값"을 반환하는 일반적인 방법은 기술적으로 하나의 반환 값이지만 여러 값인 것처럼 대부분의 컨텍스트에서 사용할 수있는 값의 튜플을 반환하는 것입니다. 하지만 여기서하는 것은

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

그리고 고정 여기에 다양한 대답이 표시대로 신속하게 문제 것은 다른 문제를 제공합니다.

따라서 요약하면 파이썬에는 다음과 같은 이유로 식별 함수가 정의되어 있지 않습니다.

  1. 공식적인 정의 (단일 인수 함수)는 그다지 유용하지 않으며 작성하기가 쉽지 않습니다.
  2. 정의를 여러 인수로 확장하는 것은 일반적으로 잘 정의되어 있지 않으므로 특정 상황에 필요한 방식으로 작동하는 고유 버전을 정의하는 것이 훨씬 좋습니다.

정확한 경우를 위해

def dummy_gettext(message):
    return message

거의 확실하게 원하는 것입니다-호출 규칙이 같고 as gettext.gettext를 반환하는 함수는 인수를 변경하지 않고 반환하며 함수의 역할과 용도를 명확하게 지정합니다. 성능이 중요한 고려 사항이라면 충격을받을 것입니다.


"답변이 표시 한대로 해당 문제를 해결하면 다른 문제가 발생합니다"라는 대답이 무엇인지 알 수 없습니다. 구체적으로 사용하면 충분합니다 id= lambda *args: args if len(args)>1 else args[0].
최대

21

당신은 잘 작동합니다. 매개 변수 수가 수정되면 다음과 같은 익명 함수를 사용할 수 있습니다.

lambda x: x

8
varargs를 사용하여이 작업을 수행 할 수도 있습니다 lambda *args: args. 정말 문체 선택입니다.

나는 많은 주장을 취하기 때문에 두 번째가 더 좋습니다.
rds

4
@delnan @rds- *args버전의 리턴 유형이 다르므로 단일 인수의 경우에도 동일하지 않습니다.
Marcin

8
@delnan : 당신은 그것이 문체 선택이라고 말했는데, 이것은 두 형태의 의미에 차이가 없다는 것을 잘못 암시합니다.
Marcin

1
@Marcin : 암시하면 안타깝습니다. 나는 사이의 선택을 의미 deflambda같은 간단한 기능을 위해.

7

파이썬에는 내장 된 아이덴티티 함수가 없습니다. 하스켈 id기능 의 모방은 다음과 같습니다.

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

사용법 예 :

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

identity주어진 인수를 반환하는 것 외에는 아무것도하지 않기 때문에 네이티브 구현보다 느리다고 생각하지 않습니다.


설정이 완료된 후 수행 한 작업에 관계없이 시간이 걸리는 통화 자체의 구성입니다.
chepner

@chepner 무슨 의미인지 더 자세히 설명해 주시겠습니까? 네이티브 함수에 대한 호출도 구성해야합니다. 이 구성은 비원시 함수에 대한 호출 구성보다 더 빨리 수행됩니까?
SergiyKolesnikov

1
사용자 정의 함수에 대한 호출은 최소한 내장 함수에 대한 호출만큼 비싸며, 아마도 사용자 정의 함수를 호출 한 후에는 더 많은 사용자 정의 또는 내장 함수를 호출 할 수 있기 때문에 아마도 더 비쌉니다 . 기능에서.
chepner

6

아닙니다.

당신의 identity:

  1. lambda * args : args와 같습니다.
  2. 그것의 인수를 윌 박스-즉

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

따라서 lambda arg: arg진정한 아이덴티티 기능을 원한다면 사용할 수 있습니다.

주의 :이 예제는 내장 id함수를 사용하지 않을 것입니다 (아마도 사용하지 않을 것입니다).


1
id는 내장 함수이며이 스 니펫은이를 덮어 씁니다.
Arnie97

@ Arnie97 박람회! 나는 잊었다id
Marcin

4

속도가 중요하지 않은 경우 모든 경우를 처리해야합니다.

def identity(*args, **kwargs):
    if not args:
        if not kwargs:
            return None
        elif len(kwargs) == 1:
            return  next(iter(kwargs.values()))
        else:
            return (*kwargs.values(),)
    elif not kwargs:
        if len(args) == 1:
            return args[0]
        else:
            return args
    else:
        return (*args, *kwargs.values())

사용 예 :

print(identity())
None
$identity(1)
1
$ identity(1, 2)
(1, 2)
$ identity(1, b=2)
(1, 2)
$ identity(a=1, b=2)
(1, 2)
$ identity(1, 2, c=3)
(1, 2, 3)

1

단일 인수 함수의 스텁

gettext.gettext(OP의 예제 사용 사례)는 단일 인수 인을 허용합니다 message. 스텁이 필요한 경우 ( ) [message]대신 반환 할 이유가 없습니다 . 따라서 둘 다messagedef identity(*args): return args

_ = lambda message: message

def _(message):
    return message

완벽하게 맞습니다.

...하지만 내장 기능은 확실히 더 빨라질 것입니다.

그러한 사소한 경우의 버그는 거의 관련이 없습니다. 사전 정의 된 유형의 인수 인 경우 str, 우리는 str()자신을 ID 함수로 사용할 수 있습니다 ( 문자열 interning 때문에 객체 ID를 유지 하기 때문에 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내장 반환 함수 객체의 '정체성' (에 비해, 특정 객체가 아니라 객체의 값에 대한 고유 식별자를 의미를 ==CPython의 연산자), 메모리 주소입니다.


40 % 속도 향상은 "그만한 가치가없는 것 같습니까?" 예를 들어 10,000x10,000 픽셀 이미지에서 채널당 한 번 (매일은 아니지만 확실히 드물지 않은) 실행되는 기능에 대해 ID가 "기본 필터"로 작동하는 경우 이는 25와 9의 차이입니다. 실행 시간의 초! 그럼에도 불구하고 Cython 예제에 감사드립니다.
9999

@ 9999 년 동의합니다. 합당 성 의견을 삭제했습니다. 답변을 개선해 주셔서 감사합니다. 나는 당신의 일부를 약간 변경했습니다.
saaj

10,000x10,000 픽셀 이미지가 있다면 numpy와 같은 것을 사용하여 벡터화 된 작업을 사용하는 것이 좋습니다. 더 빠르며 메모리를 적게 사용하며 Cython 코드를 작성할 필요가 없습니다.
anthonybell

-2

실이 꽤 낡았습니다. 그러나 여전히 이것을 게시하고 싶었습니다.

인수와 객체 모두에 대해 ID 메소드를 구축 할 수 있습니다. 아래 예에서 ObjOut은 ObjIn의 ID입니다. 위의 다른 모든 예제는 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}

이것은 참조처럼 보이면 어디에서 왔습니까?
Jeff Puckett

@JeffPuckettII 나는 당신의 질문을 따르지 않았습니다. 새 객체가 참조인지 묻고 있습니까?
Sud

다른 출처의 참조를 암시하는 "아이덴티티를 구축 할 수 있습니다 ..."에 블록 인용 부호를 사용했습니다. 이것이 당신의 자신의 말이라면, 나는 그것을 인용으로 강조 표시하지 않는 것이 좋습니다. 정말 큰 일이 아닙니다. 그러나 이것이 다른 출처에서 인용 한 경우 이에 대한 참조를 포함해야합니다.
Jeff Puckett

어떻게 원래의 질문에 대답 할 map(identity, [1, 2, 3])수익을 [1, 2, 3]?
rds

class test1(object): def __init__(self,*args,**kwargs): self.args = args self.kwargs = kwargs def identity (self): return self.args print(test1([1,2,3]).identity())-> 결과 : ([1, 2, 3],)
Sud
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.