파이썬은 왜 멀티 라인 람다를 허용하지 않습니까?


50

누군가 BDFL이 파이썬 람다를 한 줄로 선택하는 구체적인 이유를 설명 할 수 있습니까?

이것은 좋다 :

lambda x: x**x

이로 인해 오류가 발생합니다.

lambda x:
    x**x

람다를 여러 줄로 만들면 일반적인 들여 쓰기 규칙을 어떻게 "방해"하고 더 많은 예외를 추가해야하지만 이점은 가치가 없다는 것을 이해합니다.

예를 들어 JavaScript를보십시오. 익명의 기능없이 어떻게 살 수 있습니까? 그들은 필수 불가결합니다. Pythonistas가 인수로 전달하기 위해 모든 여러 줄 함수의 이름을 지정하지 않아도되지 않습니까?


3
Guido가 다중 표현 람다를 허용하지 않는 구체적인 이유를 알고 나서 무시한다는 사실을 고려할 때 실제 답변이 아닌 검증을 원한다고 가정합니다.
Jason Baker

3
7자를 저장하는 것 외에도이 방법은 어떻게 def합니까? 이제 정확히 동일한 시각적 구조를 갖습니다.
detly

답변:


42

귀도 반 반 로섬은 스스로 대답했다.

그러나 이러한 솔루션에는 종종 "Pythonicity"가 부족합니다. 이는 훌륭한 Python 기능의 어려운 특성입니다. Pythonicity를 어려운 제약으로 표현하는 것은 불가능합니다. 파이썬의 선조차도 파이썬의 간단한 테스트로 해석되지 않습니다 ...

위의 예에서 제안 된 솔루션의 Achilles 힐을 쉽게 찾을 수 있습니다. 이중 콜론은 구문 상 모호하지 않지만 ( "퍼즐 제약 조건 중 하나") 완전히 임의적이며 Python의 다른 것과 유사하지 않습니다 ...

그러나 결국 거부합니다 (결국 제출자를 실수로 오도하는 것을 인정하는 곳입니다). 나는 표현의 중간에 들여 쓰기 기반 블록을 포함하는 모든 솔루션을 용납 할 수 없다는 것을 알았습니다. 명령문 그룹화 (예 : 중괄호 또는 시작 / 종료 키워드)에 대한 대체 구문도 똑같이 용납 할 수 없으므로 여러 줄 람다를 해결할 수없는 퍼즐로 만듭니다.

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

기본적으로 그는 해결책은 가능하지만 파이썬의 방식과 일치하지 않는다고 말합니다.


2
스레드 링크 덕분에 +1 감사합니다.하지만 여전히 멀티 라인 람다에 감사드립니다.
treecoder

2
@greengit 중첩 된 데프 만 사용할 수 있습니다. 익명 함수와 동일하지는 않지만 충분히 가깝습니다.
jsternberg

2
인수로 함수를 전달할 때 중첩 된 인증 된 정의는 도움이되지 않습니다 - 그 lambds 내가 여러 줄을 원하는 이유 번호를 하나의 이유
treecoder

1
@greengit-여기에 의견을 게시하는 것보다 GvR을 사용하는 것이 좋습니다.
Jason Baker

9
@ greengit : 함수를 다른 함수의 인수로 전달할 수 있다는 것을 알고 있습니까? 인라인으로 작성할 수는 없지만 사용할 수없는 프로그래밍 기술은 없습니다.
btilly

24

파이썬에서 멀티 라인 람다를 수행하는 것이 완벽합니다.

>>> f = lambda x: (
...   x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27

실제 람다 제한은 람다는 단일 표현 이어야한다는 사실이다 . python2 print또는 return) 와 같은 키워드를 포함 할 수 없습니다 .

GvR은 일반적으로 매개 변수로 사용되는 람다의 크기를 제한하기 위해이를 선택합니다. 실제 기능을 원하면def


1
멀티 라인 은 '\ n'문자 삽입에 관한 것입니다 .D 파이썬에는 멀티 람다 가 없습니다 . 당신은 정말로 사용하고 싶습니다 def. 생각해보십시오 : 함수의 매개 변수로 호출 가능해야합니까? 그리고 해당 기능의 사용자는 기본 호출 가능 항목 을 전달할 없습니까? 당신이 그들에게 그것을주지 않으면 어떻게 그것을 전달할 수 있습니까?
Vito De Tullio

btw, 익명 함수가 필요한 예를 제공 할 수 있습니까?
Vito De Tullio

1
예, 단일 표현의 한계는 정말 실망 스럽습니다. 그들이 다중 표현 람다를 허용한다면 사람들은 분명히 그것을 남용하기 시작하지만 다른 방법은 너무 제한적입니다.
rbaleksandar

10

나는 이것이 매우 오래되었다는 것을 알고 있지만 여기에 참조로 넣습니다.

람다를 사용하는 대안 def은 비 전통적인 방식으로 사용할 수 있습니다 . 목표는 a def를 함수 에 전달하는 것인데,이 기능은 데코레이터라는 한 가지 환경에서만 수행 할 수 있습니다. 이 구현 def result으로 함수를 만들지 않고의 결과가 생성되어 결국 결과 reduce()dict입니다.

