developer tip

람다 함수 또는 중첩 함수 ( 'def') 중 어느 것이 더 선호됩니까?

optionbox 2020. 9. 1. 07:27
반응형

람다 함수 또는 중첩 함수 ( 'def') 중 어느 것이 더 선호됩니까?


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

다음은 둘 중 하나가 다른 함수 내에서 발견 된 경우 기능적으로 동일한 작업을 수행하는 몇 가지 간단한 예입니다.

Lambda 함수

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

중첩 함수

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

>>> b(5)
6

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

그것이 중요합니까? 그렇지 않으면 파이썬 원칙에 위배됩니다.

이를 수행하는 분명한 방법은 하나 (가급적이면 하나만) 여야합니다 .


lambda이름 에 할당해야하는 경우 def대신 a를 사용하십시오. defs는 할당에 대한 구문 설탕이므로 결과는 동일하며 훨씬 더 유연하고 읽기 쉽습니다.

lambdas는 한 번만 사용할 수 있으며 이름이없는 함수는 버릴 수 있습니다 .

그러나이 사용 사례는 매우 드뭅니다. 명명되지 않은 함수 개체를 전달할 필요가 거의 없습니다.

내장 map()filter()함수 객체가 필요하지만 목록 이해생성기 표현식 은 일반적으로 해당 함수보다 더 읽기 쉽고 람다없이 모든 사용 사례를 다룰 수 있습니다.

사례를 들어 당신은 정말 당신이 사용한다, 작은 함수 객체를 필요로 operator같은 모듈 기능을 operator.add대신lambda x, y: x + y

아직 lambda다루지 않은 부분이 필요한 경우 def더 읽기 쉽게을 작성하는 것이 좋습니다. 함수가 operator모듈 의 함수보다 복잡하다면 a def가 더 좋습니다.

따라서 실제 lambda사용 사례는 매우 드뭅니다.


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

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

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

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

따라서 함수 객체를받는 함수를 호출해야하는 경우 파이썬 코드 한 줄에서이를 수행하는 유일한 방법은 람다를 사용하는 것입니다. def와 동등한 것은 없습니다.

일부 프레임 워크에서 이것은 실제로 매우 일반적입니다. 예를 들어, 저는 Twisted 를 많이 사용합니다.

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

매우 일반적이며 람다와 더 간결합니다.

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

  • 'def'로 정의 된 함수는 모든 파이썬 코드를 포함 할 수 있습니다.
  • 'lambda'로 정의 된 함수는 표현식으로 평가되어야하므로 print, import, raise, ...와 같은 문을 포함 할 수 없습니다.

예를 들면

def p(x): print x

예상대로 작동하지만

lambda x: print x

SyntaxError입니다.

물론 , 또는 대체 print하는 해결 방법이 있습니다 . 그러나 일반적으로이 경우 함수를 사용하는 것이 좋습니다.sys.stdout.writeimport__import__


이 인터뷰에서 Guido van Rossum은 Python에 'lambda'를 사용하지 않았 으면 좋겠다고 말했습니다.

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

때로는 너무 빨리 기여를 받아들이고 나중에 그것이 실수라는 것을 깨달았습니다. 한 가지 예는 람다 함수와 같은 함수형 프로그래밍 기능 중 일부입니다. lambda 은 작은 익명 함수를 만들 수있는 키워드입니다. map, filter 및 reduce와 같은 내장 함수는 목록과 같은 시퀀스 유형에 대해 함수를 실행합니다.

실제로는 그렇게 잘되지 않았습니다. Python에는 로컬 및 글로벌의 두 가지 범위 만 있습니다. 이로 인해 람다가 정의 된 범위의 변수에 액세스하기를 원하기 때문에 람다 함수를 작성하는 데 어려움이 있지만 두 범위 때문에 불가능합니다. 이 문제를 피할 수있는 방법이 있지만 약간의 문제입니다. 종종 파이썬에서는 람다 함수를 엉망으로 만드는 대신 for 루프를 사용하는 것이 훨씬 쉬워 보입니다. 지도와 친구는 원하는 것을 수행하는 내장 기능이 이미있을 때만 잘 작동합니다.

IMHO, Iambdas는 때때로 편리 할 수 ​​있지만 일반적으로 가독성을 희생하여 편리합니다. 이것이 무엇을하는지 말해 줄 수 있습니까?

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

나는 그것을 썼고 그것을 알아내는 데 1 분이 걸렸습니다. 이것은 Project Euler에서 가져온 것입니다. 스포일러가 싫기 때문에 어떤 문제가 있는지 말하지 않겠습니다.하지만 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. 차이점은 deflocals 테이블에 이름 항목 생성하기 때문 입니다. 결과 함수는 동일한 실행 속도를 갖습니다.


가독성 :

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변수 이름에 할당 된 함수는 함수보다 이점이 없습니다 def.
  • lambda 기능은 피클하기 어렵거나 불가능할 수 있습니다.
  • def 함수의 이름은 합리적으로 설명적이고 고유하거나 적어도 범위에서 사용되지 않도록 신중하게 선택해야합니다.

일관성:

파이썬은 대부분 절차적이고 단순한 객관적 의미를 선호하는 함수형 프로그래밍 규칙을 피합니다. lambda조작이 직접 바이어스 대조를 이룬다. 또한, 이미 유행의 대안으로 deflambda기능은 구문에 다양성을 추가합니다. 일부는 덜 일관성이 있다고 생각할 것입니다.


기존 기능 :

다른 사람들이 언급했듯이 lambda필드에서의 많은 사용은 operator또는 다른 모듈의 구성원으로 대체 될 수 있습니다 . 예를 들면 :

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

기존 함수를 사용하면 대부분의 경우 코드를 더 읽기 쉽게 만들 수 있습니다.


