"if x : return x"문을 피하는 파이썬 방식


218

특정 조건을 확인하기 위해 4 개의 다른 방법을 순서대로 호출하고 Truthy를 반환 할 때마다 즉시 (다음 중 하나를 확인하지 않음) 반환하는 방법이 있습니다.

def check_all_conditions():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

이것은 많은 수하물 코드처럼 보입니다. 각 2 줄 if 문 대신 다음과 같이하십시오.

x and return x

그러나 그것은 잘못된 파이썬입니다. 여기에 간단하고 우아한 솔루션이 누락 되었습니까? 또한이 상황에서 4 가지 검사 방법이 비쌀 수 있으므로 여러 번 호출하고 싶지 않습니다.


7
이 x는 무엇입니까? 그것들은 단지 True / False입니까, 아니면 데이터가 없음을 나타내는 특별한 경우로 None 또는 이와 유사한 정보가 포함 된 일부 정보를 포함하는 데이터 구조입니까? 후자 인 경우 거의 예외를 사용해야합니다.
Nathaniel

13
@gerrit 위에 제시된 코드는 코드 검토에서 주제가 아닌 가상 / 의사 코드입니다. 게시물 작성자가 실제 실제 작업 코드를 검토 하기를 원한다면 코드 검토에 게시 할 수 있습니다.
Phrancis

4
x and return x보다 낫다고 생각 if x: return x합니까? 후자는 훨씬 더 읽기 쉽고 유지 관리가 가능합니다. 문자 나 줄 수에 대해 너무 걱정하지 않아도됩니다. 가독성이 중요합니다. 어쨌든 정확히 같은 수의 비 공백 문자이며 실제로 필요한 경우 if x: return x한 줄만으로도 잘 작동합니다.
marcelm

3
실제 값에 관심이 있는지 아니면 부울을 반환해야하는지 명확히하십시오. 이는 어떤 옵션을 사용할 수 있는지와 의도를보다 명확하게 전달하는 옵션을 차별화합니다. 이름은 부울 만 필요하다는 것을 나타냅니다. 또한 이러한 함수를 여러 번 호출하지 않는 것이 중요한지 여부를 결정합니다. 함수가 다른 매개 변수 집합을 사용하는지 여부도 중요합니다. 이러한 설명이 없으면이 질문이 불분명하거나 너무 광범위하거나 의견에 근거한 것으로 생각됩니다.
jpmc26

7
@ jpmc26 OP는 명시 적으로 진실한 반환 값을 말한 다음 그의 코드가 x(와 반대로 bool(x)) 반환 하므로 OP의 함수가 무엇이든 반환 할 수 있다고 가정하는 것이 안전하다고 생각합니다.
timgeb

답변:


278

루프를 사용할 수 있습니다 :

conditions = (check_size, check_color, check_tone, check_flavor)
for condition in conditions:
    result = condition()
    if result:
        return result

이는 이제 조건 수를 변수로 만들 수 있다는 이점이 있습니다.

당신은 사용할 수 map()+ filter()(사용, 파이썬 3 버전을 future_builtins버전 최초의 일치하는 값을 얻기 위해 파이썬 2 일) :

try:
    # Python 2
    from future_builtins import map, filter
except ImportError:
    # Python 3
    pass

conditions = (check_size, check_color, check_tone, check_flavor)
return next(filter(None, map(lambda f: f(), conditions)), None)

그러나 이것이 더 읽기 쉬운 것은 논쟁의 여지가 있습니다.

또 다른 옵션은 생성기 표현식을 사용하는 것입니다.

conditions = (check_size, check_color, check_tone, check_flavor)
checks = (condition() for condition in conditions)
return next((check for check in checks if check), None)

27
조건이 실제로 조건 일 경우, 즉 부울 인 경우 첫 번째 제안 any에서 루프 대신 내장을 사용할 수도 있습니다 . return any(condition() for condition in conditions)

4
@ Leonhard : any내부와 거의 동일한 구현이 있습니다. 그러나 그것은 훨씬 나아 보인다, 답변으로 게시하십시오)
Nick Volynkin

13
가독성은 다른 모든 고려 사항보다 우선합니다. 당신은지도 / 필터가 '논쟁의 여지가있다'라고 말하면서, 나는 틀림없이 추악한 투표를했습니다. 고마워요.하지만 팀의 누군가가이 코드에 대해 맵 / 필터를 넣은 경우 다른 팀으로 옮기거나 잠자리에 넘기 게됩니다.
Kevin J. Rice