뻔뻔한 플러그 :이 많이 할 여기 .

>>> xs = [('a', 1), ('b', 2), ('a', 3), ('b', 4)]
>>> foldl = lambda xs, initial: lambda f: reduce(f, xs, initial)
>>> @foldl(xs, {})
... def result(acc, (k, v)):
...     acc.setdefault(k, 0)
...     acc[k] += v
...     return acc
...
>>> result
{'a': 4, 'b': 6} 

다중 문 람다 수행 수 있지만 실제로는 아주 못생긴 코드로만 수행 할 수 있습니다. 그러나 흥미로운 점은이 구현에서 범위 지정이 작동하는 방식입니다 ( name변수 의 다중 사용 및 변수의 음영에 유의하십시오) message.

>>> from __future__ import print_function
>>> bind = lambda x, f=(lambda x: x): f(x)
>>> main = lambda: bind(
...     print('Enter your name.'), lambda _: bind(
...     raw_input('> '), lambda name: bind(
...     'Hello {}!'.format(name), lambda message: bind(
...     print(message), lambda _: bind(
...     'Bye {}!'.format(name), lambda message: bind(
...     print(message)
... ))))))
>>> main()
Enter your name.
> foo
Hello foo!
Bye foo!

모나 딕 접근 +1
jozefg

Monads는 JavaScript BTW에서 thenables 또는 future / promises 또는 콜백이라고도합니다.
aoeu256

3

다중 문 람다를 해킹하는 것은 pyrospade가 만드는 것만 큼 나쁘지 않습니다. Haskell에서와 같이 bind를 사용하여 여러 모나드 함수를 작성할 는 있지만 파이썬의 불순한 세계에 있기 때문에 부작용을 사용하여 동일한 것을 달성하십시오.

내 블로그 에서이 작업을 수행하는 몇 가지 방법을 다룹니다 .

예를 들어, 파이썬은 튜플의 요소를 순서대로 평가하므로 ,명령형과 매우 유사하게 사용할 수 있습니다 ;. 와 같은 많은 문장을와 같은 print표현식으로 대체 할 수 있습니다 sys.stdout.write.

따라서 다음은 동일합니다.

def print_in_tag_def(tag, text):
    print "<" + tag + ">"
    print text
    print "</" + tag + ">"

import sys
print_ = sys.stdout.write
print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
                                         print_(text),
                                         print_("</" + tag + ">"),
                                         None)[-1]

내가 추가했습니다 None끝에 끝에[-1] ; 을 사용하여 추출했습니다 . 반환 값을 명시 적으로 설정합니다. 우리는 이것을 할 필요는 없지만, 그것 없이는 펑키 한 (None, None, None)반환 값을 얻습니다 .

그래서 우리는 IO 액션을 시퀀싱 할 수 있습니다. 지역 변수는 어떻습니까?

파이썬 =은 문장을 형성하므로 동등한 표현을 찾아야합니다. 한 가지 방법은 인수로 전달 된 데이터 구조의 내용을 변경하는 것입니다. 예를 들면 다음과 같습니다.

def stateful_def():
    foo = 10
    bar = foo * foo
    foo = 2
    return foo + bar

stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
                                             state.setdefault('bar', state.get('foo') * state.get('foo')),
                                             state.pop('foo'),
                                             state.setdefault('foo', 2),
                                             state.get('foo') + state.get('bar'))[-1])({})

몇 가지 트릭이 사용되고 있습니다 stateful_lambda .

  • *_인수는 우리의 람다가 취할 수 있는 인수의 수입니다. 이것은 0을 허용하기 때문에인수가 ,의 호출 규칙을 복구합니다 stateful_def.
    • 인수를 호출하는 _것은 "이 변수를 사용하지 않을 것입니다"라는 규칙 일뿐입니다.
  • 우리는 다른 ( "main") 함수를 반환하는 하나의 "wrapper"함수를 가지고 있습니다 : lambda state: lambda *_: ...
    • 어휘 범위 덕분에 첫 번째 함수의 인수는 두 번째 함수의 범위 내에 있습니다.
    • 지금 일부 인수를 수락하고 나중에 나머지를 수락하기 위해 다른 함수를 반환하는 것을 카레라고합니다.
  • 우리는 즉시 "래퍼 (wrapper)"함수를 호출하여 빈 사전을 전달합니다. (lambda state: ...)({})
    • 이것은 우리가 변수 할당 할 수 있습니다 state값으로를 {}할당 문을 사용하지 않고 (예. state = {})
  • 키와 값 state을 변수 이름과 바인딩 된 값으로 취급 합니다
    • 이것은 즉시 불리는 람다를 사용하는 것보다 덜 성가시다
    • 이를 통해 변수 값을 변경할 수 있습니다
    • 우리는 사용하는 state.setdefault(a, b)대신에 a = b하고 state.get(a)대신a
  • 우리는 튜플을 사용하여 이전과 같이 부작용을 연결합니다.
  • 우리 [-1]return성명서 처럼 행동하는 마지막 값을 추출하는 데 사용 합니다 .

