[python] 파이썬에 여러 줄 람다가없는 이유는 무엇입니까?

멀티 라인 람다는 파이썬의 다른 구문 구문과 구문 적으로 충돌하기 때문에 파이썬에서 추가 할 수 없다고 들었습니다. 나는 오늘 버스에서 이것에 대해 생각하고 있었고 여러 줄 람다가 충돌하는 단일 파이썬 구조를 생각할 수 없다는 것을 깨달았습니다. 내가 그 언어를 아주 잘 알고 있기 때문에, 이것은 나를 놀라게했다.

이제 Guido가 언어에 여러 줄 람다를 포함시키지 않았지만 호기심에서 벗어날 이유가 있다고 확신합니다. 여러 줄 람다를 포함하는 것이 모호한 상황은 무엇입니까? 내가 들었던 것이 사실입니까, 아니면 파이썬이 여러 줄 람다를 허용하지 않는 다른 이유가 있습니까?



답변

다음을보십시오 :

map(multilambda x:
      y=x+1
      return y
   , [1,2,3])

이것이 람다 반환입니까 (y, [1,2,3])(따라서지도는 하나의 매개 변수 만 가져 오며 오류가 발생합니까)? 아니면 반환 y합니까? 아니면 새 줄의 쉼표가 잘못되어 구문 오류입니까? 파이썬은 당신이 원하는 것을 어떻게 알 수 있습니까?

괄호 안에서 들여 쓰기는 파이썬에 중요하지 않으므로 여러 줄로 명확하게 작업 할 수 없습니다.

이것은 단순한 것입니다. 아마도 더 많은 예가있을 것입니다.


답변

귀도 반 로섬 (파이썬 발명가) 은 오래된 블로그 게시물 에서이 정확한 질문에 스스로 대답합니다 .
기본적으로 그는 이론적으로는 가능하지만 제안 된 해결책은 피 토닉이 아니라고 인정합니다.

“하지만이 퍼즐에 대해 제안 된 솔루션의 복잡성은 엄청나 다. 파서 (또는 더 정확하게는 어휘 분석기)가 들여 쓰기에 민감하고 들여 쓰기에 민감하지 않은 모드를 전환 할 수 있어야한다. 기술적으로 모든 문제를 해결할 수 있습니다 (이미 일반화 할 수있는 들여 쓰기 수준 스택이 있습니다). 그러나 그 중 어느 것도 그것이 정교한 Rube Goldberg contraption이라고 생각하지 않습니다 . “


답변

이것은 일반적으로 매우 추악하지만 (때로는 대안이 더 추악한 경우도 있음) 해결 방법은 중괄호 식을 만드는 것입니다.

lambda: (
    doFoo('abc'),
    doBar(123),
    doBaz())

할당은받지 않으므로 미리 데이터를 준비해야합니다. 이것이 유용하다고 생각한 곳은 PySide 래퍼이며 때로는 콜백이 짧습니다. 추가 멤버 함수를 작성하는 것이 훨씬 추악합니다. 일반적으로 이것은 필요하지 않습니다.

예:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(),
    spinBox1.setValue(0),
    diag.show())


답변

몇 가지 관련 링크 :

잠시 동안, 나는 처음에 Erlang을 기반으로 Ruby 블록과 함께 파이썬의 들여 쓰기 기반 구문을 갖게 될 Reia의 개발을 따르고있었습니다. 그러나 디자이너는 들여 쓰기 민감도를 포기하고이 결정에 대해 들여 쓰기 + 여러 줄 블록으로 인해 발생한 문제에 대한 토론과 Guido의 디자인 문제 / 결정에 대해 얻은 감사에 대한 토론이 포함되었습니다.

http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html

또한, 파이썬에서 루비 스타일 블록에 대한 흥미로운 제안이 있습니다. Guido가 실제로 그것을 쏘지 않고 응답을 게시하는 곳을 가로 질러 뛰어 왔습니다.

http://tav.espians.com/ruby-style-blocks-in-python.html


답변

[편집] 이 답변을 읽으십시오 . 여러 줄 람다가 왜 아닌지 설명합니다.

간단히 말해, 그것은 비유 론적입니다. Guido van Rossum의 블로그 게시물에서 :

식 중간에 들여 쓰기 기반 블록을 포함하는 솔루션을 사용할 수 없습니다. 명령문 그룹화 (예 : 중괄호 또는 시작 / 종료 키워드)에 대한 대체 구문도 똑같이 용납 할 수 없으므로 여러 줄 람다를 해결할 수없는 퍼즐로 만듭니다.


답변

영광 스럽지만 끔찍한 핵을 보여 드리겠습니다.

import types

def _obj():
  return lambda: None

def LET(bindings, body, env=None):
  '''Introduce local bindings.
  ex: LET(('a', 1,
           'b', 2),
          lambda o: [o.a, o.b])
  gives: [1, 2]

  Bindings down the chain can depend on
  the ones above them through a lambda.
  ex: LET(('a', 1,
           'b', lambda o: o.a + 1),
          lambda o: o.b)
  gives: 2
  '''
  if len(bindings) == 0:
    return body(env)

  env = env or _obj()
  k, v = bindings[:2]
  if isinstance(v, types.FunctionType):
    v = v(env)

  setattr(env, k, v)
  return LET(bindings[2:], body, env)

이제이 LET양식을 다음과 같이 사용할 수 있습니다 .

map(lambda x: LET(('y', x + 1,
                   'z', x - 1),
                  lambda o: o.y * o.z),
    [1, 2, 3])

이것은 다음을 제공합니다. [0, 3, 8]


답변

내 프로젝트 중 일부 에서이 더러운 핵을 연습하는 것이 유죄입니다.

    lambda args...:( expr1, expr2, expr3, ...,
            exprN, returnExpr)[-1]

나는 pythonic을 유지할 수있는 방법을 찾을 수 있기를 바랍니다. 그러나 그렇게해야한다면 exec를 사용하고 전역을 조작하는 것보다 덜 고통 스럽습니다.