15
읽을 수없는 코드 블록은 실제로 "파이썬 식"입니까? 특히 압축하는의 아이디어 conditionsarguments? 이것은 내 뇌 파서에 의해 구문 분석하는 데 약 10 초가 걸리는 원래 코드보다 훨씬 나쁩니다.
yo '

34
"Python을 선호한다"고 그들은 말했다. "펄은 읽을 수 없다"고 그들은 말했다. 그리고 이것은 일어났다 : return next((check for check in checks if check), None).
jja

393

Martijn의 정답 대신 체인을 연결할 수 or있습니다. 첫 번째 진실 된 값을 반환하거나 None진실 된 가치가없는 경우 :

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor() or None

데모:

>>> x = [] or 0 or {} or -1 or None
>>> x
-1
>>> x = [] or 0 or {} or '' or None
>>> x is None
True

9
물론, 몇 가지 이상의 옵션이 있으면 빨리 읽는 것이 지루할 것입니다. 또한 내 접근 방식으로 다양한 조건을 사용할 수 있습니다.
Martijn Pieters

14
@MartijnPieters 당신은 \자신의 라인에 각 수표를 넣을 수 있습니다 .
Caridorc

12
@MartijnPieters 나는 내 대답이 당신보다 낫다는 것을 암시하지 않았다. 나는 너의 대답도 좋아한다 :)
timgeb

38
@Caridorc : 나는 \논리적 인 라인을 확장하기 위해 사용하는 것을 싫어 한다. 가능한 경우 괄호를 사용하십시오. 그래서 return (....)필요에 따라 줄 바꿈 삽입. 여전히, 그것은 하나의 긴 논리적 인 선이 될 것입니다.
Martijn Pieters

47
이것이 더 나은 해결책이라고 생각합니다. 하나의 함수가 어쨌든 엄청난 수의 검사를 수행해서는 안되기 때문에 "몇 개 이상의 옵션이있는 경우 지루한 [..]을 얻는다" 라는 주장 은 무의미하다. 이것이 필요한 경우, 점검은 여러 기능으로 분할되어야합니다.
BlueRaja-대니 Pflughoeft

88

바꾸지 마

다양한 다른 답변이 보여주는 것처럼이 작업을 수행하는 다른 방법이 있습니다. 원래 코드만큼 명확한 것은 없습니다.


39
나는 그것에 반박 할 것이지만, 당신의 제안은 합법적이라고 할 수 있습니다. 개인적으로, 나는 예를 들어 timgeb의 솔루션이 즉시 클릭하는 것과 같이 OP를 읽으려고 노력하면서 눈이 피로 해졌습니다.
Reti43

3
정말 의견의 문제입니다. 나 개인적으로, 나는 꽤 괜찮은 :것으로 간주 if x: return x하기 때문에 개행을 제거 하고 함수를보다 컴팩트하게 만듭니다. 그러나 그것은 단지 나일 수 있습니다.
yo '

2
당신 만이 아닙니다. ortimgeb처럼 사용 하는 것은 적절하고 잘 이해되는 관용구입니다. 많은 언어들이 이것을 가지고 있습니다. 아마도이 호출 될 때 orelse그것은 더욱 분명하지만, 옛날에도 보통이다 or(또는 ||다른 언어로)되는 것을 의미 첫 번째가한다면, 시도 할 대안으로 이해되어야한다 "일을하지 않습니다."
Ray Toal

1
@RayToal : 다른 언어에서 관용구를 가져 오는 것은 코드를 난독 처리하는 좋은 방법입니다.
Jack Aidley

1
때로는 그렇습니다. 또한 사람의 마음을 열고 아무도 전에 시도해 보지 못한 새롭고 더 나은 패턴과 패러다임을 발견하도록 이끌 수 있습니다. 스타일은 사람들이 새로운 것을 빌려 공유하고 시도함으로써 진화합니다. 두 가지 방식으로 작동합니다. 어쨌든, 나는 or비 Pythonic이라는 레이블 이 붙어 있거나 난독 화 된 방식 의 사용을 들어 본 적이 없지만, 어쨌든 그것은 의견의 문제입니다.
Ray Toal

83

효과적으로 timgeb와 같은 대답이지만 더 나은 형식을 위해 괄호를 사용할 수 있습니다.

