는 더 많은 사용하는 것이 바람직에서는 파이썬:람다 함수하거나 중첩기능('def')?

StackOverflow https://stackoverflow.com/questions/134626

문제

나는 주로 람다 함수를 사용 하지만 때로는 사용이 중첩된 기능을 제공 하는 것 같은 동작입니다.

여기에 몇 가지 간단한 예제는 그들이 기능적으로 같은 일을 할 경우 이내에서 검색되었습니다 또 다른 기능:

람다 함수

>>> a = lambda x : 1 + x
>>> a(5)
6

중첩된 기능

>>> def b(x): return 1 + x

>>> b(5)
6

이 있는 이점 중 하나를 사용하여 다른?(Performance?가독성?제한?일관성?등.)

그것도 중요?지 않는 경우 다음을 위반하는 Pythonic 원리:

"이 있어야 하고 바람직하게 하나만 분명 그것을 할 수있는 방법".

도움이 되었습니까?

해결책

할당 해야하는 경우 lambda 이름으로 a def 대신에. defS는 할당을위한 구문 설탕 일 뿐이므로 결과는 동일하며 훨씬 유연하고 읽을 수 있습니다.

lambdaS는 사용될 수 있습니다 한 번 사용하고 버리십시오 이름이없는 함수.

그러나이 사용 사례는 매우 드 rare니다. 이름이없는 기능 개체를 전달할 필요는 거의 없습니다.

내장 map() 그리고 filter() 기능 개체가 필요하지만 이해력을 나열하십시오 그리고 발전기 표현식 일반적으로 해당 기능보다 읽기 쉬우 며 Lambdas의 필요없이 모든 사용 사례를 다룰 수 있습니다.

실제로 작은 기능 개체가 필요한 경우 사용해야합니다. operator 모듈 기능과 같은 operator.add 대신에 lambda x, y: x + y

아직도 필요하다면 lambda 다루지 않으면 a를 쓰는 것을 고려할 수 있습니다 def, 더 읽기 쉬운 것. 함수가 operator 모듈, a def 아마 더 낫다.

그래서, 실제 세계는 좋다 lambda 사용 사례는 매우 드 rare니다.

다른 팁

실제로 말하면, 나에게는 두 가지 차이점이 있습니다.

첫 번째는 그들이하는 일과 반환에 관한 것입니다.

  • DEF는 아무것도 반환하지 않고 로컬 네임 스페이스에서 '이름'을 작성하는 키워드입니다.

  • Lambda는 함수 객체를 반환하고 로컬 네임 스페이스에서 '이름'을 만들지 않는 키워드입니다.

따라서 함수 객체를 취하는 함수를 호출 해야하는 경우 한 줄의 Python 코드에서이를 수행하는 유일한 방법은 Lambda와 함께하는 것입니다. DEF와 동등한 것은 없습니다.

일부 프레임 워크에서 이것은 실제로 매우 일반적입니다. 예를 들어, 나는 사용합니다 꼬인 많이, 그래서 같은 일을합니다

d.addCallback(lambda result: setattr(self, _someVariable, result))

람다스와 더 간결하고 간결합니다.

두 번째 차이점은 실제 함수가 허용하는 일에 관한 것입니다.

  • 'def'로 정의 된 함수는 모든 파이썬 코드를 포함 할 수 있습니다.
  • 'lambda'로 정의 된 함수는 표현식으로 평가해야하므로 인쇄, 가져 오기, RISE, ...와 같은 진술을 포함 할 수 없습니다.

예를 들어,

def p(x): print x

예상대로 작동합니다

lambda x: print x

SyntaxError입니다.

물론 해결 방법이 있습니다 print ~와 함께 sys.stdout.write, 또는 import ~와 함께 __import__. 그러나 일반적 으로이 경우 기능을 사용하는 것이 좋습니다.

이 인터뷰에서 Guido 반로 섬을 말한 그는 그 소원이 없었 let'lambda'로 Python:

"Q.어떤 기능의 파이썬은 적어도 당신이 기쁘게 생각합니까?

때로는 내가 너무 빠른 수락에 기여하고,나중에는 것을 깨달았다.한 예로 들 수 있의 일부를 프로그래밍 기능과 같은 람다 함수입니다.람다는 키워드를 만들 수 있는 작은 익명이 기능내장와 같은 기능을 지도,여과기,그리고 줄이 실행되는 기능을 통해 시퀀스 유형,그러한 목록으로 표시합니다.