파이썬 원칙 :“한 가지, 바람직하게는 한 가지 분명한 방법이 있어야합니다.”

그것은 진리단일 소스 와 유사합니다 . 안타깝게도 단일 명백한 실행 방법 원칙은 항상 진정한지도 교장 이라기보다는 Python에 대한 더 비참한 열망이었습니다. Python의 매우 강력한 배열 이해를 고려하십시오. mapfilter기능 기능적으로 동일 합니다.

[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두 번째 차원을 만드는 것보다 더 읽기 쉽습니다. 이것은 더 높은 차원에서 훨씬 더 중요합니다.


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

정규 함수 (표현식으로 생성됨)에 비해 람다를 사용하는 한 가지 장점과 몇 가지 단점이 있습니다. 따라서 def람다 대신 키워드로 함수를 만드는 것을 선호합니다 .

첫 번째 요점-동일한 유형의 객체입니다.

람다는 일반 함수와 동일한 유형의 객체를 생성합니다.

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

람다는 함수이기 때문에 일류 객체입니다.

람다와 함수 :

  • 인수로 전달할 수 있습니다 (일반 함수와 동일).
  • 외부 함수 내에서 생성되면 해당 외부 함수의 지역에 대한 클로저가됩니다.

그러나 람다는 기본적으로 함수가 전체 함수 정의 구문을 통해 얻는 일부 항목이 누락되었습니다.

람바 __name__'<lambda>'

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>

Lambda에는 주석과 독 스트링이 없습니다.

기본적으로 람다는 문서화되어 있지 않습니다. 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

But there's probably some error messing up the output of help, though.

Lambdas can only return an expression

Lambdas can't return complex statements, only expressions.

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

Expressions can admittedly be rather complex, and if you try very hard you can probably accomplish the same with a lambda, but the added complexity is more of a detriment to writing clear code.

We use Python for clarity and maintainability. Overuse of lambdas can work against that.

The only upside for lambdas: can be created in a single expression

This is the only possible upside. Since you can create a lambda with an expression, you can create it inside of a function call.

Creating a function inside a function call avoids the (inexpensive) name lookup versus one created elsewhere.

However, since Python is strictly evaluated, there is no other performance gain to doing so aside from avoiding the name lookup.

For a very simple expression, I might choose a lambda.

I also tend to use lambdas when doing interactive Python, to avoid multiple lines when one will do. I use the following sort of code format when I want to pass in an argument to a constructor when calling 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

And now:

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

I believe the slight time difference above can be attributed to the name lookup in return_nullary_function - note that it is very negligible.

Conclusion

Lambdas are good for informal situations where you want to minimize lines of code in favor of making a singular point.

Lambdas are bad for more formal situations where you need clarity for editors of code who will come later, especially in cases where they are non-trivial.

We know we are supposed to give our objects good names. How can we do so when the object has no name?

For all of these reasons, I prefer to create functions with def instead of with lambda.


The primary use of lambda has always been for simple callback functions, and for map, reduce, filter, which require a function as an argument. With list comprehensions becoming the norm, and the added allowed if as in:

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

it's hard to imagine a real case for the use of lambda in daily use. As a result, I'd say, avoid lambda and create nested functions.


An important limitation of lambdas is that they cannot contain anything besides an expression. It's nearly impossible for a lambda expression to produce anything besides trivial side effects, since it cannot have anywhere near as rich a body as a def'ed function.

That being said, Lua influenced my programming style toward the extensive use of anonymous functions, and I litter my code with them. On top of that, I tend to think about map/reduce as abstract operators in ways I don't consider list comprehensions or generators, almost as If I'm deferring an implementation decision explicitly by using those operators.

Edit: This is a pretty old question, and my opinions on the matter have changed, somewhat.

First off, I am strongly biased against assigning a lambda expression to a variable; as python has a special syntax just for that (hint, def). In addition to that, many of the uses for lambda, even when they don't get a name, have predefined (and more efficient) implementations. For instance, the example in question can be abbreviated to just (1).__add__, without the need to wrap it in a lambda or def. Many other common uses can be satisfied with some combination of the operator, itertools and functools modules.


  • Computation time.
  • Function without name.
  • To achieve One function and many use functionality.

Considering a simple example,

# 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

If you are just going to assign the lambda to a variable in the local scope, you may as well use def because it is more readable and can be expanded more easily in the future:

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

or

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

One use for lambdas I have found... is in debug messages.

Since lambdas can be lazily evaluated you can have code like this:

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

instead of possibly expensive:

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

which processes the format string even if the debug call does not produce output because of current logging level.

Of course for it to work as described the logging module in use must support lambdas as "lazy parameters" (as my logging module does).

The same idea may be applied to any other case of lazy evaluation for on demand content value creation.

For example this custom ternary operator:

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)

instead of:

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

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

with lambdas only the expression selected by the condition will be evaluated, without lambdas both will be evaluated.

Of course you could simply use functions instead of lambdas, but for short expressions lambdas are (c)leaner.


I agree with nosklo. By the way, even with a use once, throw away function, most of the time you just want to use something from the operator module.

E.G :

You have a function with this signature : myFunction(data, callback function).

You want to pass a function that add 2 elements.

Using lambda :

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

The pythonic way :

import operator
myFunction(data, operator.add)

Or course this is a simple example, but there is a lot of stuff the operator module provides, including the items setters / getters for list and dict. Really cool.


A major difference is that you can not use def functions inline, which is in my opinion the most convenient use case for a lambda function. For example when sorting a list of objects:

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

I would therefore suggest keeping the use of lambdas to this kind of trivial operations, which also do not really benefit from the automatic documentation provided by naming the function.


lambda is useful for generating new functions:

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

반응형