def check_all_the_things():
    return (
        one()
        or two()
        or five()
        or three()
        or None
    )

8
모두이 답변을 1 위까지 올리는 데 도움을주십시오. 당신의 역할을!
Gyom

74

Curly의 법칙 에 따르면 두 가지 우려를 나누면이 코드를 더 읽기 쉽게 만들 수 있습니다.

  • 무엇을 확인해야합니까?
  • 한 가지 사실이 돌아왔습니까?

두 가지 기능으로

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions():
    for condition in all_conditions():
        if condition:
            return condition
    return None

이것은 피합니다 :

  • 복잡한 논리 구조
  • 정말 긴 줄
  • 되풀이

... 선형적이고 읽기 쉬운 흐름을 유지하면서.

특정 상황에 따라 더 나은 기능 이름을 얻을 수도 있습니다.


True / False가 질문과 일치하도록 condition / None으로 변경되어야하지만이 것을 좋아합니다.
Malcolm

2
이것은 내가 가장 좋아하는 것입니다! 그것은 다른 점검과 논쟁에도 대처합니다. 이 특정 예제를 위해 과도하게 디자인되었지만 미래의 문제에 유용한 도구입니다!
rjh

4
return None함수는 반환하기 때문에 필요하지 않습니다 None기본적으로. 그러나 None명시 적 으로 반환하는 데 아무런 문제가 없으며 그렇게하기로 결정한 것이 좋습니다.
timgeb

1
이 접근법은 로컬 함수 정의로 더 잘 구현 될 것이라고 생각합니다.
Jack Aidley

1
@timgeb "명시적인 것이 묵시적인 것보다 낫다" Zen of Python .
jpmc26

42

이것은 Martijns의 첫 번째 예의 변형입니다. 또한 단락을 허용하기 위해 "콜 러블 컬렉션"스타일을 사용합니다.

루프 대신 내장을 사용할 수 있습니다 any.

conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions) 

any부울 을 반환하므로 확인의 정확한 반환 값이 필요한 경우이 솔루션이 작동하지 않습니다. any구분하지 않습니다 14, 'red', 'sharp', 'spicy'반환 값으로, 그들은 모두 반환됩니다 True.


당신은 할 수있는 next(itertools.ifilter(None, (c() for c in conditions)))부울로 캐스팅없이 실제 값을 얻을 수 있습니다.
kojiro

1
any실제로 단락 합니까 ?
zwol

1
@zwol 네, 샘플 기능을 사용해 보거나 docs.python.org/3/library/functions.html을

1
이것은 4 개의 함수를 '또는'으로 연결하는 것보다 읽기 쉽지 않으며 조건 수가 크거나 동적 인 경우에만 지불합니다.
rjh

1
@rjh 완벽하게 읽을 수 있습니다. 그것은 단지 목록 리터럴과 이해입니다. 나는 3 시경 이후 눈이 유약하기 때문에 선호합니다x = bar(); if x: return x;
Blacklight Shining

27

if x: return x한 줄에 모두 쓰는 것을 고려해 보셨습니까 ?

def check_all_conditions():
    x = check_size()
    if x: return x

    x = check_color()
    if x: return x

    x = check_tone()
    if x: return x

    x = check_flavor()
    if x: return x

    return None

이것은 당신이 가진 것보다 덜 반복적 이지 는 않지만 IMNSHO는 꽤 부드럽게 읽습니다.


24

any이 목적을 위해 만들어진 내장 기능을 언급 한 사람이 아무도 없습니다 .

def check_all_conditions():
    return any([
        check_size(),
        check_color(),
        check_tone(),
        check_flavor()
    ])

이 구현은 아마도 가장 분명하지만 첫 번째 검사가하더라도 모든 검사를 평가합니다 True.


첫 번째 실패한 검사에서 실제로 중지해야하는 경우 reduce목록을 간단한 값으로 변환하기 위해 사용 되는 것을 사용하십시오 .

def check_all_conditions():
    checks = [check_size, check_color, check_tone, check_flavor]
    return reduce(lambda a, f: a or f(), checks, False)

