Python에서 람다 식 내부 할당
개체 목록이 있고 하나를 제외하고 비어있는 모든 개체, filter
및 lambda
식 을 제거하고 싶습니다 .
예를 들어 입력이 다음과 같은 경우 :
[Object(name=""), Object(name="fake_name"), Object(name="")]
... 출력은 다음과 같네요.
[Object(name=""), Object(name="fake_name")]
lambda
식에 할당을 추가하는 방법이 있습니까? 예를 들면 :
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
:=
Python 3.8에 추가 된 할당 된 연산자 는 람다 내부의 할당을 지원합니다. 이 연산자는 구문상의 여러 괄호 (...)
, 괄호 [...]
또는 괄호 로 묶인 {...}
하나만 나타날 수 있습니다 . 예를 들어 다음과 같이 있고 있습니다.
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Python 2에서는 목록 이해의 부작용으로 로컬 할당을 수행 할 수 있습니다.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
그러나 변수 flag
가의 범위가 아닌 외부 범위에 있기 때문에 이들 중 하나를 사용할 수 없습니다 lambda
. 이것은 관련이 없습니다. 이것은 lambda
Python 2의 일반적인 동작입니다. 파이썬 3를 사용하면 의 nonlocal
내부의 키워드 로이 문제를 해결할 수 def
있지만의 내부에서는 nonlocal
사용할 수 없습니다 lambda
.
해결 방법이 제안 (아래 참조) 주제를 다루는 동안 ...
어떤 경우에는 내부의 모든 작업을 수행 할 수 있습니다 lambda
.
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
반지름이 10.0cm이고 높이가 20.0cm 인 원통의 부피는 6283.2cm³입니다.
반지름이 20.0cm이고 높이가 40.0cm 인 실린더의 부피는 50265.5cm³입니다.
반지름이 30.0cm이고 높이가 60.0cm 인 실린더의 부피는 169646.0cm³입니다.
하지 마십시오.
... 원래 예제로 돌아가서 : flag
외부 범위 의 변수에 할당을 수행 할 수는 없지만 함수를 사용하여 이전에 할당 된 값을 수정할 수 있습니다.
예를 들어 다음을 사용하여 설정 flag
한 객체 일 수 있습니다 ..value
setattr
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
위의 테마에 맞추고 싶다면 setattr
다음 대신 목록 이해력을 사용할 수 있습니다 .
[None for flag.value in [bool(o.name)]]
그러나 실제로 심각한 코드에서는 lambda
외부 할당을 수행 하려는 경우 대신 항상 정규 함수 정의를 사용해야 합니다.
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)
filter
/ lambda
표현식 에서 상태를 실제로 유지할 수 없습니다 (전역 네임 스페이스를 남용하지 않는 한). 그러나 reduce()
표현식 에서 전달되는 누적 결과를 사용하여 비슷한 것을 얻을 수 있습니다 .
>>> f = lambda a, b: (a.append(b) or a) if (b not in a) else a
>>> input = ["foo", u"", "bar", "", "", "x"]
>>> reduce(f, input, [])
['foo', u'', 'bar', 'x']
>>>
물론 조건을 약간 조정할 수 있습니다. 이 경우 중복을 필터링하지만 a.count("")
예를 들어를 사용하여 빈 문자열 만 제한 할 수도 있습니다 .
말할 필요도없이, 당신은 이것을 할 수 있지만 정말로해서는 안됩니다. :)
마지막으로 순수한 Python으로 무엇이든 할 수 있습니다lambda
. http://vanderwijk.info/blog/pure-lambda-calculus-python/
null을 모두 제거 하고 입력 크기가 변경되면 다시 넣을 수있는 경우 람다를 사용할 필요가 없습니다 .
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = [x for x in input if x.name]
if(len(input) != len(output)):
output.append(Object(name=""))
및 친구들과 다양한 트릭을 수행하는 것은 가능하지만 표현식 =
내에서는 일반 할당 ( )이 불가능합니다 .lambda
setattr
그러나 문제를 해결하는 것은 실제로 매우 간단합니다.
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input
)
당신에게 줄 것입니다
[Object(Object(name=''), name='fake_name')]
보시다시피 마지막 인스턴스 대신 첫 번째 빈 인스턴스를 유지합니다. 대신 마지막이 필요하면로 들어가는 filter
목록을 뒤집고에서 나오는 목록을 뒤집습니다 filter
.
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input[::-1]
)[::-1]
당신에게 줄 것입니다
[Object(name='fake_name'), Object(name='')]
한 가지 알아야 할 : 임의의 객체와 작업이 순서대로 해당 개체가 제대로 구현해야 __eq__
하고 __hash__
같은 설명 여기 .
업데이트 :
[o for d in [{}] for o in lst if o.name != "" or d.setdefault("", o) == o]
또는 사용 filter
과 lambda
:
flag = {}
filter(lambda o: bool(o.name) or flag.setdefault("", o) == o, lst)
이전 답변
좋습니다. 필터와 람다를 계속 사용하고 있습니까?
이것은 사전 이해력과 함께 제공되는 것이 더 나을 것 같습니다.
{o.name : o for o in input}.values()
저는 파이썬이 람다에서 할당을 허용하지 않는 이유가 이해에서 할당을 허용하지 않는 이유와 비슷하다고 생각합니다. 그리고 그것은 이러한 것들이 C
측면에서 평가되어 우리에게 줄 수 있다는 사실 과 관련이 있습니다. 속도 증가. 적어도 그것은 귀도의 에세이 중 하나를 읽은 후의 인상 입니다.
내 생각 엔 이것은 또한 가지고있는 철학에 갈 것입니다 하나의 파이썬에서 어떤 한 가지 일을 올바른 방법.
대신 flag = True
가져 오기를 수행 할 수 있다면 이것이 기준을 충족한다고 생각합니다.
>>> from itertools import count
>>> a = ['hello', '', 'world', '', '', '', 'bob']
>>> filter(lambda L, j=count(): L or not next(j), a)
['hello', '', 'world', 'bob']
또는 필터가 다음과 같이 더 잘 작성 될 수 있습니다.
>>> filter(lambda L, blank_count=count(1): L or next(blank_count) == 1, a)
또는 가져 오기가없는 단순한 부울의 경우 :
filter(lambda L, use_blank=iter([True]): L or next(use_blank, False), a)
요약 : 기능적 관용구를 사용할 때는 기능적 코드를 작성하는 것이 좋습니다.
많은 사람들이 지적했듯이 Python에서는 람다 할당이 허용되지 않습니다. 일반적으로 기능적 관용구를 사용할 때 기능적 방식으로 생각하는 것이 좋습니다. 즉, 가능한 한 부작용이나 할당이 없다는 것을 의미합니다.
다음은 람다를 사용하는 기능적 솔루션입니다. fn
명확성 을 위해 람다를 할당했습니다 (조금 길기 때문에).
from operator import add
from itertools import ifilter, ifilterfalse
fn = lambda l, pred: add(list(ifilter(pred, iter(l))), [ifilterfalse(pred, iter(l)).next()])
objs = [Object(name=""), Object(name="fake_name"), Object(name="")]
fn(objs, lambda o: o.name != '')
목록을 변경하는 대신 반복자를 사용하여이 거래를 수행 할 수도 있습니다. 수입품도 약간 다릅니다.
from itertools import chain, islice, ifilter, ifilterfalse
fn = lambda l, pred: chain(ifilter(pred, iter(l)), islice(ifilterfalse(pred, iter(l)), 1))
언제든지 코드를 재구성하여 명령문의 길이를 줄일 수 있습니다.
반복하는 동안 상태를 추적하는 파이썬적인 방법은 생성기를 사용하는 것입니다. itertools 방식은 IMHO를 이해하기가 매우 어렵고이를 위해 람다를 해킹하는 것은 어리석은 일입니다. 나는 시도 할 것이다 :
def keep_last_empty(input):
last = None
for item in iter(input):
if item.name: yield item
else: last = item
if last is not None: yield last
output = list(keep_last_empty(input))
전반적으로 가독성은 항상 간결함을 능가합니다.
아니요, 자체 정의로 인해 람다 안에 할당을 넣을 수 없습니다. 함수형 프로그래밍을 사용하여 작업하는 경우 값이 변경되지 않는다고 가정해야합니다.
한 가지 해결책은 다음 코드입니다.
output = lambda l, name: [] if l==[] \
else [ l[ 0 ] ] + output( l[1:], name ) if l[ 0 ].name == name \
else output( l[1:], name ) if l[ 0 ].name == "" \
else [ l[ 0 ] ] + output( l[1:], name )
호출 사이의 상태를 기억하기 위해 람다가 필요한 경우 로컬 네임 스페이스에 선언 된 함수 또는 오버로드 된 __call__
. 이제 당신이하려는 일에 대한 나의 모든주의가 방해가 되었으니, 우리는 당신의 질문에 대한 실제 답을 얻을 수 있습니다.
호출 사이에 메모리를 확보하기 위해 람다가 정말로 필요하다면 다음과 같이 정의 할 수 있습니다.
f = lambda o, ns = {"flag":True}: [ns["flag"] or o.name, ns.__setitem__("flag", ns["flag"] and o.name)][0]
그럼 그냥 통과해야 f
으로 filter()
. 정말로 필요한 경우 flag
다음 을 통해의 가치를 되 찾을 수 있습니다 .
f.__defaults__[0]["flag"]
또는의 결과를 수정하여 전역 네임 스페이스를 수정할 수 있습니다 globals()
. 불행히도 결과를 수정 locals()
해도 로컬 네임 스페이스에 영향 을 주지 않는 것과 같은 방식으로 로컬 네임 스페이스를 수정할 수 없습니다 .
bind 함수를 사용하여 의사 다중 문 람다를 사용할 수 있습니다. 그런 다음 플래그에 래퍼 클래스를 사용하여 할당을 활성화 할 수 있습니다.
bind = lambda x, f=(lambda y: y): f(x)
class Flag(object):
def __init__(self, value):
self.value = value
def set(self, value):
self.value = value
return value
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
flag = Flag(True)
output = filter(
lambda o: (
bind(flag.value, lambda orig_flag_value:
bind(flag.set(flag.value and bool(o.name)), lambda _:
bind(orig_flag_value or bool(o.name))))),
input)
먼저, 당신은 당신의 직업을 위해 지역 할당을 사용할 필요가 없습니다, 위의 대답을 확인하십시오
둘째, locals () 및 globals ()를 사용하여 변수 테이블을 얻은 다음 값을 변경하는 것이 간단합니다.
이 샘플 코드를 확인하십시오.
print [locals().__setitem__('x', 'Hillo :]'), x][-1]
환경에 전역 변수 추가를 변경해야하는 경우 locals () 를 globals () 로 바꾸십시오.
파이썬의 목록 작성은 멋지지만 대부분의 triditional 프로젝트는 이것을 받아들이지 않습니다 (예 : 플라스크 : [)
도움이 되길 바랍니다
참고 URL : https://stackoverflow.com/questions/6282042/assignment-inside-lambda-expression-in-python
'IT' 카테고리의 다른 글
지난주 데이터를 선택하는 MySQL 쿼리? (0) | 2020.09.04 |
---|---|
Node.js 앱은 포트를 차단하는 다른 프로세스가 없더라도 포트 80에서 사용할 수 없습니다. (0) | 2020.09.04 |
Android SDK AsyncTask doInBackground가 실행되지 않음 (하위 클래스) (0) | 2020.09.04 |
CSS를 사용하여 모든 요소에 너비를 제공하는 방법은 무엇입니까? (0) | 2020.09.04 |
osx mavericks에 "gem install therubyracer -v '0.10.2'"가 설치되지 않았습니다. (0) | 2020.09.04 |