실제로,그것을 끄지 않았습니다.파이썬은 범위:지역 및 글로벌입니다.이것을 쓰는 람다 함수 고통스럽기 때문에,당신은 종종에 액세스하려는 변수 범위 lambda 정의되었다,하지만 당신은 할 수 없기 때문에 두 가지의 범위가 있습니다.이의 주위에 방법이지만,그것은 무언가의 임시방편 보.그것은 종종 훨씬 더 쉽게 보이는 파이썬에서만 사용에 대한 대신 루프를 장난으로 람다 함수입니다.지도와 친구들이 잘 작동이 있는 경우에만 이미 기능이 갖는 당신이 원하는 않습니다.

이럴 Iambdas 편리 할 수 있습니다 때때로,그러나 일반적으로 편에서는 비용의 일기 좋게.말할 수 있습니 나에게 이것이 무엇:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

나는 그것을 썼고,그것은 내게 하는 분이 있습니다.이 프로젝트로부터 오일러-말하지 않겠는 문제 때문에 내가 싫어 스포일러,하지만 그것을 실행에 0.124 초:)

n = 1000의 경우 여기에는 람다 기능 대 함수를 호출하는 시간이 있습니다.

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop

Nosklo의 조언에 동의합니다. 기능에 이름을 부여 해야하는 경우 사용하십시오. def. 나는 예약한다 lambda 간단한 코드 스 니펫을 다른 기능에 전달하는 경우 : 예를 들어 : 예를 들어 :

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )

성능:

함께 함수를 만듭니다 lambda ~이다 약간 더 빠릅니다 그것을 만드는 것보다 def. 차이점은 때문입니다 def 현지인 테이블에서 이름 항목 만들기. 결과 함수의 실행 속도가 동일합니다.


가독성 :

Lambda 기능은 대부분의 Python 사용자에게는 다소 읽기 쉬운 것이지만 일부 상황에서는 훨씬 더 간결합니다. 비 기능적으로 기능적 인 루틴을 사용하여 변환하는 것을 고려하십시오.

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

보시다시피, lambda 버전은 더 짧고 "더 쉽게"추가하면됩니다. lambda v: 기능 버전으로 변환하기 위해 원래 비 기능 버전으로. 또한 훨씬 더 간결합니다. 그러나 많은 Python 사용자가 Lambda 구문에 의해 혼란스러워 질 것이므로 길이와 실제 복잡성을 동료 코더의 혼란에 빠뜨릴 수 있습니다.


제한 사항 :

  • lambda 변수 이름에 할당되지 않는 한 함수는 한 번만 사용할 수 있습니다.
  • lambda 가변 이름에 할당 된 함수는 이점이 없습니다 def 기능.
  • lambda 기능은 피클하기가 어렵거나 불가능할 수 있습니다.
  • def 함수의 이름은 합리적으로 설명적이고 독특하거나 적어도 다른 방식으로 사용되지 않도록 신중하게 선택해야합니다.

일관성:

Python은 대부분 절차 적 및 단순한 객관적인 의미를 선호하는 기능 프로그래밍 규칙을 피합니다. 그만큼 lambda 연산자는이 편견과 직접 대조적입니다. 더욱이, 이미 널리 퍼져있는 대안으로 def,, lambda 함수는 구문에 다양성을 추가합니다. 일부는 덜 일관성이 있다고 생각할 것입니다.


기존 기능 :

다른 사람들이 언급했듯이 많은 용도 lambda 현장에서 operator 또는 다른 모듈. 예를 들어:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

기존 기능을 사용하면 많은 경우 코드를 더 읽을 수 있습니다.


Pythonic 원칙 :“하나의 끔찍한 방법이 하나만 있어야합니다.”

그것은 비슷합니다 진실의 단일 원천 교의. 불행히도, 단일 관용적 인 웨이-도-디 원칙은 진정한지도 원이 아니라 항상 파이썬에 대한 열망이었다. 파이썬의 강력한 배열 이해를 고려하십시오. 그것들은 기능적으로 동등합니다 map 그리고 filter 기능 :

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambda 그리고 def 동일합니다.

그것은 의견의 문제이지만, 나는 분명히 어떤 것도 깨지지 않는 일반적인 용도를위한 파이썬 언어의 모든 것이 "피티닉"이라고 말할 것입니다.

다른 답변에 동의하는 동안 때로는 더 읽기 쉬운 경우가 있습니다. 다음은 어디에 있습니다 lambda 유용한 경우, 사용 케이스에서 나는 N 차원을 계속 만난다. defaultdict.
예는 다음과 같습니다.

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

나는 그것을 만드는 것보다 더 읽기 쉬운 것을 발견했다 def 두 번째 차원의 경우. 이것은 더 높은 차원에서 훨씬 더 중요합니다.

Lambda의 기본 사용은 항상 간단한 콜백 기능과 MAP, Reduce, 필터에 대한 기능이 필요했습니다. 목록 이해력이 표준이되고 다음과 같이 추가 된 경우 추가가 허용됩니다.

