- 놓치기 쉬운 Python 문법들2023년 11월 29일 04시 21분 18초에 업로드 된 글입니다.작성자: Taeyong, Lee.
필자가 연구로 사용해본 언어들은 MATLAB, C, R, Julia, Java가 있고 각각 기초 문법부터 천천히 배웠던 기억이 있다. 하지만, Python은 이례적으로 조금 급한 연구에서 이용하기 위해 배워서, 기초적인 부분에서 모자란 부분이 일부 있다. 여러 코딩 테스트를 대비하면서, 새로이 알게 되거나 잊기 쉬운 기초 문법들을 정리하려 한다.
나누기
Python에서 나누기(/)는 꽤 주의해야한다. 나눠진 결과를 기본적으로 실수로 취급한다. 몫을 얻기 위해선 //, 나머지를 얻기 위해선 % 연산자를 사용한다. 또한, 거듭제곱은 **로 사용한다. ^를 사용하는 다른 언어와 조금 다르다. 참고로 Python에서 ^ 연산자는 bitwise-XOR을 의미한다.
a, b = 7, 2 print(a/b) # 3.5 print(a//b) # 3 print(a%b) # 1 print(a**b) # 49
리스트
C++의 STL Vector와 유사하다. 2차원 리스트를 초기화할 때는 아래와 같이 초기화해야 한다.
N, M = 3, 4 arr = [[0]*N for _ in range(M)] print(arr)
만약, 아래와 같이 초기화 한다면, 동일한 객체에 대한 레퍼런스가 복제된다.
N, M = 3, 4 arr = [[0]*N]*M print(arr) # [[0,0,0,0],[0,0,0,0],[0,0,0,0]] arr[1][1] = 5 print(arr) # [[0,5,0,0],[0,5,0,0],[0,5,0,0]]
리스트 메소드 정리
메소드명 설명 시간 복잡도 append() 원소를 하나 삽입 $\mathcal{O}(1)$ sort() 오름차순으로 정렬 (reverse=True 사용 시에 내림차순으로 정렬) $\mathcal{O}(N\log N)$ reverse() 원소의 순서를 뒤집는다 $\mathcal{O}(N)$ insert() 특정한 인덱스 위치에 원소를 삽입 $\mathcal{O}(N)$ count() 특정한 값을 가지는 데이터 개수 $\mathcal{O}(N)$ remove() 특정한 값을 갖는 원소를 제거, 여러개여도 하나만 제거 $\mathcal{O}(N)$ insert, remove 메소드가 $\mathcal{O}(N)$이므로 남발하면 안된다. remove가 하나만 제거하므로 여러개 제거하기 위해선 set을 설정하고 리스트 컴프리핸션을 이용하여 제거하는 게 좋다.
문자열
문자열은 작은 따옴표(')나 큰 따옴표(")를 이용하여 초기화할 수 있고, 각각 반대에 있는 따옴표는 안에서 이용 가능하다. 이스케이프 문자(\)를 이용하면 각 따옴표나 특별한 역할을 하는 문자를 추가할 수 있다. 더하여, 다른 언어와 비슷하게, 문자열을 내부적으로 리스트와 같이 처리된다.
A = "ABCDEF" print(A[2:4]) # CD
튜플
튜플은 리스트에 비해 공간 효율적이다.
사전
사전 자료형은 내부적으로 해시 테이블(Hash table)을 이용하므로 데이터의 검색 및 수정에 $\mathcal{O}(1)$의 상수 시간에 처리할 수 있다. 키-값으로 구성된 데이터를 처리할 땐, 리스트보다 훨씬 빠르게 동작한다.
집합
집합의 기본적인 연산은 수학에서와 같이, 합집합, 교집합, 차집합이 있고, 아래와 같이 사용한다.
a = {1,2,3,4,5} b = {3,4,5,6,7} print(a|b) # Union: {1,2,3,4,5,6,7} print(a&b) # Intersection: {3,4,5} print(a-b) # Subtract: {1,2}
또한, add(), remove() 메소드로 추가하고 제거한다. 여러개를 추가할 때는 update() 메소드를 이용한다.
조건문
if ~ elif ~ else 를 사용하고, 사용되는 비교, 논리 연산자는 다음과 같다; ==, ~=, >, <, >=, <=, and, or, not, in, not in.
함수
함수 밖의 block의 변수를 변경할 때는 global 키워드를 사용한다. 또한, 람다 표현을 사용하면 짧은 함수를 쉽게 만들 수 있다.
def add(a,b): return a+b print(add(3,7)) print((lambda a, b: a+b)(3,7)) # 10
입출력
Python에서 data를 입력받을 때는 input() 메소드를 기본적으로 이용한다. 이는, 한줄의 "문자열"을 입력받는다. 즉, 정수형 데이터를 받을 때에는, int() 메소드를 사용하여 자료형을 변환해야한다. 주로 공백으로 구분되는 경우가 많아 아래 코드가 매우 자주 이용되니까 알아두면 좋다.
data = list(map(int, input().split())) data.sort() print(data)
단, 입력 갯수가 많은 경우 위 메소드는 동작 속도가 느리다. 대신 sys 라이브러리의 sys.stdin.readline() 메소드를 이용한다.
import sys sys.stdin.readlin().rstrip()
여기엔, rstrip() 메소드를 반드시 호출해야 한다. readline()을 이용하여 입력하면, 입력 후 엔터가 줄 바꿈 기호로 입력되는데, 이를 제거해야한다.
print() 메소드는 각 변수를 콤마(,)로 구분하여 넣을 수 있는데, 각 변수가 띄어쓰기로 구분되어 출력된다. 또한, 출력 이후에 줄 바꿈을 자동으로 수행한다. 이는 MATLAB의 disp()함수와 같다. 3.6이상의 버전부터는 f-string 문법을 사용할 수 있다.
a, b = 3, 4 print(a,b) # 3 4 print(a) # 3 print(b) # 4 answer = 7 print("a + b is " + str(answer) + ".") # a + b is 7. print("a + b is", answer, ".") # a + b is 7 . print(f"a + b is {answer}.") # a + b is 7.
표준 라이브러리
Python의 표준 라이브러리는 공식 문서에서 자세히 확인할 수 있다. 중요한 것만 서술하겠다.
내장 함수
input(), print(), sum(), min(), max(), eval(), sorted()
itertools
permutations, combinations, product, combinations_with_replacement
모든 순열, 조합을 구해주는 두 클래스 permutations, combinations와 각각을 중복을 허용하여 해주는 클래스들 product, combinations_with_replacement 이다. 한가지만 예시로 아래와 같이 사용할 수 있다.
from itertools import combinations_with_replacement data = ['A','B','C'] result = combinations_with_replacement(data, 2) print(list(result)) # [('A','A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
heapq
Priority queue (우선순위 큐)를 구현할 때 많이 사용된다. Python의 heap은 min heap으로 구성되어 있다. heap에 원소를 삽입할 때는 heappush() 메소드를 사용하고, 삭제할 때는 heappop() 메소드를 사용한다. 아래는 heapsort 메소드의 구현이다.
import heapq def heapsort(iterable): h = [] result = [] for value in iterable: heapq.heappush(h, value) for _ in range(len(h)): result.append(heapq.heappop(h)) return result result = heapsort([1,3,5,7,9,2,4,6,8,0]) print(result) # [0,1,2,3,4,5,6,7,8,9]
Python에서는 max heap을 제공하지 않으므로, heappush에서 -value로 바꿔 삽입하는 방식으로 구현한다.
bisect
bisect 라이브러리는 이진 탐색(binary search)을 쉽게 구현하게 해준다. 이 라이브러리는 "정렬된" 배열에서 특정한 원소를 찾아야 할 때 효과적이다. bisect_left(), bisect_right() 메소드가 가장 중요하고, 이 두 메소드는 $\mathcal{O}(\log N)$으로 동작한다.
from bisect import bisect_left, bisect_right def count_by_range(a, left_value, right_value): return bisect_right(a, right_value) - bisect_left(a, left_value) a = [1,2,3,3,3,3,4,4,8,9] print(count_by_range(a,4,4)) # 2 print(count_by_range(a,-1,3)) # 6
collections
유용한 자료구조를 제공하는 라이브러리이다. deque와 Counter 클래스를 주로 사용한다. Python에서는 일반적으로 deque를 사용하여 queue를 구현해야 한다. Queue 라이브러리가 있지만, 일반적인 queue 자료구조가 아니다. 리스트는 앞쪽에 있는 원소를 처리할 때 많은 시간이 소요될 수 있다. 하지만, deque는 상수 시간에 처리 가능하다. 하지만, 인덱싱과 슬라이싱 등의 기능은 사용할 수 없다. deque는 스택이나 큐의 기능을 모두 포함하기 때문에, 대용으로 사용된다.
from collections import deque data = deque([2,3,4]) data.appendleft(1) # [1,2,3,4] data.append(5) # [1,2,3,4,5]
Counter 클래스는 등장 횟수를 세는 기능을 제공한다. 원소별 등장 횟수를 세는 기능이 필요할 때 짧게 구현할 수 있다.
from collections import Counter counter = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue']) print(counter['blue']) # 3 print(counter['green']) # 1 print(dict(counter)) # {'red': 2, 'blue': 3, 'green': 1}
마치며
위 내용들은 나동빈 저자의 이것이 취업을 위한 코딩테스트다 with 파이썬 책의 Appendix A 파트를 읽고 정리한 것이다. Python으로 뭔가 구현할 때 기초적인 부분이 떠오르지 않을 때가 많은데, 여러 언어를 배운 경험 상, 그때 그때 찾는것 보다 이렇게 필요한걸 쭉 정리하는 게 도움이 많이 되었다. 그래서 기초부분에서 잊기 쉬운 부분들을 이렇게 정리해본다.
이전글이 없습니다.댓글