물론 이것은 꽤 번거롭지 만 도우미 함수로 더 멋진 API를 만들 수 있습니다.

# Keeps arguments and values close together for immediately-called functions
callWith = lambda x, f: f(x)

# Returns the `get` and `setdefault` methods of a new dictionary
mkEnv = lambda *_: callWith({},
                            lambda d: (d.get,
                                       lambda k, v: (d.pop(k), d.setdefault(k, v))))

# A helper for providing a function with a fresh `get` and `setdefault`
inEnv = lambda f: callWith(mkEnv(), f)

# Delays the execution of a function
delay = lambda f x: lambda *_: f(x)

# Uses `get` and `set`(default) to mutate values
stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
                                                 set('bar', get('foo') * get('foo')),
                                                 set('foo', 2),
                                                 get('foo') + get('bar'))[-1])

농담이다,이 악몽처럼 롤 보이는
알렉산더 밀스

1
@AlexanderMills Heh, 이것은 실제 사례로 의도 된 것이 아니며, pyrospade의 람다에서 람다에서 람다 접근에 대한 반박을 더한 것으로, 사물이 그렇게 나쁘지 않다는 것을 보여줍니다 . 사실, 이것은 python.org/dev/peps/pep-0572
Warbo

1

나는 기여할 수 있지만 줄 바꿈을 사용하십시오.

x = lambda x,y: x-y if x<y \ 
                     else y-x if y<x \
                     else 0

파이썬이 oneliners를 작성할 수 있다는 아주 좋은 점을 잊지 마십시오.

a=b=0; c=b+a; d = a+b**2 #etc etc

그리고 람다 는 매우 강력하지만 1 개의 전체 기능을 대체하기위한 것이 아닙니다. 해킹 할 수 있음을 의미합니다 (위의 동료의 예를 빌리십시오).

makeTag = lambda tagName: "<{}>".format(tagName)
closeTag = lambda tagName: makeTag("/"+str(tagName))
openTag = lambda tagName: makeTag(tagName)
writeHMTLline = lambda tag,content: ""+opetTag(tag)+str(content)+closeTag(tag)

그러나 당신은 정말로 이것을 이렇게하고 싶습니까? 그것은 시간이 지나면 대부분 읽을 수 없으며, 끝이 뾰족한 것으로 시작하는 로프의 시작 부분과 같습니다. 풀리지 않은 밧줄

Lambdas는 기능 지향 프로그래밍 (특히 기능 중심)의 기능을 맵, 필터링 및 축소하는 기능 중 하나의 유일한 기능입니다. 예를 들어 정수이고 2로 나눌 수있는 값의 문자 값 가져 오기

chrDev2 = lambda INT: chr(INT) if isinstance(INT,int) and INT%2==0 else INT
someStringList = map( chrDev2, range(30) )
>>> ['\x00', 1, '\x02', 3, '\x04', 5, '\x06', 7, '\x08', 9, '\n', 11, '\x0c', 13, '\x0e', 15, '\x10', 17, '\x12', 19, '\x14', 21, '\x16', 23, '\x18', 25, '\x1a', 27, '\x1c', 29]

복잡한 함수 (또는 여러 람다)를 정의하고 다른 람다 안에 넣으면 함수 expresions 함수로 사용할 수 있습니다.

def someAnon(*args): return sum(list(args))
defAnon = lambda list: [ x*someAnon(*list) for x in list]

그러나 파이썬은 다른 방법으로 함수 expresions를 지원합니다 : -lets 함수가 호출 superAwesomeFunction되었고 그 함수가 매우 멋진 일을 할 수 있다고 말하면 , 함수를 호출하지 않고 변수에 할당 할 수 있습니다.

SAF = superAwesomeFunction # there is no () at the end, 

이제 SAF를 호출하면 superAwesomeFunction 또는 메소드가 호출됩니다. Lib 폴더를 검색하면 대부분의 파이썬을 찾을 수 있습니다__builtin__ 모듈이 그런 식으로 작성되었음을 알 수 있습니다. 때로는 사용자가 사용할 수있을만큼 필요하지 않은 특정 작업을 수행하는 일부 기능이 필요하지만 여러 기능이 필요하기 때문에 수행됩니다. 따라서 이름이 "superAwesomeFunction"인 2 개의 함수를 가질 수 없으며 "superAwesomeFunctionDoingBasicStuf"및 "realSuperAwesomeFunction"을 가질 수 있으며 "superAwesomeFunction"변수에 "realSuperAwesomeFunction"을 넣는 것보다 완료된 것입니다.

console importedModule.__file__(실제 예 import os;os.__file__) 을 입력하여 가져온 모듈의 위치를 ​​찾은 다음 해당 디렉토리를 따라 importedModule.py 라는 파일로 이동하십시오. 하여 편집기에서 열고 자신의 "지식"을 최대화하는 방법을 찾으십시오.

이것이 당신과 다른 동료들에게 도움이되기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.