programing

람다 함수와 중첩 함수('def') 중 어느 것을 사용하는 것이 더 좋습니까?

muds 2023. 9. 28. 08:51
반응형

람다 함수와 중첩 함수('def') 중 어느 것을 사용하는 것이 더 좋습니까?

저는 람다 함수를 주로 사용하지만 때때로 동일한 동작을 제공하는 것으로 보이는 중첩 함수를 사용합니다.

다음은 기능적으로 동일한 작업을 수행하는 몇 가지 사소한 예입니다.

람다 함수

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

내포함수

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

>>> b(5)
6

하나를 사용하는 것이 다른 것보다 장점이 있습니까? (성능?가독성?한계?일관성?등)

그게 중요하긴 해요?만약 그렇지 않다면, 그것은 피톤의 원칙에 위배되는 것입니다.

그것을 할 수 있는 분명한 방법이 하나 있어야 합니다. 그리고 가급적이면 단 하나의 방법이 있어야 합니다.

해야 할 lambda이름은 a를 사용합니다.def대신.defs는 과제에 대한 통사적 설탕일 뿐이므로 결과는 동일하며 훨씬 더 유연하고 읽기 쉽습니다.

lambdas는 한 번 사용할 수 있고, 이름이 없는 기능은 버립니다.

그러나 이 사용 사례는 매우 드물습니다.이름 없는 함수 개체를 전달할 필요가 거의 없습니다.

된 것들은.map()그리고.filter()함수 개체가 필요하지만 목록 이해생성기 표현은 일반적으로 이러한 함수보다 더 가독성이 높고 lambdas를 사용하지 않아도 모든 사용 사례를 다룰 수 있습니다.

가 꼭 을 .operator능,예와 같은 :operator.addlambda x, y: x + y

하시면.lambda 경우,은을 하는 것을 할 수 .다를은하십시오.def 더 말이죠,입니다.operator,, adef아마 더 나을 겁니다.

의 좋은 , .lambda사용 사례는 매우 드뭅니다.

사실 제게는 두 가지 차이점이 있습니다.

첫 번째는 그들이 무엇을 하고 무엇을 돌려주는지에 관한 것입니다.

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

  • lambda는 함수 개체를 반환하는 키워드이며 로컬 네임스페이스에 '이름'을 만들지 않습니다.

따라서 함수 객체를 취하는 함수를 호출해야 한다면 파이썬 코드의 한 줄에서 이를 수행할 수 있는 유일한 방법은 람다를 사용하는 것입니다.데프와 동등한 것은 없습니다.

일부 프레임워크에서는 실제로 매우 일반적입니다. 예를 들어 Twisted를 많이 사용하기 때문에 다음과 같은 작업을 수행합니다.

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

꽤 흔하고, 람다와 더 간결합니다.

두 번째 차이점은 실제 기능이 무엇을 할 수 있는지에 대한 것입니다.

  • def'로 정의된 함수는 python 코드를 포함할 수 있습니다.
  • lambda'로 정의된 함수는 식을 계산해야 하므로 print, import, raise, ...와 같은 문장을 포함할 수 없습니다.

예를들면,

def p(x): print x

예상대로 작동합니다.

lambda x: print x

는 SyntaxError입니다.

- - print와 함께sys.stdout.write, 아니면import와 함께__import__ 하지만 보통 그런 경우에는 기능을 사용하는 것이 좋습니다.

인터뷰에서 귀도 반 로섬은 파이썬에 람다가 들어가지 않았으면 좋겠다고 말했습니다.

"Q. Python의 어떤 기능이 가장 마음에 들지 않습니까?

때때로 저는 기부금을 너무 빨리 받아왔고, 나중에 그것이 실수였다는 것을 깨달았습니다.람다 함수와 같은 기능적 프로그래밍 기능 중 일부를 예로 들 수 있습니다. 익명 수 있는 로, map,와 같은 lambda는 작은 익명 함수를 만들 수 있는 키워드로, map, filter, reduced 와 같은 기본 기능이 목록과 같은 시퀀스 유형에서 함수를 실행합니다와 같은 type에서합니다.

실제로는 결과가 별로 좋지 않았습니다.파이썬에는 로컬과 글로벌 두 가지 스코프만 있습니다.람다가 정의된 범위의 변수에 액세스하고 싶지만 두 개의 범위 때문에 액세스할 수 없기 때문에 람다 함수를 쓰는 것은 어려운 일입니다.이것을 피할 방법은 있지만, 일종의 진흙 같은 것입니다.종종 파이썬에서는 람다 함수를 만지작거리는 대신 for loop을 사용하는 것이 훨씬 쉬워 보입니다. 맵과 친구들은 이미 원하는 대로 할 수 있는 내장 기능이 있을 때만 잘 작동합니다.