x = [f for f in range(1, 40) if f % 2]

매일 사용하는 람다를 사용하는 실제 사례를 상상하기는 어렵습니다. 결과적으로, 나는 람다를 피하고 중첩 된 기능을 만듭니다.

람다의 중요한 한계는 표현 외에는 아무것도 포함 할 수 없다는 것입니다. Lambda 표현이 사소한 부작용 외에 무엇이든 생산하는 것은 거의 불가능합니다. def'ED 기능.

즉, Lua는 익명의 기능을 광범위하게 사용하는 것에 대한 프로그래밍 스타일에 영향을 미쳤으며 코드와 함께 코드를 쓰러 뜨 렸습니다. 또한, 나는 마치 해당 연산자를 사용하여 구현 결정을 명시 적으로 연기하는 것처럼 목록 이해력이나 생성기를 고려하지 않는 방식으로 MAP/Reduce에 대해 추상 연산자로 생각하는 경향이 있습니다.

편집하다: 이것은 꽤 오래된 질문이며, 그 문제에 대한 나의 의견은 다소 바뀌 었습니다.

우선, 나는 할당하는 것에 대해 강력하게 편향되어있다 lambda 변수에 대한 표현; Python은 그에 대한 특별한 구문을 가지고 있기 때문에 (힌트, def). 또한 Lambda의 많은 용도는 이름을 얻지 못하더라도 사전 정의 (보다 효율적인) 구현을했습니다. 예를 들어, 해당 예제는 (1).__add__, a로 감싸지 않아도됩니다 lambda 또는 def. 다른 많은 일반적인 용도는 operator, itertools 그리고 functools 모듈.

더 바람직한 : Lambda 함수 또는 중첩 함수 (def)?

규칙적인 기능 (표현식으로 생성됨)과 몇 가지 단점을 통해 Lambda를 사용하는 데 하나의 이점이 있습니다. 그런 이유로 나는 def Lambdas 대신 키워드.

첫 번째 요점 - 그들은 같은 유형의 객체입니다

람다는 일반 기능과 동일한 유형의 물체를 초래합니다.

>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
... 
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True

Lambdas는 기능이기 때문에 일류 대상입니다.

람다와 기능 모두 :

  • 인수로 전달 될 수 있습니다 (일반 기능과 동일)
  • 외부 기능 내에서 생성되면 해당 외부 기능의 현지인을 통해 폐쇄됩니다.

그러나 Lambdas는 기본적으로 기능이 전체 기능 정의 구문을 통해 얻는 것들이 누락됩니다.

람바 __name__ ~이다 '<lambda>'

Lambdas는 결국 익명의 기능이므로 자신의 이름을 모릅니다.

>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'

따라서 람다는 네임 스페이스에서 프로그래밍 방식으로 볼 수 없습니다.

이것은 특정한 것들을 제한합니다. 예를 들어, foo 직렬화 된 코드로 찾을 수 있습니다 l 할 수 없습니다 :

>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>: 
attribute lookup <lambda> on __main__ failed

우리는 조회 할 수 있습니다 foo 괜찮아 - 자체 이름을 알고 있기 때문에 :

>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>

람다에는 주석이없고 문서가 없습니다

기본적으로 Lambdas는 문서화되지 않습니다. 다시 쓰자 foo 더 잘 문서화하려면 :

def foo() -> int:
    """a nullary function, returns 0 every time"""
    return 0

이제 Foo는 문서가 있습니다.

>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:

foo() -> int
    a nullary function, returns 0 every time

반면, 우리는 람다에 동일한 정보를 제공하는 동일한 메커니즘이 없습니다.

>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda (...)

그러나 우리는 그것들을 해킹 할 수 있습니다 :

>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda ) -> in
    nullary -> 0

그러나 도움의 출력을 망치는 오류가있을 것입니다.

람다는 표현 만 반환 할 수 있습니다

람다는 복잡한 진술을 반환 할 수 없으며 표현 만 반환 할 수 없습니다.

>>> lambda: if True: 0
  File "<stdin>", line 1
    lambda: if True: 0
             ^
SyntaxError: invalid syntax

표현은 분명히 복잡 할 수 있으며 시도하면 매우 램다로 똑같이 성취 할 수는 있지만, 추가 된 복잡성은 명확한 코드를 작성하는 데 더욱 해를 끼칩니다.

선명도와 유지 가능성을 위해 파이썬을 사용합니다. 람다의 과도한 사용은 이에 반대 할 수 있습니다.

그만큼 Lambdas의 거꾸로 : 단일 표현식으로 만들 수 있습니다.

