wtf python 알아두면 좋은 내용 정리
- 목차
wtf python이란?
What the f*ck Python?으로, python을 쓰다보면 헷갈리거나 이해되지 않는 연산자나 내장 함수들이 있다. 그런 것들을 소개하고 왜 그런 결과가 나오는지 알려주는 github 문서다.
영문: GitHub - satwikkansal/wtfpython: What the f*ck Python? 😱
한글: GitHub - buttercrab/wtfpython-ko: 놀라운 예제들을 통해서 파이썬을 탐험하고 이해해보세요!
일부는 엄청 깊게 파고들어서 찐 개발자들에겐 도움이 될 수 있으나 나 같은 데이터 분석 업무 위주로 하는 준개발자에게는 불필요한 내용도 좀 있다. 그래서 긴 wtf python 문서 중에서 나에게 필요한 내용을 정리해보았다.
:=
연산자
(a := 3) # 3
(a := 6, 9) # (6, 9)
print(a) # 6
a, b = 6, 9 # 언패킹
print(a) # 6
(a, b := 16, 19) # (6, 16, 19)
print(a, b) # 6, 16
:=
연산자는 대입과 동시에 다른 연산을 할 수 있도록 돕는다.
4 (a := 6, 9)
라는 것은 ((a := 6), 9)
와 같다.
12 :=
연산자는 언패킹이 되지 않기 때문에 (a, b := 16, 19)
를 하면 (a, (b := 16), 19)
를 하는 것과 같다.
연결된 비교 연산자 주의
(False == False) in [False] # False
False == (False in [False]) # False
False == False in [False] # True
비교 연산자가 여러 개가 연속해서 나온다면, 앞에서부터 차례대로 계산이 되는 게 아니라 & 조건으로 묶인다. 예를 들어 a op1 b op2 c
라는 식이 있다면 이는 곧 a op1 b and b op2 c
와 같다.
1 True in [False]
이기 때문에 False
2 False == True
이기 때문에 False이지만
3 False == False in [False]
는 다시 쓰면 (False == False) and (False in [False])
이므로 True and True
즉 True
가 나오게 된다.
1 > 0 < 1 # True
(1 > 0) < 1 # False
1 > (0 < 1) # False
여기서도
1 1 > 0 < 1
은 (1 > 0) and (0 < 1)
로 True
2 True < 1
에서 True
는 1로 취급받아서 False
3 2와 같은 이유로 False
is
와 ==
의 차이점
is
는 양쪽이 같은 객체를 참조하고 있는지를 확인 (같은 메모리를 사용하는지)==
는 양쪽의 “값”이 같은지를 확인
그렇기 때문에 일반적으로 값이 None
인지를 체크할 때 a == None
대신 a is None
을 쓰는 것이 관례이다.
함수에서는 finally
를 조심해서 쓰기
def some_func():
try:
print(1)
return 'from_try'
finally:
print(2)
return 'from_finally'
some_func()
# 1
# 2
# 'from_finally'
some_func()
에서 finally
가 오기 전에 return
이 실행됐어도 finally
는 그를 무시하고 반드시 실행된다.
is not ...
과 is (not ...)
은 서로 다른 연산자
'something' is not None # True
'something' is (not None) # False
is not
은 한 개의 연산자임을 주의해야 한다. (절대 is
와 not
이 합쳐진 연산자가 아니다.)
그렇기 때문에 'something' is (not None)
은 'something' is True
라는 뜻이 되고 False
가 된다.
==
와 not
의 우선순위를 주의
x = True
y = False
not x == y # True
x == not y # error!
not
보다 ==
의 우선순위가 높기 때문에, ==
가 먼저 실행된다.
4 not x == y
는 not (x == y)
로 True
가 되고
7 x == not y
는 (x == not) y
가 되어 에러가 난다.
올바르게 고치려면 x == (not y)
가 되어야 한다.
반복문에서 리스트 아이템 제거하기
list_1 = [1, 2, 3, 4]
list_2 = [1, 2, 3, 4]
list_3 = [1, 2, 3, 4]
list_4 = [1, 2, 3, 4]
for idx, item in enumerate(list_1):
del item
for idx, item in enumerate(list_2):
list_2.remove(item)
for idx, item in enumerate(list_3[:]):
list_3.remove(item)
for idx, item in enumerate(list_4):
list_4.pop(idx)
list_1 # [1, 2, 3, 4]
list_2 # [2, 4]
list_3 # []
list_4 # [2, 4]
list_1
의 del item
은 네임스페이스에서의 item
을 지우는 거라 list_1
에는 어떤 영향도 주지 않는다.
리스트를 돌면서 아이템을 체크, 삭제하려면 list_3[:]
처럼 리스트를 복사해주어야 한다.list_2
와 list_4
는 첫 for에서 첫 번째 item이 지워져 [2, 3, 4]
가 되고 두 번째 for
에서 idx=2
가 되어 두 번째 item
이 지워져 [2, 4]
가 된다.
+=
의 연산 속도
# 3개의 문자열을 "+"을 사용해서:
>>> timeit.timeit("s1 = s1 + s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)
0.25748300552368164
# 3개의 문자열을 "+="을 사용해서:
>>> timeit.timeit("s1 += s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)
0.012188911437988281
s1 += s2 + s3
이 s1 = s1 + s2 + s3
보다 빠르다.
list와 tuple
x = 6, 7, 8
y = sorted(x)
x == y # False
() == [] # True
x
는 tuple이고 sorted
결과는 list이기 때문에 x == y
는 False
가 맞다.
그러나 빈 tuple과 빈 list를 비교하면 같다.
덧셈과 뺄셈
a = 5
++a # 5
--a # 5
a -=- 1 # a = 6
a +=+ 1 # a = 7
++a
는 +(+a)
와 같고 --a
는 -(-a)
와 같다.a -=- 1
은 일종의 말장난 같은 것으로 사실 a -= -1
이며 a = a - (-1)
과 같다.
변수 디버깅
>>> some_string = "wtfpython"
>>> f'{some_string=}'
"some_string='wtfpython'"
python 3.8 이상에서는 f-string으로 변수 디버깅을 빠르게 할 수 있다.
이건 진짜 wtf
a, b = a[b] = {}, 5
a # {5: ({...}, 5)}
표현식은 가장 우측의 {}, 5
하나이며 나머지는 다 대입이다.
대입의 경우 가장 왼쪽부터 실행되어 a, b = {}, 5
가 실행되고 그 이후 a[b] = a, b
가 실행된다....
은 순환 참조를 의미하여 a[b][0] is a
를 하면 True
가 나온다.
참고로 이 문제는 24년 1월 기준, GPT-4도 맞추지 못한 문제다.
'파이썬 Python' 카테고리의 다른 글
7판 4선승제에서 승리 확률 계산하는 코드 (python) (0) | 2024.05.08 |
---|---|
python으로 제곱근(root) 계산하는 함수 구현하기 (0) | 2024.04.26 |
Python 모르고 놓치고 있는 유용한 기능 (0) | 2024.01.30 |
객관식 문제 채점 프로그램 (python) (1) | 2021.03.23 |
파이썬 Tesseract를 이용한 OCR 프로그램 만들기 (2) | 2020.12.05 |