나는 파이썬을 배우려고 노력하고 있는데 멋지고 짧지 만 완전히 말이되지 않는 코드를 발견했습니다.
컨텍스트는 다음과 같습니다.
def fn(*args):
return len(args) and max(args)-min(args)
나는 그것이 무엇을하고 있는지 알지만 왜 파이썬이 이것을 수행합니까-즉 True / False 대신 값을 반환합니까?
10 and 7-2
5를 반환합니다. 마찬가지로 및를 또는로 변경하면 기능이 변경됩니다. 그래서
10 or 7 - 2
10을 반환합니다.
이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?
답변
TL; DR
두 논리 연산자 and
및 의 두 동작을 요약하여 시작합니다 or
. 이러한 관용구는 아래 논의의 기초가 될 것입니다.
and
첫 번째 Falsy 값이 있으면 반환하고, 그렇지 않으면 표현식의 마지막 값을 반환합니다.
or
첫 번째 Truthy 값이 있으면 반환하고, 그렇지 않으면 식의 마지막 값을 반환합니다.
동작은 문서 , 특히이 표에 요약되어 있습니다 .
피연산자에 관계없이 부울 값을 반환하는 유일한 연산자는 not
연산자입니다.
“진실성”및 “진실성”평가
진술
len(args) and max(args) - min(args)
A는 매우 파이썬 간결 (틀림없이 적은 읽기) “하면 말하는 방법 args
비어 있지의 결과를 반환 max(args) - min(args)
그렇지 않으면 반환”는 0
. 일반적으로 표현을보다 간결하게 표현한 것입니다 if-else
. 예를 들면
exp1 and exp2
(대략) 번역해야합니다 :
r1 = exp1
if r1:
r1 = exp2
또는 동등하게
r1 = exp1 if exp1 else exp2
비슷하게,
exp1 or exp2
다음과 같습니다.
r1 = exp1
if not r1:
r1 = exp2
어디 exp1
및 exp2
일부 개체를 반환 임의의 파이썬 객체, 또는 표현입니다. 여기 에서 논리 연산자 and
와 or
연산자 의 사용을 이해하는 데있어 핵심 은 부울 값을 연산하거나 반환하는 데 제한되지 않는다는 것을 이해하는 것입니다. 진실성 값을 가진 모든 개체를 여기서 테스트 할 수 있습니다. 여기에는 int
, str
, list
, dict
, tuple
, set
, NoneType
, 및 사용자 객체를 정의했다. 단락 규칙도 여전히 적용됩니다.
그러나 진실이란 무엇입니까?
조건식에서 사용될 때 객체가 평가되는 방식을 나타냅니다. @Patrick Haugh는 이 게시물 에서 진실성을 멋지게 요약 합니다.
“허위”인 다음을 제외하고 모든 값은 “진정한”것으로 간주됩니다.
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
-빈list
{}
-빈dict
()
-빈tuple
''
-빈str
b''
-빈bytes
set()
-빈set
- 빈
range
처럼,range(0)
- 대상
obj.__bool__()
보고False
obj.__len__()
보고0
“truthy”값은
if
또는while
문에 의해 수행 된 검사를 충족합니다 . 우리는 차별화에 “truthy”와 “falsy을”사용
bool
가치True
와False
.
어떻게 and
작동
우리는 이러한 경우에 이러한 연산자가 어떻게 작동하는지에 대한 토론의 후속으로 OP의 질문을 기반으로합니다.
정의가있는 함수가 주어짐
def foo(*args): ...
0 개 이상의 인수 목록에서 최소값과 최대 값의 차이를 어떻게 반환합니까?
최소값과 최대 값을 찾는 것은 쉽습니다 (내장 함수 사용!). 여기서 유일한 문제는 인수 목록이 비어있을 수있는 코너 케이스를 적절하게 처리하는 것입니다 (예 : 호출 foo()
). and
연산자 덕분에 한 줄로 두 가지를 모두 수행 할 수 있습니다 .
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
and
이 사용 되므로 첫 번째 표현식이 인 경우 두 번째 표현식도 평가되어야합니다 True
. 첫 번째 표현식이 진실로 평가되면 반환 값은 항상 두 번째 표현식 의 결과입니다 . 첫 번째 표현식이 Falsy로 평가되면 반환 된 결과는 첫 번째 표현식의 결과입니다.
위의 함수에서 foo
하나 이상의 인수를받는 경우 는 (양수) len(args)
보다 크므 0
로 반환 된 결과는입니다 max(args) - min(args)
. 인수가 전달되지 않은 경우 OTOH, len(args)
이다 0
Falsy하고, 어떤 0
반환됩니다.
이 함수를 작성하는 다른 방법은 다음과 같습니다.
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
또는 더 간결하게
def foo(*args):
return 0 if not args else max(args) - min(args)
물론, 이러한 함수 중 어떤 것도 유형 검사를 수행 하지 않으므로 제공된 입력을 완전히 신뢰 하지 않는 한 이러한 구성의 단순성에 의존 하지 마십시오 .
어떻게 or
작동
or
인위적인 예를 들어 비슷한 방식으로 작업을 설명합니다 .
정의가있는 함수가 주어짐
def foo(*args): ...
foo
모든 숫자를 반환 하려면 어떻게 완료9000
하시겠습니까?
or
여기서 코너 케이스를 처리하는 데 사용 합니다. 우리는 다음 foo
과 같이 정의 합니다.
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
# [9004]
foo(1, 2, 3, 4)
# 'No number over 9000!'
foo
목록에서 필터링을 수행하여 모든 숫자를 유지합니다 9000
. 그러한 숫자가 있으면 목록 이해의 결과는 Truthy 인 비어 있지 않은 목록이되므로 반환됩니다 (여기에서 작동중인 단락). 그러한 숫자가 없으면 목록 comp의 결과 []
는 Falsy입니다. 이제 두 번째 표현식이 평가되고 (비어 있지 않은 문자열) 반환됩니다.
조건문을 사용하여이 함수를 다음과 같이 다시 작성할 수 있습니다.
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
이전과 마찬가지로이 구조는 오류 처리 측면에서 더 유연합니다.
답변
Python 문서 에서 인용
어느 쪽도 있음을 참고
and
하거나하는 것은or
제한하지 값을 하고 입력 그들은으로 되돌아False
와True
, 오히려 돌아 마지막에 평가 인수를 . 이것은 때로 유용합니다. 예를 들어,s
비어있는 경우 기본값으로 대체해야하는 문자열 인 경우 표현식s or 'foo'
이 원하는 값을 생성합니다.
그래서 이것은 파이썬이 부울 표현식을 평가하도록 설계된 방법이며 위의 문서는 그들이 왜 그렇게했는지에 대한 통찰력을 제공합니다.
부울 값을 얻으려면 그냥 형변환하십시오.
return bool(len(args) and max(args)-min(args))
왜?
단락.
예를 들면 :
2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all
같은 경우 or
도 마찬가지입니다. 즉, Truthy 라는 표현식을 찾으면 즉시 반환 하므로 나머지 표현식을 평가하는 것은 중복됩니다.
대신 하드 코어를 반환 True
하거나 False
, 파이썬 반환 Truthy 또는 Falsey은 , 어쨌든로 평가하려고하는 True
나 False
. 표현식을 그대로 사용할 수 있으며 여전히 작동합니다.
Truthy 와 Falsey 가 무엇인지 알아 보려면 Patrick Haugh의 답변을 확인하십시오.
답변
및 및 또는 부울 논리를 수행하지만 비교할 때 실제 값 중 하나를 반환합니다. 사용할 때 와 왼쪽에서 오른쪽으로, 값은 부울 문맥에서 평가된다. 0, ”, [], (), {} 및 None 은 부울 컨텍스트에서 false입니다. 다른 모든 것은 사실입니다.
모든 값은 부울 컨텍스트에 해당하는, 경우 와 마지막 값을 반환합니다.
>>> 2 and 5
5
>>> 2 and 5 and 10
10
값은 부울 컨텍스트에서 false 인 경우 와 첫 거짓 값을 반환합니다.
>>> '' and 5
''
>>> 2 and 0 and 5
0
그래서 코드
return len(args) and max(args)-min(args)
인수가max(args)-min(args)
있을 때 의 값을 반환하고 그렇지 않으면 0 인 값을 반환합니다 .len(args)
답변
이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?
이것은 합법적이며 마지막 값이 반환되는 단락 평가 입니다.
좋은 예를 제공합니다. 0
인수가 전달되지 않으면 함수가 반환 되며 코드는 전달 된 인수가없는 특별한 경우를 확인할 필요가 없습니다.
이것을 사용하는 또 다른 방법은 빈 목록과 같이 변경 가능한 기본 요소에 None 인수를 기본값으로 설정하는 것입니다.
def fn(alist=None):
alist = alist or []
....
참이 아닌 값이 alist
기본적으로 빈 목록으로 전달 되면 if
명령문과 변경 가능한 기본 인수 함정 을 피하는 편리한 방법
답변
Gotchas
예, 몇 가지 문제가 있습니다.
fn() == fn(3) == fn(4, 4)
첫째, fn
returns 0
이면 매개 변수없이, 하나의 매개 변수와 함께 또는 여러 개의 동일한 매개 변수를 사용하여 호출되었는지 알 수 없습니다.
>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0
무슨 fn
뜻이야?
그렇다면 Python은 동적 언어입니다. fn
무엇을하는지, 입력이 무엇인지, 출력이 어떻게 보일지 어디에도 지정되어 있지 않습니다 . 따라서 함수 이름을 올바르게 지정하는 것이 정말 중요합니다. 마찬가지로 인수를 호출 할 필요는 없습니다 args
. delta(*numbers)
또는 calculate_range(*numbers)
함수가 수행해야하는 작업을 더 잘 설명 할 수 있습니다.
인수 오류
마지막으로 논리 and
연산자는 인수없이 호출 될 경우 함수가 실패하는 것을 방지해야합니다. 그러나 일부 인수가 숫자가 아니면 여전히 실패합니다.
>>> fn('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
가능한 대안
“허가보다 용서를 구하기가 더 쉽다” 에 따라 함수를 작성하는 방법이 있습니다. 원리 :
def delta(*numbers):
try:
return max(numbers) - min(numbers)
except TypeError:
raise ValueError("delta should only be called with numerical arguments") from None
except ValueError:
raise ValueError("delta should be called with at least one numerical argument") from None
예로서:
>>> delta()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5
delta
인수없이가 호출 될 때 예외를 발생시키고 싶지 않다면, 그렇지 않으면 불가능한 값을 반환 할 수 있습니다 (예 : -1
또는 None
) :
>>> def delta(*numbers):
... try:
... return max(numbers) - min(numbers)
... except TypeError:
... raise ValueError("delta should only be called with numerical arguments") from None
... except ValueError:
... return -1 # or None
...
>>>
>>> delta()
-1
답변
이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?
이 질문에 합법적이고 신뢰할 수있을뿐만 아니라 매우 실용적이라고 덧붙이고 싶습니다. 다음은 간단한 예입니다.
>>>example_list = []
>>>print example_list or 'empty list'
empty list
따라서 실제로 유리하게 사용할 수 있습니다. 간결하게하기 위해 이것이 내가 보는 방법입니다.
Or
운영자
Python의 or
연산자는 첫 번째 Truth-y 값 또는 마지막 값을 반환하고 중지합니다.
And
운영자
Python의 and
연산자는 첫 번째 False-y 값 또는 마지막 값을 반환하고 중지합니다.
무대 뒤에서
파이썬에서는 True
0 을 제외한 모든 숫자가 해석 됩니다. 따라서 다음과 같이 말합니다.
0 and 10
와 같다:
False and True
어느 것이 분명 False
합니다. 따라서 0을 반환하는 것이 논리적입니다.
답변
예. 이것은 올바른 동작과 비교입니다.
파이썬에서 적어도 A and B
반환 B
하는 경우 A
기본적으로되어 True
있는 경우를 포함하여 A
NOT NULL, NOT이다 None
NOT (예 : 빈으로 빈 용기 list
, dict
등). A
IFF A
는 본질적으로 False
또는 None
또는 비어 있거나 Null입니다.
반면에, A or B
반환 A
하는 경우 A
기본적으로되어 True
있는 경우를 포함하여 A
, NOT NULL 인 NOT None
(예 : 빈 등 NOT 빈 용기 list
, dict
등) 그렇지 않으면 반환 B
.
파이썬에서 non-null
비어 있지 않은 객체가 True로 평가되면 부울처럼 취급 되기 때문에이 동작을 눈치 채지 못하거나 간과하기 쉽습니다 .
예를 들어, 다음은 모두 “True”를 인쇄합니다.
if [102]:
print "True"
else:
print "False"
if "anything that is not empty or None":
print "True"
else:
print "False"
if {1, 2, 3}:
print "True"
else:
print "False"
반면에 다음은 모두 “False”를 인쇄합니다.
if []:
print "True"
else:
print "False"
if "":
print "True"
else:
print "False"
if set ([]):
print "True"
else:
print "False"