reduce(function, iterable[, initializer]): 반복 가능한 항목에 왼쪽에서 오른쪽으로 두 인수의 함수를 누적 적용하여 반복 가능한 값을 단일 값으로 줄입니다. 왼쪽 인수 x는 누적 값이고 오른쪽 인수 y는 이터 러블의 업데이트 값입니다. 선택적 이니셜 라이저가 있으면 계산에서 이터 러블 항목 앞에 배치됩니다.

귀하의 경우 :

  • lambda a, f: a or f()검사 어큐뮬레이터 어느 것이 그 함수 a또는 현재 체크 f()된다 True. 경우에 유의 a하다 True, f()평가되지 않습니다.
  • checks점검 기능 포함 ( f람다 의 항목)
  • False 초기 값입니다. 그렇지 않으면 검사가 수행되지 않으며 결과는 항상 True

anyreduce기능 프로그래밍을위한 기본적인 도구이다. 나는 당신이 이것들을 훈련시키는 것도 강력히 권장합니다 map.


9
any수표가 실제로 부울 값을 문자 그대로 True또는로 반환하는 경우에만 작동 False하지만 질문에서 해당 값을 지정하지 않습니다. reduce수표로 반환 된 실제 값을 반환하는 데 사용해야 합니다. 또한 any생성기를 사용하여 모든 검사를 평가하지 않아도됩니다 ( 예 :) any(c() for c in (check_size, check_color, check_tone, check_flavor)). Leonhard의 답변
David Z

의 설명과 사용법이 마음에 듭니다 reduce. @DavidZ와 마찬가지로 귀하의 솔루션 any은 발전기 를 사용해야 한다고 생각 하며, True또는 로 돌아 오는 것으로 제한되어야 False합니다.
timgeb

1
@DavidZ 실제로 anytruthy 값으로 작동합니다 : any([1, "abc", False]) == Trueany(["", 0]) == False
ngasull

3
@blint 죄송합니다. 명확하지 않았습니다. 질문의 목표는 점검 결과리턴하는 것입니다 (단, 점검의 성공 여부 만 나타내는 것이 아님). 실제 부울 값이 check 함수에서 반환되면 해당 목적으로 any만 작동 한다는 것을 지적했습니다 .
David Z

19

동일한 코드 구조를 원한다면 삼항 문장을 사용할 수 있습니다!

def check_all_conditions():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

나는 당신이 그것을 보면 잘 보이고 분명하다고 생각합니다.

데모:

실행중인 스크린 샷


7
터미널 위의 작은 ASCII 물고기는 무엇입니까?

36
@LegoStormtroopr 나는 생선 껍질을 사용하므로 행복하게하기 위해 ascii 어항으로 장식합니다. :)
Phinet

3
좋은 물고기 (그리고 색은 어떤 편집기입니까?)에 감사드립니다
mathreadler

4
당신은에서 물고기를 얻을 수 fishshell.com 하고, 여기에 아스키의 설정 파일 pastebin.com/yYVYvVeK는 또한 편집기는 숭고한 텍스트입니다.
Phinet

9
x if x else <something>다음으로 축소 가능x or <something>

5

나에게 가장 좋은 대답은 @ phil-frost의 @ wayne-werner 's입니다.

내가 흥미로운 점은 함수가 많은 다른 데이터 유형을 반환한다는 사실에 대해 아무도 말하지 않았기 때문에 추가 작업을 수행하기 위해 x 자체의 유형을 검사해야한다는 것입니다.

따라서 @PhilFrost의 응답을 단일 유형을 유지한다는 아이디어와 혼합합니다.

def all_conditions(x):
    yield check_size(x)
    yield check_color(x)
    yield check_tone(x)
    yield check_flavor(x)

def assessed_x(x,func=all_conditions):
    for condition in func(x):
        if condition:
            return x
    return None

공지 사항 x또한 인수로 전달되지만,이 all_conditions모두가 얻을 어디에 기능을 확인하는 통과 발전기로 사용되는 x확인하고, 반환 True또는 False. 사용하여 funcall_conditions같은 기본 값, 당신은 사용할 수 있습니다 assessed_x(x), 또는 당신은을 통해 더욱 개인화 된 발전기를 전달할 수 있습니다 func.

이렇게하면 x한 번의 확인이 통과 되더라도 항상 같은 유형이됩니다.


4

이상적으로는 check_ 반환 값 True이나 False값이 아닌 함수를 다시 작성합니다 . 그런 다음 수표가됩니다

if check_size(x):
    return x
#etc

