"if x : return x"문을 피하는 파이썬 방식
특정 조건을 확인하기 위해 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 가지 검사 방법이 비쌀 수 있으므로 여러 번 호출하고 싶지 않습니다.
루프를 사용할 수 있습니다 :
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)
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
바꾸지 마
다양한 다른 답변이 보여주는 것처럼이 작업을 수행하는 다른 방법이 있습니다. 원래 코드만큼 명확한 것은 없습니다.
효과적으로 timgeb와 같은 대답이지만 더 나은 형식을 위해 괄호를 사용할 수 있습니다.
def check_all_the_things():
return (
one()
or two()
or five()
or three()
or None
)
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
이것은 피합니다 :
- 복잡한 논리 구조
- 정말 긴 줄
- 되풀이
... 선형적이고 읽기 쉬운 흐름을 유지하면서.
특정 상황에 따라 더 나은 기능 이름을 얻을 수도 있습니다.
이것은 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
.
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는 꽤 부드럽게 읽습니다.
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는 iterable의 업데이트 값입니다. 선택적 이니셜 라이저가 있으면 계산에서 이터 러블 항목 앞에 배치됩니다.
귀하의 경우 :
lambda a, f: a or f()
검사 어큐뮬레이터 어느 것이 그 함수a
또는 현재 체크f()
된다True
. 경우에 유의a
하다True
,f()
평가되지 않습니다.checks
점검 기능 포함 (f
람다 의 항목)False
초기 값입니다. 그렇지 않으면 검사가 수행되지 않으며 결과는 항상True
any
및 reduce
기능 프로그래밍을위한 기본적인 도구이다. 나는 당신이 이것들을 훈련시키는 것도 강력히 권장합니다 map
.
동일한 코드 구조를 원한다면 삼항 문장을 사용할 수 있습니다!
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
나는 당신이 그것을 보면 잘 보이고 분명하다고 생각합니다.
데모:
나에게 가장 좋은 대답은 @ 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
. 사용하여 func
와 all_conditions
같은 기본 값, 당신은 사용할 수 있습니다 assessed_x(x)
, 또는 당신은을 통해 더욱 개인화 된 발전기를 전달할 수 있습니다 func
.
이렇게하면 x
한 번의 확인이 통과 되더라도 항상 같은 유형이됩니다.
이상적으로는 check_
반환 값 True
이나 False
값이 아닌 함수를 다시 작성합니다 . 그런 다음 수표가됩니다
if check_size(x):
return x
#etc
당신 x
이 불변이 아니라고 가정하면 , 함수는 여전히 그것을 재 할당 할 수는 없지만 수정할 수는 있지만 호출 된 함수는 check
실제로 수정해서는 안됩니다.
위의 Martijns 첫 번째 예제에서 약간의 변형으로 루프 내부의 if를 피할 수 있습니다.
Status = None
for c in [check_size, check_color, check_tone, check_flavor]:
Status = Status or c();
return Status
이 방법은 상자 밖에서는 약간이지만 최종 결과는 간단하고 읽기 쉽고 멋지게 보입니다.
기본 아이디어는 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 방법은 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
나는 @timgeb를 좋아한다. 그 동안 내가 표현하는 것을 추가 할 None
에 return
문 것은의 컬렉션으로 필요하지 않습니다 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
나는 여기서 뛰어 들어 한 줄의 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
또는 사용 max
:
def check_all_conditions():
return max(check_size(), check_color(), check_tone(), check_flavor()) or None
나는 과거에 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
하고 테스트 수를 변경 하고 s
예를 들어 k='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
- 나는 이것을 pep8이 아니라 문장 대신 하나의 간결한 설명 단어를 사용한다는 의미입니다. OP가 일부 코딩 규칙에 따라 기존 코드베이스 중 하나를 작동하거나 코드베이스의 간결한 용어를 신경 쓰지 않을 수 있습니다.
참고 URL : https://stackoverflow.com/questions/36117583/pythonic-way-to-avoid-if-x-return-x-statements
'Programing' 카테고리의 다른 글
스위프트는 Objective-C의“@synchronized”와 어떤 기능을합니까? (0) | 2020.04.25 |
---|---|
setDrawerListener 메소드는 추천되지 않습니다 (0) | 2020.04.25 |
SQL Server에서 왼쪽 조인과 오른쪽 조인의 차이점 (0) | 2020.04.25 |
범위를 벗어난 배열에 액세스하는 것이 얼마나 위험합니까? (0) | 2020.04.25 |
Express 4.0으로 파일 업로드 : req.files undefined (0) | 2020.04.25 |