ImmHO, Iambdas는 가끔 편리할 수 있지만 보통 가독성을 희생하면서 편리합니다.이것이 무엇을 하는지 말해줄 수 있습니까?

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

제가 쓴 건데 그걸 알아내는데 1분이 걸렸습니다.이것은 프로젝트 오일러에서 온 것입니다 - 스포일러를 싫어해서 어떤 문제인지 말하지는 않겠지만 0.124초 만에 실행됩니다 :)

: ()def)?

정규 함수보다 람다를 사용하는 데는 한 가지 장점이 있습니다. 식에서 생성된다는 것입니다.

몇 가지 단점이 있습니다.

  • , ())'<lambda>')
  • 무서류
  • 주석 없음
  • 복잡한 진술은 없습니다.

둘 다 같은 종류의 물체입니다.def람다 대신 키워드를 선택합니다.

첫번째 점은 - 그들은 같은 종류의 물체입니다.

람다를 사용하면 정규 함수와 동일한 유형의 개체가 생성됩니다.

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

람다는 기능이기 때문에 1등급의 물건입니다.

람다와 기능:

  • 인수로 전달할 수 있습니다(정규 함수와 동일).
  • 외부 함수 내에서 생성될 때 해당 외부 함수의 로컬에 대한 폐쇄가 됩니다.

그러나 기본적으로 lambda는 전체 함수 정의 구문을 통해 함수가 얻는 몇 가지를 놓치고 있습니다.

__name__이다.'<lambda>'

람다는 결국 익명의 기능이기 때문에 자신의 이름을 모릅니다.

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

하지만 도움의 결과를 엉망으로 만드는 오류가 있을 수도 있습니다.

Lambdas는 식만 반환할 수 있습니다.

람다는 복잡한 진술은 돌려줄 수 없고 표현만 가능합니다.

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

물론 표현은 다소 복잡할 수 있으며, 매우 열심히 노력하면 아마도 람다로도 동일한 결과를 얻을 수 있지만, 추가된 복잡성은 명확한 코드를 작성하는 데 더 큰 해가 됩니다.

명확성과 유지보수성을 위해 Python을 사용합니다.람다를 과도하게 사용하는 것은 그것에 불리하게 작용할 수 있습니다.

람다의 유일한 장점: 한 번의 표현으로 만들 수 있습니다.

이것이 유일하게 가능한 상승입니다.식을 사용하여 람다를 만들 수 있으므로 함수 호출 내부에 만들 수 있습니다.

함수 호출 내부에 함수를 만들면 다른 곳에서 생성된 이름과 비교하여 값비싼 이름 조회를 피할 수 있습니다.

그러나 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- 그것은 매우 무시할 수 있다는 것을 유의하세요.

결론

람다는 코드 줄을 최소화하여 단 하나의 요점을 제시하는 비공식적인 상황에 적합합니다.

람다는 나중에 올 코드 편집자에게 명확성이 필요한 보다 공식적인 상황, 특히 사소한 것이 아닌 경우에 좋지 않습니다.

우리는 우리의 물건에 좋은 이름을 붙여야 한다는 것을 알고 있습니다.그 물체에 이름이 없는데 어떻게 그렇게 할 수 있습니까?

이러한 으로 합니다를 deflambda.

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

성능:

로 함수 lambda를 사용하여 생성하는 것보다 약간 빠릅니다.def는 . 입니다 입니다.def로컬 테이블에 이름 항목을 만듭니다.결과 함수의 실행 속도는 동일합니다.


가독성:

람다 함수는 대부분의 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고 "입니다만 은 더 r"입니다.lambda v:원래의 비기능 버전으로 변환할 수 있습니다.훨씬 간결하기도 합니다.그러나 많은 Python 사용자들이 람다 구문에 혼란을 겪을 것이므로 길이와 실제 복잡성에서 손실되는 것은 동료 코더들로부터 혼란 속에서 다시 얻을 수 있다는 것을 기억하십시오.


제한 사항:

  • lambda함수는 변수 이름에 할당되지 않는 한 한 한 번만 사용할 수 있습니다.
  • lambda다보다 .def기능들.
  • lambda함수들은 피클하기 어렵거나 불가능할 수 있습니다.
  • def함수의 이름은 합리적으로 설명되고 고유하거나 최소한 범위 내에서 사용되지 않도록 신중하게 선택해야 합니다.

일관성:

파이썬은 절차적이고 단순한 목적 의미론을 선호하여 함수적 프로그래밍 규약을 대부분 피합니다.lambda연산자는 이러한 편향과 직접적인 대조를 이룹니다.으로서.def,lambda함수는 구문에 다양성을 추가합니다.어떤 사람들은 그것이 덜 일관적이라고 생각할 것입니다.


기존 함수:

다른 사람들이 언급한 바와 같이, 많은 용도의lambda될 수 있습니다.operator다른 모듈을 선택할 수 있습니다.예를 들어 다음과 같습니다.

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

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