당신 x이 불변이 아니라고 가정하면 , 함수는 여전히 그것을 재 할당 할 수는 없지만 수정할 수는 있지만 호출 된 함수는 check실제로 수정해서는 안됩니다.


3

위의 Martijns 첫 번째 예제에서 약간의 변형으로 루프 내부의 if를 피할 수 있습니다.

Status = None
for c in [check_size, check_color, check_tone, check_flavor]:
  Status = Status or c();
return Status

그렇습니까? 당신은 여전히 ​​비교를합니다. 당신의 버전에서는 당신은 모든 값을 확인하고 진실한 값의 첫 번째 인스턴스에서 반환하지 않을 것입니다. 그 기능의 비용에 따라, 바람직하지 않을 수도 있습니다.
Reti43

4
@ Reti43 : 진실한 경우 Status or c()호출을 건너 뛰거나 짧게 평가 하므로이 답변의 코드는 OP의 코드보다 더 많은 함수를 호출하지 않는 것으로 보입니다. stackoverflow.com/questions/2580136/…c()Status
닐 슬레이터 2013 년

2
@NeilSlater True입니다. 내가 볼 수있는 유일한 단점은 첫 번째 함수가 O (1)에서 진실한 것을 반환하기 전에 O (1)이었을 때 listiterator가 n 번을 산출해야하기 때문에 가장 좋은 경우는 이제 O (n)에 있다는 것입니다.
timgeb

1
네 좋은 지적입니다. c ()가 거의 비어있는 루프를 반복하는 것보다 평가하는 데 약간의 시간이 더 걸리기를 바랍니다. 풍미를 확인하는 것은 좋은 저녁이라면 적어도 하루 종일 걸릴 수 있습니다.
mathreadler

3

나는 @timgeb를 좋아한다. 그 동안 내가 표현하는 것을 추가 할 Nonereturn문 것은의 컬렉션으로 필요하지 않습니다 or분리 문이 평가하는 첫 번째 없음 제로는, 아무도 비어가 없음 - 없음 반환 된 후 어떤 존재하지 않는 경우 None반환됩니다 있는지 여부None !

check_all_conditions()기능은 다음과 같습니다.

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor()

timeit함께 사용 하면서 number=10**7여러 제안의 실행 시간을 보았습니다. 비교를 위해 방금 random.random()문자열을 반환하거나 None임의의 숫자를 기반으로 함수를 사용했습니다 . 전체 코드는 다음과 같습니다.

import random
import timeit

def check_size():
    if random.random() < 0.25: return "BIG"

def check_color():
    if random.random() < 0.25: return "RED"

def check_tone():
    if random.random() < 0.25: return "SOFT"

def check_flavor():
    if random.random() < 0.25: return "SWEET"

def check_all_conditions_Bernard():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

def check_all_Martijn_Pieters():
    conditions = (check_size, check_color, check_tone, check_flavor)
    for condition in conditions:
        result = condition()
        if result:
            return result

def check_all_conditions_timgeb():
    return check_size() or check_color() or check_tone() or check_flavor() or None

def check_all_conditions_Reza():
    return check_size() or check_color() or check_tone() or check_flavor()

def check_all_conditions_Phinet():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions_Phil_Frost():
    for condition in all_conditions():
        if condition:
            return condition

def main():
    num = 10000000
    random.seed(20)
    print("Bernard:", timeit.timeit('check_all_conditions_Bernard()', 'from __main__ import check_all_conditions_Bernard', number=num))
    random.seed(20)
    print("Martijn Pieters:", timeit.timeit('check_all_Martijn_Pieters()', 'from __main__ import check_all_Martijn_Pieters', number=num))
    random.seed(20)
    print("timgeb:", timeit.timeit('check_all_conditions_timgeb()', 'from __main__ import check_all_conditions_timgeb', number=num))
    random.seed(20)
    print("Reza:", timeit.timeit('check_all_conditions_Reza()', 'from __main__ import check_all_conditions_Reza', number=num))
    random.seed(20)
    print("Phinet:", timeit.timeit('check_all_conditions_Phinet()', 'from __main__ import check_all_conditions_Phinet', number=num))
    random.seed(20)
    print("Phil Frost:", timeit.timeit('check_all_conditions_Phil_Frost()', 'from __main__ import check_all_conditions_Phil_Frost', number=num))

if __name__ == '__main__':
    main()

결과는 다음과 같습니다.

