[python] 파이썬 : functools.partial이 왜 필요한가요?

부분 적용이 멋지다. functools.partial람다를 통과 할 수없는 기능은 무엇입니까 ?

>>> sum = lambda x, y : x + y
>>> sum(1, 2)
3
>>> incr = lambda y : sum(1, y)
>>> incr(2)
3
>>> def sum2(x, y):
    return x + y

>>> incr2 = functools.partial(sum2, 1)
>>> incr2(4)
5

functools보다 효율적으로, 또는 읽을 어떻게 든?



답변

functools.partial람다를 통과 할 수없는 기능은 무엇입니까 ?

추가 기능 측면에서는 그리 많지 않지만 (나중에 참조하십시오) – 가독성은 보는 사람의 눈에 있습니다.
함수형 프로그래밍 언어 (특히 리스프 / 계획 가족의 것)을 잘 알고있는 대부분의 사람들은 좋아 보인다 lambda잘 – 나는 “가장”, 확실히 말을 하지 모두 귀도 내가 확실히 ( “익숙”그 사이에 있기 때문에 등 ) 아직 lambda파이썬에서 눈에 띄지 않는 이상으로 생각합니다 …
그는 파이썬으로 그것을 받아 들인 것에 대해 회개했지만 “파이썬의 결함”중 하나로 파이썬 3에서 제거하려고 계획했습니다.
나는 그를 완전히지지했다. (I 사랑 lambda 제도에 … 잠시 한계를 파이썬에서 , 그리고 이상한 방법은 그냥 아무튼 나머지 언어로 피부를 크롤링하십시오).

그리 그러나,의 무리에 대한 lambda애호가 – 귀도 역 추적하고 떠나기로 결심 할 때까지, 지금까지 파이썬의 역사에서 볼 반란에 가장 가까운 것 중 하나 무대 lambda.의
에 몇 가지 추가 functools(함수는 상수, 정체성을 반환하게하는이, 등) (이상 중복 명시 적으로 피하기 위해 일어나지 않았다 lambda‘의 기능),하지만 partial물론 남아의 그것은 전혀 없습니다 (한을 중복 않으며)는 눈에 거슬리는입니다.

기억 lambda의 신체가로 제한된다 표현 은 한계를 가지고 있으므로. 예를 들어 … :

>>> import functools
>>> f = functools.partial(int, base=2)
>>> f.args
()
>>> f.func
<type 'int'>
>>> f.keywords
{'base': 2}
>>> 

functools.partial의 반환 함수는 내부 검사에 유용한 속성, 즉 랩핑하는 함수, 그리고 어떤 위치 및 명명 된 인수로 수정되는지로 장식됩니다. 또한 명명 된 인수를 다시 무시할 수 있습니다 ( “고정”은 다소 기본 설정입니다).

>>> f('23', base=10)
23

보시다시피 , 그것은 간단 하지 않습니다 lambda s: int(s, base=2)!-)

예, 당신은 할 수 당신이 몇 가지 제공하기 위해 람다를 곡해 – 키워드 – 오버 라이딩을 위해, 예를

>>> f = lambda s, **k: int(s, **dict({'base': 2}, **k))

하지만 사랑스러운 희망 도 가장 열렬한 것을 lambda-lover은 고려하지 않습니다 댄 공포 더 읽기 partial전화 -!). “속성 설정”부분은 파이썬의 “본문은 단일 표현”제한으로 인해 더욱 어려워집니다 lambda(그리고 할당은 절대로 파이썬 표현식의 일부가 될 수 없다는 사실). 디자인 한계를 넘어서 목록 이해력을 확장함으로써 … :

>>> f = [f for f in (lambda f: int(s, base=2),)
           if setattr(f, 'keywords', {'base': 2}) is None][0]

이제 하나의 표현으로 명명 된 인수 overridability 플러스 세 가지 속성의 설정을, 결합, 그리고 얼마나 읽을 말해 … 될 것입니다!


답변

다음은 차이점을 보여주는 예입니다.

In [132]: sum = lambda x, y: x + y

In [133]: n = 5

In [134]: incr = lambda y: sum(n, y)

In [135]: incr2 = partial(sum, n)

In [136]: print incr(3), incr2(3)
8 8

In [137]: n = 9

In [138]: print incr(3), incr2(3)
12 8

Ivan Moore의 다음 게시물은 “람다의 한계”와 파이썬의 클로저를 확장합니다.


답변

최신 버전의 Python (> = 2.7)에서는 다음을 수행 할 수 있지만 다음을 수행 할 수 picklepartial없습니다 lambda.

>>> pickle.dumps(partial(int))
'cfunctools\npartial\np0\n(c__builtin__\nint\np1\ntp2\nRp3\n(g1\n(tNNtp4\nb.'
>>> pickle.dumps(lambda x: int(x))
Traceback (most recent call last):
  File "<ipython-input-11-e32d5a050739>", line 1, in <module>
    pickle.dumps(lambda x: int(x))
  File "/usr/lib/python2.7/pickle.py", line 1374, in dumps
    Pickler(file, protocol).dump(obj)
  File "/usr/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 748, in save_global
    (obj, module, name))
PicklingError: Can't pickle <function <lambda> at 0x1729aa0>: it's not found as __main__.<lambda>


답변

functools가 어떻게 더 효율적입니까?

이것에 대한 부분 답변으로 나는 성능을 테스트하기로 결정했습니다. 내 예는 다음과 같습니다.

from functools import partial
import time, math

def make_lambda():
    x = 1.3
    return lambda: math.sin(x)

def make_partial():
    x = 1.3
    return partial(math.sin, x)

Iter = 10**7

start = time.clock()
for i in range(0, Iter):
    l = make_lambda()
stop = time.clock()
print('lambda creation time {}'.format(stop - start))

start = time.clock()
for i in range(0, Iter):
    l()
stop = time.clock()
print('lambda execution time {}'.format(stop - start))

start = time.clock()
for i in range(0, Iter):
    p = make_partial()
stop = time.clock()
print('partial creation time {}'.format(stop - start))

start = time.clock()
for i in range(0, Iter):
    p()
stop = time.clock()
print('partial execution time {}'.format(stop - start))

파이썬 3.3에서는 다음을 제공합니다.

lambda creation time 3.1743163756961392
lambda execution time 3.040552701787919
partial creation time 3.514482823352731
partial execution time 1.7113973411608114

즉, partial은 작성 시간이 조금 더 걸리지 만 실행 시간은 상당히 줄어 듭니다. 이것은 ars 의 답변에서 논의 된 초기 및 후기 바인딩의 효과 일 수 있습니다 .


답변

Alex가 언급 한 추가 기능 외에도 functools.partial의 또 다른 장점은 속도입니다. 부분적으로 다른 스택 프레임을 구성 (및 파괴)하지 않아도됩니다.

부분 또는 람다에 의해 생성 된 함수는 기본적으로 docstring을 갖지 않습니다 (단, 객체를 통해 doc 문자열을 설정할 수는 있음 __doc__).

이 블로그에서 자세한 내용을 확인할 수 있습니다 : Python의 부분 함수 응용 프로그램


답변

세 번째 예에서 가장 빠른 의도를 이해합니다.

람다를 구문 분석 할 때 표준 라이브러리에서 직접 제공하는 것보다 더 많은 복잡성 / oddity가 예상됩니다.

또한 세 번째 예는 전체 서명에 의존하지 않는 유일한 예입니다. sum2 . 따라서 약간 느슨하게 결합됩니다.


답변