피톤의 원리: "그것을 할 수 있는 분명한 방법이 하나 있어야 한다, 그리고 가급적이면 단 하나만이 있어야 한다,"

그것은 진실의 단일 원천 교리와 비슷합니다.불행하게도, 단일 방식으로 하는 원칙은 Python에게 진정한 지도 원칙이라기 보다는 항상 갈망의 대상이 되어 왔습니다.Python의 매우 강력한 어레이 이해를 고려해 보십시오.이들은 기능적으로 다음과 같습니다.map그리고.filter함수:

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

lambda그리고.def같습니다.

이것은 의견의 문제이지만, 저는 파이썬 언어의 어떤 것도 분명히 깨지지 않는 일반적인 용도의 파이썬 언어로는 충분하다고 말하고 싶습니다.

해야 할 nosklo 의합니다를 함수 이름을 지정해야 할 경우 사용하십시오.def했습니다.lambda다음과 같이 간단한 코드 조각을 다른 함수에 전달하는 경우의 함수:

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

다른 대답에 동의하면서도 때로는 더 읽기 쉽기도 합니다.다가 lambda편리하게 사용할 수 있습니다. 사용 사례에서 N차원을 계속 접하게 됩니다.
예는 다음과 같습니다.

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

나는 그것을 만드는 것보다 더 가독성이 있다고 생각합니다.def2차원의 경우.이는 더 높은 차원에서 더욱 중요합니다.

람다의 주된 용도는 항상 단순한 콜백 함수와 인수로서의 함수가 필요한 맵, 축소, 필터링을 위한 것이었습니다.목록 이해가 표준이 되고 다음과 같은 경우 추가가 허용됩니다.

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

람다를 일상생활에서 사용하는 실제 사례는 상상하기 어렵습니다.따라서 람다를 피하고 중첩 함수를 생성해야 합니다.

람다의 중요한 한계는 표현 외에 어떤 것도 담을 수 없다는 것입니다. 수 에 다른 하는 것은 왜냐하면 람다 표현식은 한 물체만큼 풍부한 물체를 가질 수 없기 때문입니다.def .

그렇기는 하지만, 루아는 익명 함수의 광범위한 사용에 대한 저의 프로그래밍 스타일에 영향을 미쳤고, 저는 그것들에 제 코드를 뿌렸습니다.여기에 저는 추상적인 연산자로서 지도/축소를 목록의 이해나 생성자를 고려하지 않는 방식으로 생각하는 경향이 있습니다. 마치 제가 그 연산자를 사용하여 구현 결정을 명시적으로 미루는 것처럼 말입니다.

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

는 A 를 를 것에 있습니다.lambda 있기 t를 들어,현; python에 어,def이 외에도 람다의 많은 용도는 이름이 없는 경우에도 미리 정의된(그리고 보다 효율적인) 구현을 가지고 있습니다.를 들어,어,될 수 .(1).__add__, 을 lambda아니면def인 용도는 . 의 할 수 .operator,itertools그리고.functools

람다를 로컬 범위에 있는 변수에 할당하려는 경우에는 diff를 사용하는 것이 더 판독성이 높고 나중에 더 쉽게 확장할 수 있기 때문입니다.

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)
  • 계산 시간.
  • 이름없는 기능.
  • 하나의 기능을 달성하고 많은 사람들이 기능을 사용합니다.

간단한 예를 들어 보면,

# 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

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

람다는 게으르게 평가될 수 있기 때문에 다음과 같은 코드를 가질 수 있습니다.

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

비용이 많이 드는 대신:

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

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

물론 사용 중인 로깅 모듈이 설명한 대로 작동하려면 lambdas를 "lazy parameters"(내 로깅 모듈이 하는 것처럼) 지원해야 합니다.

온 디맨드 콘텐츠 가치 창출을 위한 게으른 평가의 경우에도 동일한 아이디어가 적용될 수 있습니다.

예를 들어, 사용자 지정 터너리 연산자:

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(데이터, 콜백 기능)이라는 시그니처가 있는 기능이 있습니다.

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

람다 사용:

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

피톤적인 방법:

import operator
myFunction(data, operator.add)

물론 이것은 간단한 예이지만, 운영자 모듈이 제공하는 것은 목록 및 dict에 대한 항목 설정/게터를 포함하여 매우 많습니다.진짜 멋있어요.

큰 은 입니다를 할 수 입니다.def을 합니다.제라고 생각합니다.lambda기능. 개체 목록을 할 때:예를 들어 객체 목록을 정렬할 때:

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

따라서 저는 함수 이름을 지정함으로써 제공되는 자동 문서화의 혜택을 받지 못하는 이런 사소한 작업에도 람다를 계속 사용할 것을 제안합니다.

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

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

언급URL : https://stackoverflow.com/questions/134626/which-is-more-preferable-to-use-lambda-functions-or-nested-functions-def

반응형