Bernard: 7.398444877040768
Martijn Pieters: 8.506569201346597
timgeb: 7.244275416364456
Reza: 6.982133448743038
Phinet: 7.925932800076634
Phil Frost: 11.924794811353031

2

이 방법은 상자 밖에서는 약간 있지만 최종 결과는 간단하고 읽기 쉽고 멋지게 보입니다.

기본 아이디어는 raise함수 중 하나가 진실한 것으로 평가되어 결과를 반환 할 때 예외입니다. 다음과 같이 보일 수 있습니다.

def check_conditions():
    try:
        assertFalsey(
            check_size,
            check_color,
            check_tone,
            check_flavor)
    except TruthyException as e:
        return e.trigger
    else:
        return None

assertFalsey호출 된 함수 인수 중 하나가 진실로 평가 될 때 예외를 발생 시키는 함수가 필요합니다 .

def assertFalsey(*funcs):
    for f in funcs:
        o = f()
        if o:
            raise TruthyException(o)

위의 내용은 평가할 기능에 대한 인수를 제공하도록 수정 될 수 있습니다.

그리고 물론 당신은 TruthyException그 자체 가 필요합니다 . 이 예외는 예외 object를 트리거 한 것을 제공합니다 .

class TruthyException(Exception):
    def __init__(self, obj, *args):
        super().__init__(*args)
        self.trigger = obj

물론 원래 기능을 좀 더 일반적인 것으로 바꿀 수 있습니다.

def get_truthy_condition(*conditions):
    try:
        assertFalsey(*conditions)
    except TruthyException as e:
        return e.trigger
    else:
        return None

result = get_truthy_condition(check_size, check_color, check_tone, check_flavor)

if명령문을 사용 하고 예외를 처리 하므로 약간 느려질 수 있습니다 . 그러나 예외는 최대 한 번만 처리되므로 확인을 실행하고 True수천 번 값을 얻을 것으로 예상하지 않는 한 성능에 대한 적중은 적어야합니다 .


// , 귀엽다! 이런 종류의 예외 처리를 사용하는 것이 "Pythonic"으로 간주됩니까?
Nathan Basanese 2016 년

@NathanBasanese 물론 예외는 항상 제어 흐름에 사용됩니다. StopIteration꽤 좋은 예입니다 : 반복 가능을 소진 할 때마다 예외가 발생합니다. 피하고 싶은 것은 계속해서 예외를 반복해서 발생시키는 것인데, 이는 비싸 질 것입니다. 그러나 한 번만하는 것은 아닙니다.
Rick은 Monica

//, 아, 나는 당신이 programmers.stackexchange.com/questions/112463/… 같은 것을 언급한다고 생각 합니다 . 그 질문과이 답변에 투표했습니다. 이에 대한 Python 3 문서는 다음과 같습니다. docs.python.org/3/library/stdtypes.html#iterator-types , 나는 생각합니다.
Nathan Basanese

1
어딘가 다른 함수에서 몇 가지 검사를 수행하기 위해 범용 함수와 예외를 정의하고 싶습니까? 나는 그것이 조금 많은 것 같아요.
Blacklight Shining

@BacklightShining 동의합니다. 나는 실제로 이것을 직접하지 않을 것입니다. OP는 반복되는 코드를 피할 수있는 방법을 요구했지만 그가 시작한 것은 완벽하다고 생각합니다.
Rick은 Monica

2

pythonic 방법은 reduce (이미 언급 한 것처럼) 또는 itertools (아래에 표시된 것처럼)를 사용하지만 연산자의 단락을 사용 or하면 더 명확한 코드가 생성 되는 것으로 보입니다.

from itertools import imap, dropwhile

def check_all_conditions():
    conditions = (check_size,\
        check_color,\
        check_tone,\
        check_flavor)
    results_gen = dropwhile(lambda x:not x, imap(lambda check:check(), conditions))
    try:
        return results_gen.next()
    except StopIteration:
        return None

0

나는 여기서 뛰어 들어 한 줄의 Python을 작성하지 않았지만 if x = check_something(): return x유효 하다고 가정 합니다.

그렇다면:

def check_all_conditions():

    if (x := check_size()): return x
    if (x := check_color()): return x
    if (x := check_tone()): return x
    if (x := check_flavor()): return x

    return None