이것이 유일한 상승 여력입니다. 표현식으로 lambda를 만들 수 있으므로 함수 호출 내부에서 만들 수 있습니다.

함수 호출 내에서 함수 생성은 (저렴한) 이름 조회와 다른 곳에서 생성 된 이름을 피합니다.

그러나 Python은 엄격하게 평가되므로 이름 조회를 피하는 것 외에도 다른 성능을 얻을 수 없습니다.

매우 간단한 표현을 위해 람다를 선택할 수 있습니다.

또한 대화 형 파이썬을 할 때 람다를 사용하는 경향이 있습니다. 호출 할 때 생성자에게 인수를 전달하고 싶을 때 다음 종류의 코드 형식을 사용합니다. timeit.repeat:

import timeit

def return_nullary_lambda(return_value=0):
    return lambda: return_value

def return_nullary_function(return_value=0):
    def nullary_fn():
        return return_value
    return nullary_fn

그리고 지금:

>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304

위의 약간의 시간 차이는 이름 조회로 인한 것일 수 있다고 생각합니다. return_nullary_function - 그렇습니다 매우 무시할 수 있습니다.

결론

Lambdas는 단일 지점을 만들기 위해 코드 라인을 최소화하려는 비공식 상황에 적합합니다.

Lambdas는 나중에 올라갈 코드 편집자에게 명확성이 필요한보다 공식적인 상황에 대해, 특히 사소하지 않은 경우에 나쁘다.

우리는 우리가 물건에 좋은 이름을 주어야한다는 것을 알고 있습니다. 객체가있을 때 어떻게 할 수 있습니까? 아니요 이름?

이 모든 이유로, 나는 다음과 같은 기능을 선호합니다. def 대신 lambda.

  • 계산 시간.
  • 이름이없는 기능.
  • 하나의 기능과 많은 사용 기능을 달성합니다.

간단한 예를 고려하여

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements

Lambda를 로컬 범위의 변수에 할당하려면 DEF를 읽을 수 있고 앞으로 더 쉽게 확장 될 수 있기 때문에 DEF를 사용할 수도 있습니다.

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

또는

def fun(a, b): return a ** b # more readable
map(fun, someList)

내가 찾은 람다에 대한 한 가지 용도는 ... 디버그 메시지에 있습니다.

Lambdas가 게으르게 평가 될 수 있으므로 다음과 같은 코드를 가질 수 있습니다.

log.debug(lambda: "this is my message: %r" % (some_data,))

비싸지 않고 :

log.debug("this is my message: %r" % (some_data,))

디버그 호출이 현재 로깅 레벨로 인해 출력을 생성하지 않더라도 형식 문자열을 처리합니다.

물론 사용중인 로깅 모듈에 설명 된대로 작동하려면 Lambdas를 "게으른 매개 변수"(내 로깅 모듈과 마찬가지로)로 지원해야합니다.

같은 아이디어가 온난 한 콘텐츠 가치 창출에 대한 다른 게으른 평가의 사례에 적용될 수 있습니다.

예를 들어이 맞춤형 삼안 작업자 :

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

대신에:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

Lambdas를 사용하면 조건에 의해 선택된 표현 만 평가되며 Lambdas없이 둘 다 평가됩니다.

물론 당신은 단순히 람다 대신 기능을 사용할 수 있지만 짧은 표현의 경우 람다는 (c) leaner입니다.

나는 Nosklo에 동의합니다. 그건 그렇고,조차도 한 번 사용하고 버리십시오 기능, 대부분의 경우 연산자 모듈에서 무언가를 사용하려고합니다.

예 :

이 서명과 함께 함수가 있습니다 : myfunction (data, 콜백 함수).

2 개의 요소를 추가하는 함수를 전달하려고합니다.

람다 사용 :

myFunction(data, (lambda x, y : x + y))

Pythonic 방식 :

import operator
myFunction(data, operator.add)

또는 물론 이것은 간단한 예이지만 목록 및 DITT를위한 항목 세터 / 게터를 포함하여 운영자 모듈이 제공하는 많은 것들이 있습니다. 정말 멋진.

Lambda는 새로운 기능을 생성하는 데 유용합니다.

def somefunc(x): return lambda y: x+y
f = somefunc(10)
f(2)
>>> 12
f(4)
>>> 14

주요 차이점은 사용할 수 없다는 것입니다 def 내 의견으로는 내 생각에 가장 편리한 사용 사례입니다. lambda 기능. 예를 들어 객체 목록을 정렬 할 때 :

my_list.sort(key=lambda o: o.x)

그러므로 나는 이런 종류의 사소한 작업에 람다를 사용하는 것을 제안 할 것이며, 이는 또한 기능을 명명하여 제공되는 자동 문서의 이점도 이점도 없다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top