"and"/ "or"연산자의 이상한 사용
나는 파이썬을 배우려고 노력하고 있는데 멋지고 짧지 만 완전히 말이되지 않는 코드를 발견했습니다.
컨텍스트는 다음과 같습니다.
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)
" 비어 있지 않은 경우 결과를 반환하고 , 그렇지 않으면 반환 합니다. " 라는 매우 비 단식적인 간결한 (그리고 아마도 덜 읽기 쉬운) 방법입니다 . 일반적으로 표현을보다 간결하게 표현한 것입니다 . 예를 들면args
max(args) - min(args)
0
if-else
exp1 and exp2
(대략) 번역해야합니다 :
r1 = exp1
if not r1:
r1 = exp2
또는 동등하게
r1 = exp1 if exp1 else 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
Therefore you can really use it at your advantage. In order to be conscise this is how I see it:
Or
operator
Python's or
operator returns the first Truth-y value, or the last value, and stops
And
operator
Python's and
operator returns the first False-y value, or the last value, and stops
Behind the scenes
In python, all numbers are interpreted as True
except for 0. Therefore, saying:
0 and 10
is the same as:
False and True
Which is clearly False
. It is therefore logical that it returns 0
Yes. This is the correct behaviour of and comparison.
At least in Python, A and B
returns B
if A
is essentially True
including if A
is NOT Null, NOT None
NOT an Empty container (such as an empty list
, dict
, etc). A
is returned IFF A
is essentially False
or None
or Empty or Null.
On the other hand, A or B
returns A
if A
is essentially True
including if A
is NOT Null, NOT None
NOT an Empty container (such as an empty list
, dict
, etc), otherwise it returns B
.
It is easy to not notice (or to overlook) this behaviour because, in Python, any non-null
non-empty object evaluates to True is treated like a boolean.
For example, all the following will print "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"
간단한 방법으로 이해하려면
그리고 : if first_val is False return first_val else second_value
예 :
1 and 2 # here it will return 2 because 1 is not False
그러나,
0 and 2 # will return 0 because first value is 0 i.e False
그리고 => 누군가가 거짓이면 거짓입니다. 둘 다 사실이라면 그것은 사실이 될 것입니다
또는 : if first_val is False return second_val else first_value
이유는 first가 false이면 2가 true인지 아닌지 확인하기 때문입니다.
예 :
1 or 2 # here it will return 1 because 1 is not False
그러나,
0 or 2 # will return 2 because first value is 0 i.e False
또는 => 누군가가 거짓이면 참이됩니다. 따라서 첫 번째 값이 거짓이면 2 값이 무엇이든 상관 없습니다. 그래서 그것은 그것이 될 수있는 두 번째 값을 반환합니다.
누군가가 사실이라면 그것은 사실이 될 것입니다. 둘 다 거짓이면 거짓이됩니다.
참고 URL : https://stackoverflow.com/questions/47007680/strange-use-of-and-or-operator
'developer tip' 카테고리의 다른 글
git push 명령의 사용자 이름 및 비밀번호 (0) | 2020.10.05 |
---|---|
구조체의 특별한 점은 무엇입니까? (0) | 2020.10.05 |
Google App Engine에서 JSON을 어떻게 파싱 할 수 있습니까? (0) | 2020.10.05 |
null과 System.DBNull.Value의 차이점은 무엇입니까? (0) | 2020.10.05 |
gcc C 컴파일러는 C 자체로 작성됩니까? (0) | 2020.10.05 |