1
유효한 파이썬이 아닙니다. 파이썬은 그런 할당 연산자를 사용하도록 허용하지 않습니다. 그러나 새로운 특수 대입식이 최근에 추가되었으므로 이제 if ( x := check_size() ) :동일한 효과를 위해 쓸 수 있습니다 .
Jack Aidley

0

또는 사용 max:

def check_all_conditions():
    return max(check_size(), check_color(), check_tone(), check_flavor()) or None

-2

나는 과거에 dicts로 switch / case 문을 흥미롭게 구현 하여이 답변을 얻었습니다. 제공 한 예제를 사용하면 다음을 얻을 수 있습니다. (광기 using_complete_sentences_for_function_names이므로 check_all_conditions이름이로 변경됩니다 status. (1) 참조)

def status(k = 'a', s = {'a':'b','b':'c','c':'d','d':None}) :
  select = lambda next, test : test if test else next
  d = {'a': lambda : select(s['a'], check_size()  ),
       'b': lambda : select(s['b'], check_color() ),
       'c': lambda : select(s['c'], check_tone()  ),
       'd': lambda : select(s['d'], check_flavor())}
  while k in d : k = d[k]()
  return k

select 함수는 각각 check_FUNCTION두 번 호출 할 필요가 없습니다. 즉, check_FUNCTION() if check_FUNCTION() else next다른 함수 레이어를 추가하여 피할 수 있습니다 . 장기 실행 기능에 유용합니다. dict의 람다는 while 루프까지 값 실행을 지연시킵니다.

보너스로 당신은 실행 순서를 수정할 수 있습니다, 심지어 변경하여 시험의 일부를 생략 k하고 sk='c',s={'c':'b','b':None} 원래 처리 순서를 반대로하여 .

timeit동료는 찾아 볼하지만 당신은 더 코드의 귀여움에 관심을 보인다 별도의 층 또는 스택 2 개, DICT에 대한 비용을 추가 비용을 통해 흥정 수 있습니다.

또는 간단한 구현은 다음과 같습니다.

def status(k=check_size) :
  select = lambda next, test : test if test else next
  d = {check_size  : lambda : select(check_color,  check_size()  ),
       check_color : lambda : select(check_tone,   check_color() ),
       check_tone  : lambda : select(check_flavor, check_tone()  ),
       check_flavor: lambda : select(None,         check_flavor())}
  while k in d : k = d[k]()
  return k
  1. 나는 이것을 pep8이 아니라 문장 대신 하나의 간결한 설명 어를 사용한다는 의미입니다. OP가 일부 코딩 규칙에 따라 기존 코드베이스 중 하나를 작동하거나 코드베이스의 간결한 용어를 신경 쓰지 않을 수 있습니다.

1
때때로 사람들은 한 단어가 할 때 그들의 이름에 정말로 열중합니다. OP의 코드를 예로 사용하면 함수를 호출 할 가능성은 거의 없지만이 함수 check_no/some/even/prime/every_third/fancy_conditions만 호출하면 status됩니다 check_status. 사용 _all_은 불필요한 것이며 우주의 무결성을 보장하지는 않습니다. 이름 지정은 가능할 때마다 이름 간격을 활용하여 일관된 키워드 세트를 사용해야합니다. 긴 문장은 문서 문자열로 사용하는 것이 가장 좋습니다. 간결하게 무언가를 묘사하기 위해 8-10 자 이상의 문자가 거의 필요하지 않습니다.
Carel

1
고급 함수가 자체 문서화되기를 원하기 때문에 긴 함수 이름의 팬입니다. 그러나 모든 조건을 확인 하지는check_all_conditions 않기 때문에 나쁜 이름 입니다. 나는 같은 것을 사용할 것이다 . matches_any_condition
John Hazen

그것은 재미있는 전술입니다. 나는 나중에 오타가 될 문자의 수를 최소화하려고 노력합니다. 이것을 편집해야합니까?
Carel

2
이것은 특히이 질문에 대한 다른 솔루션을 고려할 때 너무 해킹 해 보입니다. OP가 시도하는 것은 전혀 복잡하지 않습니다. 이 솔루션은 반 수면을 이해하기에 충분히 단순해야합니다. 그리고 나는 여기서 무슨 일이 일어나고 있는지 전혀 모른다.
Blacklight Shining

유연성을 목표로하고있었습니다. 덜 까다로운 변형을 포함하도록 수정 된 답변
Carel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.