그 동안 C언어를 사용해 알고리즘 문제들을 풀었지만 이번 기업 코딩 테스트는 C언어로 볼 수 없어 파이썬을 하루 동안 벼락치기하게 되었다. 아무래도 단기간에 빠르게 익혀야하다보니 알고리즘 문제를 풀 수 있을만큼 필요한 부분만 뽑아서 정리해보았다.

자료형
기본 자료형
숫자형 - int(정수), float(실수), complex(복소수)
문자열 - str
불리언 - bool
컨테이너 자료형
리스트(list), 튜플(tuple), 딕셔너리(dictionary), 집합(set)
- int, float, str, bool
기초 문법
주석
한 줄 주석 - #
여러 줄 주석 - ''' ''', """ """"
슬라이싱
기본 형태 - seq[start : stop : step]
예시 :
s[:] # 전체 복사(얕은 복사)
s[::-1] # 역순
s[::2] # 짝수 인덱스(0,2,4,...)만
s[1::2] # 홀수 인덱스(1,3,5,...)만
s[:n] # 앞 n개
s[n:] # n부터 끝까지
s[:-1] # 마지막 빼고
s[1:-1] # 양 끝 제거
연산자
산술 연산자 - +(덧셈), -(뺄셈), *(곱셈), /(나눗셈), //(몫), %(나머지), **(거듭제곱), @(행렬 곱)
단항 연산자 - +(부호 유지), -(부호 반전)
비트 연산자 - ~(NOT), <<(쉬프트), >>(쉬프트), &(AND), ^(XOR), |(OR)
비교 연산자 - <, <=, >, >=, ==, !=
논리 연산자 - and, or, not
멤버 연산자 - in, not in
형변환
int(), float(), str(), bool()(0 이거나 값이 없으면 false)
문자열 처리
합치기 - snack = '스윙칩', one = '1개' > giveme = one + snack, giveme = one + '스윙칩'
길이 - len()
여러줄 문자
icecream = ''' 올 때
메로나
사오세요'''
icecream = """ 올 때
메로나
사오세요"""
반복출력
print('-' *20) # 출력 결과 : --------------------
문자열 메소드
| 이름 | 분류 | 시그니처 | 핵심 기능 | 반환 |
| lower() | 대소문자 | s.lower() | 대문자→소문자 | 새 문자열 |
| upper() | 대소문자 | s.upper() | 소문자→대문자 | 새 문자열 |
| capitalize() | 대소문자 | s.capitalize() | 첫 글자만 대문자(제목 케이스), 나머지 소문자 | 새 문자열 |
| title() | 대소문자 | s.title() | 각 “단어”의 첫 글자 대문자 | 새 문자열 |
| swapcase() | 대소문자 | s.swapcase() | 대↔소문자 상호 변환 | 새 문자열 |
| split() | 분리 | s.split(sep=None, maxsplit=-1) | 구분자로 문자열을 쪼개 리스트 생성 | list[str] |
| count() | 검색 | s.count(sub[, start[, end]]) | 부분문자열 (겹치지 않게) 등장 횟수 | int |
| find() | 검색 | s.find(sub[, start[, end]]) | 부분문자열의 첫 위치 인덱스, 없으면 -1 | int |
| startswith() | 접두사 | s.startswith(prefix[, start[, end]]) | 접두사면 True (튜플 가능) | bool |
| endswith() | 접미사 | s.endswith(suffix[, start[, end]]) | 접미사면 True (튜플 가능) | bool |
| strip() | 공백/문자 제거 | s.strip(chars=None) | 양쪽 끝 문자 제거(기본: 공백) | 새 문자열 |
| replace() | 치환 | s.replace(old, new, count=-1) | old→new 치환(앞에서 count개만 가능) | 새 문자열 |
| center() | 정렬/패딩 | s.center(width, fillchar=' ') | 가운데 정렬 + 채움문자 패딩 | 새 문자열(또는 원본) |
문자열 포맷과 탈출 문자
f-string
- 문자열 앞에 f 붙이고 {} 안에 변수/ 표현식을 넣어 치환
- { 또는 }를 그대로 출력하려면 {{ / }} 처럼 두 번 써야 함.
- f-string의 { ... } 표현식 내부에는 백슬래시(\)를 직접 쓸 수 없음(예: 따옴표 이스케이프용). 이런 경우 따옴표 종류를 바꾸거나(싱글/더블), 문자열 부분에서 처리
name = "Kim"
score = 91.2345
s1 = f"Hello, {name}"
s2 = f"score={score:.2f}" # 소수 2자리
s3 = f"2+3={2+3}" # 표현식 가능
por = '포르쉐'
hyu = '현대'
printf(f'저는 {por},{hyu} 등이 있어요.')
str.format()
- 치환 필드 문법 : {field_name!conversion:format_spec}
"Coordinates: {latitude}, {longitude}".format(latitude="37.24N", longitude="-115.81W")
"{:<10} | {:>10}".format("left", "right") # 정렬
"{:,}".format(1234567890) # 천 단위 구분
por = '포르쉐'
hyu = '현대'
printf('저는 {1},{0} 등이 있어요.'.format(hyu,por))
탈출 문자
| 표기 | 의미 |
| \\ | 백슬래시 자체 |
| \' / \" | 따옴표 자체 |
| \n | 줄바꿈 (newline) |
| \t | 탭 (tab) |
| \r | 캐리지 리턴 (CR) |
| \b | 백스페이스 |
| \f | 폼피드 |
| \v | 수직 탭 |
| \xhh | 16진수 바이트 값(2자리) |
| \uXXXX | 유니코드(16진수 4자리) |
| \UXXXXXXXX | 유니코드(16진수 8자리) |
| \N{name} | 이름으로 유니코드 지정 |
리스트 메소드
| 이름 | 형태 | 동작 | 반환 |
| append(x) | a.append(x) | 맨 뒤에 x 추가 | None |
| extend(iterable) | a.extend(it) | 여러 요소를 뒤에 이어붙임 | None |
| insert(i, x) | a.insert(i, x) | 인덱스 i 위치에 x 삽입 | None |
| remove(x) | a.remove(x) | 값이 x인 첫 요소 삭제(없으면 에러) | None |
| pop([i]) | a.pop() / a.pop(i) | 인덱스 i(기본: 마지막) 요소 삭제 + 반환 | 요소 1개 |
| clear() | a.clear() | 모든 요소 삭제 | None |
| index(x[, start[, end]]) | a.index(x, ...) | x의 첫 위치 인덱스(없으면 에러) | int |
| count(x) | a.count(x) | x 등장 횟수 | int |
| sort(*, key=None, reverse=False) | a.sort(...) | 리스트를 제자리 정렬 | None |
| reverse() | a.reverse() | 순서를 제자리에서 뒤집음 | None |
| copy() | a.copy() | 얕은 복사(a[:]와 동치) | 새 list |
튜플 메소드
| 이름 | 형태 | 의미 | 반환 | 주의 |
| count(value) | t.count(x) | 튜플 안에서 x가 몇 번 등장하는지(전체 발생 횟수) | int | 겹침 개념 없음(원소 단위 카운트) |
| index(value[, start[, stop]]) | t.index(x) / t.index(x, start) / t.index(x, start, stop) | x가 처음 등장하는 위치(인덱스) | int | 없으면 ValueError. start/stop 범위 내에서만 찾음(슬라이싱처럼 stop은 제외) |
세트 메소드
원본 유지
| 이름 | 형태 | 동작 | 반환 |
| isdisjoint(other) | s.isdisjoint(o) | 교집합이 비어있으면 True | bool |
| issubset(other) | s.issubset(o) | 부분집합 여부 (s <= o) | bool |
| issuperset(other) | s.issuperset(o) | 상위집합 여부 (s >= o) | bool |
| union(*others) | s.union(o1, o2...) | 합집합 (`s | other`) |
| intersection(*others) | s.intersection(...) | 교집합 (s & other) | 새 set |
| difference(*others) | s.difference(...) | 차집합 (s - other) | 새 set |
| symmetric_difference(other) | s.symmetric_difference(o) | 대칭차 (s ^ other) | 새 set |
| copy() | s.copy() | 얕은 복사 | 새 set |
원본 변화
| 이름 | 형태 | 동작 | 반환 |
| add(x) | s.add(x) | 원소 추가 | None |
| remove(x) | s.remove(x) | 원소 삭제(없으면 KeyError) | None |
| discard(x) | s.discard(x) | 원소 삭제(없어도 에러 없음) | None |
| pop() | s.pop() | 임의 원소 1개 삭제+반환(비면 KeyError) | 원소 1개 |
| clear() | s.clear() | 전부 삭제 | None |
| update(*others) | s.update(...) | 합집합으로 갱신 (`s | = ...`) |
| intersection_update(*others) | s.intersection_update(...) | 교집합으로 갱신 (s &= ...) | None |
| difference_update(*others) | s.difference_update(...) | 차집합으로 갱신 (s -= ...) | None |
| symmetric_difference_update(other) | s.symmetric_difference_update(o) | 대칭차로 갱신 (s ^= o) | None |
딕셔너리 메소드
| 이름 | 형태 | 동작 | 반환 |
| clear() | d.clear() | 모든 항목 삭제 | None |
| copy() | d.copy() | 얕은 복사 | 새 dict |
| fromkeys(iterable, value=None) | dict.fromkeys(keys, v) | keys로 새 dict 생성(값은 동일 객체 참조 주의) | 새 dict |
| get(key, default=None) | d.get(k, def) | key 없으면 default 반환(에러 안 냄) | 값 |
| keys() | d.keys() | key 뷰(view) | view |
| values() | d.values() | value 뷰(view) | view |
| items() | d.items() | (key,value) 뷰(view) | view |
| pop(key[, default]) | d.pop(k[, def]) | key 삭제+값 반환(없으면 default 또는 KeyError) | 값 |
| popitem() | d.popitem() | 마지막에 넣은 항목(LIFO) 삭제+반환(비면 KeyError) | (k, v) |
| setdefault(key, default=None) | d.setdefault(k, def) | 없으면 k:def 삽입 후 값 반환 | 값 |
| update(...) | d.update(...) | 매핑/쌍(iterable)/kwargs로 갱신(덮어씀) | None |
tuple / list / set / dict 자료형 변환
공통 생성자(컨테이너 생성)
- list(x) : x를 순회(iterate)해서 요소들을 리스트로
- tuple(x) : x를 순회해서 요소들을 튜플로
- set(x) : x를 순회해서 요소들을 셋으로 (중복 제거)
- dict(x) : x를 순회해서 (key, value) 쌍으로 해석해 딕셔너리로
순서/중복/제약
- list/tuple: 순서 유지, 중복 허용
- set: 중복 제거, (수학적 집합) “동일 값 1개만”, 순서 개념은 기대하지 않는 게 안전
- dict: 키 중복 불가(마지막 값이 덮어씀), 키는 hashable(불변)이어야 함
기본 컨테이너 ↔ 기본 컨테이너 변환
(1) list ↔ tuple
t = tuple([1, 2, 2]) # (1, 2, 2)
lst = list((1, 2, 2)) # [1, 2, 2]
(2) list/tuple → set
set([1, 2, 2]) # {1, 2}
set((1, 2, 2)) # {1, 2}
(3) set → list/tuple
list({3, 1, 2}) # 예: [1, 2, 3] 처럼 보일 수도 있지만 순서를 보장하지 않음
tuple({3, 1, 2}) # ( ... ) 역시 마찬가지
정렬된 결과가 필요하면:
sorted_list = sorted({3, 1, 2}) # [1, 2, 3]
dict 관련 변환(가장 헷갈리는 구간)
(1) dict → list / tuple / set :
list(d) / tuple(d) / set(d) 는 기본적으로 키(keys) 를 순회
d = {"a": 1, "b": 2}
list(d) # ['a', 'b'] (키)
tuple(d) # ('a', 'b')
set(d) # {'a', 'b'}
원하는 대상에 따라 다음을 사용:
list(d.keys()) # ['a', 'b']
list(d.values()) # [1, 2]
list(d.items()) # [('a', 1), ('b', 2)]
(2) list/tuple/set → dict : “(key, value) 쌍”
- 아래처럼 길이 2짜리 iterable의 iterable 이어야 함.
pairs = [("a", 1), ("b", 2)]
dict(pairs) # {'a': 1, 'b': 2}
- 키 중복이면 마지막이 덮어씀
dict([("a", 1), ("a", 99)]) # {'a': 99}
- 형태가 안 맞으면 오류
dict(["ab", "cd"]) # ValueError: 요소 길이가 2가 아님(문자열은 글자 단위로 쪼개짐)
dict([("a", 1, 2)]) # ValueError
(3) dict의 “키만/값만”으로 dict를 만들고 싶을 때
- 키만 있고 값은 기본값을 넣고 싶으면 dict.fromkeys
dict.fromkeys(["a", "b"], 0) # {'a': 0, 'b': 0}
- 값이 가변 객체면(예: []) 모든 키가 같은 객체를 공유하니 주의
d = dict.fromkeys(["a", "b"], [])
d["a"].append(1)
# {'a': [1], 'b': [1]} # 둘 다 같이 바뀜 (같은 리스트 공유)
문자열/바이트 같은 “iterable”에서의 변환 주의점
문자열은 글자 단위로 순회됨.
list("abc") # ['a', 'b', 'c']
set("aba") # {'a', 'b'}
tuple("ab") # ('a', 'b')
dict("ab") 는 시도하면 각 글자(요소)가 길이 2의 (k,v)가 아니라서 보통 오류가 남.
(원리상 dict(x)는 x의 각 원소가 (k, v)여야 함)
List Comprehension
형태 : new_list = [변수 활용 for 변수 in 반복대상 if 조건]
예시 :
# 기본 변환
nums = [1, 2, 3, 4, 5]
squares = [x * x for x in nums]
# [1, 4, 9, 16, 25]
# 조건 필터링
nums = [1, 2, 3, 4, 5, 6]
evens = [x for x in nums if x % 2 == 0]
# [2, 4, 6]
# if-else 포함
nums = [1, 2, 3, 4, 5]
labels = ["even" if x % 2 == 0 else "odd" for x in nums]
# ['odd', 'even', 'odd', 'even', 'odd']
# 중첩 루프
pairs = [(i, j) for i in [1, 2, 3] for j in [10, 20]]
# [(1, 10), (1, 20), (2, 10), (2, 20), (3, 10), (3, 20)]
# 문자열 처리
words = ["hi", "python", "a", "list"]
result = [w.upper() for w in words if len(w) >= 2]
# ['HI', 'PYTHON', 'LIST']
# 2차원 리스트 펼치기
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in matrix for x in row]
# [1, 2, 3, 4, 5, 6]
# 공백 제거 빈 문자열 제거
raw = [" apple ", " ", " banana", "", "cherry "]
clean = [s.strip() for s in raw if s.strip()]
# ['apple', 'banana', 'cherry']
for 문
- iterable(리스트/튜플/문자열/딕트/제너레이터 등) 을 순회하며 요소를 꺼냄.
- 기본 형태
for x in iterable:
...
- 자주 쓰는 패턴
- 인덱스 필요: enumerate(iterable)
- 여러 개 묶기: zip(a, b)
- 반복 횟수: range(n)
- 반복 중단/건너뜀: break / continue
- for-else: break 없이 끝까지 돌면 else 실행
- range의 경우 형식은 range(start, stop,step)
for x in items:
if cond: break
else:
# break가 없었을 때만
...
if 문 (조건 분기)
- 조건은 truthy/falsey로 평가됨. (0, "", [], {}, None 등은 보통 falsey)
- 기본 형태
if cond:
...
elif other_cond:
...
else:
...
- 자주 쓰는 표현
- 삼항 연산: a if cond else b
- 단락 평가: A and B, A or B
- 비교 연쇄: 0 < x < 10
while 문 (조건 반복)
- 조건이 True인 동안 반복.
- 기본 형태
while cond:
...
- 무한 루프는 while True: + 종료 조건에서 break
- while-else: break 없이 조건이 False가 되어 종료되면 else 실행
while cond:
if stop: break
else:
...
함수 def
정의/호출
def f(a, b=0, *args, **kwargs):
return a + b
핵심 포인트
- return 없으면 None 반환
- 기본 인자(default)는 함수 정의 시점에 평가됨 -> 가변 객체([], {}) 기본값은 주의
def bad(x, acc=[]): # 지양
acc.append(x)
return acc
- 스코프: 지역/전역, 필요 시 global, nonlocal
- 람다: lambda x: x+1 (간단한 익명 함수)
함수에서 가변인자 활용(*)
주문 합계 계산: *items = “몇 개가 오든 다 받기”
def total_price(order_id, *items):
# order_id: 고정 인자 1개
# items: order_id 뒤에 오는 모든 위치 인자들을 튜플로 묶음
print("order_id:", order_id)
print("items:", items, type(items)) # 튜플 확인
return sum(items)
print(total_price("A001", 3000)) # 1개 상품
print(total_price("A002", 3000, 1200, 500)) # 3개 상품
- 호출 시 내부에서 실제로 매핑되는 값( *items는 “뒤에 붙는 위치 인자들을 전부 모아 튜플로 만듦)
- total_price("A001", 3000)
- order_id = "A001"
- items = (3000,) ← 튜플(원소 1개)
- total_price("A002", 3000, 1200, 500)
- order_id = "A002"
- items = (3000, 1200, 500) ← 튜플(원소 3개)
- total_price("A001", 3000)
리스트를 풀어서 전달(언패킹)
prices = [3000, 1200, 500]
print(total_price("A003", *prices))
- *prices는 리스트를 원소 단위로 펼쳐서 인자로 전달
- 결과적으로 items = (3000, 1200, 500)가 된다.
- 함수 정의에서 *items : 모으기(pack)
- 함수 호출에서 *prices : 풀기(unpack)
인자 배치 규칙
def f(a, b, *rest):
...
- a, b는 필수(고정) 위치 인자
- rest는 그 뒤에 남는 모든 위치 인자
f(1, 2) # rest = ()
f(1, 2, 3, 4, 5) # rest = (3, 4, 5)
- 또 중요한 규칙 하나:
- *rest는 항상 위치 인자들 중 마지막 수집용이라서 뒤에 또 다른 일반 위치 인자를 둘 수 없음
(단, * 뒤에 키워드 전용 인자는 가능)
try 예외 처리
- 기본 형태
try:
#수행 문장
except:
#에러 발생 시 수행 문장
else:
#에러 없을 시 수행 문장
...
finally:
#무관하게 마지막에 항상 수행하는 문장
...
- 핵심 포인트
- 구체적인 예외 타입을 잡는 게 원칙 (except Exception:은 최후 수단)
- 예외 발생시키기: raise ValueError("msg")
- 자원 해제는 보통 with(context manager) 사용이 더 안전함.
- except과 finally 중 하나는 있어야함
class (객체/상태/행동 캡슐화)
- 기본 형태
class A:
def __init__(self, x):
self.x = x
def inc(self):
self.x += 1
- 핵심 포인트
- self: 인스턴스 자신
- 인스턴스 변수: self.x
- 클래스 변수: A.shared (모든 인스턴스가 공유)
- 메서드 종류
- 인스턴스 메서드: def m(self, ...)
- 클래스 메서드: @classmethod def m(cls, ...)
- 정적 메서드: @staticmethod def m(...)
- 상속: class B(A): ..., 오버라이드/super()
파일 입출력
open() 기본 형태와 의미
f = open("list.txt", "r", encoding="utf-8")
- 파일명(path): "list.txt" (상대경로/절대경로 가능)
- 열기 모드(mode): "r", "w", "a" 등
- encoding: 텍스트 파일을 문자로 읽고/쓸 때 인코딩 지정(한글 포함이면 보통 utf-8 권장)
- open()은 파일 객체(file object) 를 반환하고, 이 객체로 read(), write() 등을 수행
열기 모드(mode)
(1) r (read, 읽기)
- 파일이 없으면 오류(FileNotFoundError)
- 읽기만 가능
with open("list.txt", "r", encoding="utf-8") as f:
contents = f.read()
print(contents)
(2) w (write, 쓰기)
- 파일이 없으면 새로 생성
- 파일이 있으면 기존 내용을 전부 지우고(초기화) 덮어씀
with open("list.txt", "w", encoding="utf-8") as f:
f.write("김xx\n")
f.write("정xx\n")
f.write("허xx\n")
(3) a (append, 이어서 쓰기)
- 파일이 없으면 새로 생성
- 파일이 있으면 맨 뒤에 이어서 추가
with open("list.txt", "a", encoding="utf-8") as f:
f.write("추가된줄\n")
파일 쓰기(write)
write()는 “문자열”을 쓴다
- \n을 직접 넣어야 줄바꿈이 된다.
with open("list.txt", "w", encoding="utf-8") as f:
f.write("첫 줄\n")
f.write("둘째 줄\n")
여러 줄을 한 번에 쓰기
lines = ["A\n", "B\n", "C\n"]
with open("list.txt", "w", encoding="utf-8") as f:
f.writelines(lines) # 리스트(반복가능객체) 그대로 이어서 씀
파일 읽기(read)
(1) read() : 파일 전체를 한 번에 문자열로
with open("list.txt", "r", encoding="utf-8") as f:
contents = f.read()
print(contents)
- 파일이 크면 메모리 사용이 커질 수 있음
(2) readline() : 한 줄씩 읽기
with open("list.txt", "r", encoding="utf-8") as f:
line = f.readline() # 한 줄(끝에 \n 포함 가능)
(3) for line in f:
with open("list.txt", "r", encoding="utf-8") as f:
for line in f:
print(line, end="") # end=""는 아래 설명 참고
close() vs with open(...) as f:
직접 열고 닫기
f = open("list.txt", "r", encoding="utf-8")
print(f.read())
f.close()
with 문(컨텍스트 매니저)
with open("list.txt", "r", encoding="utf-8") as f:
print(f.read())
# 블록을 벗어나면 자동으로 close()
- 예외가 발생해도 파일이 안전하게 닫힘
자주 같이 알아두는 모드 옵션
- "x": 새로 생성 전용(이미 파일 있으면 오류)
- "b": 바이너리 모드(이미지/zip 등) -> 예: "rb", "wb"
- "t": 텍스트 모드(기본값) -> 예: "rt", "wt"
- "r+", "w+", "a+": 읽기+쓰기 (동작이 헷갈릴 수 있어 필요할 때만)
예시)
with open("img.png", "rb") as f:
data = f.read()
self와 상속(Inheritance)
self
- 파이썬에서 클래스 메서드는 항상 첫 번째 인자로 self를 받음
- self는 메서드를 호출한 인스턴스 객체
- 메서드 안에서 인스턴스 변수(멤버 변수)에 접근할 때 self.변수명 형태를 사용
예시:
class SmartWatch:
def __init__(self, model, price):
self.model = model
self.price = price
def start_timer(self, minutes):
print(f"{self.model}: 타이머 {minutes}분 시작")
사용 예
w1 = SmartWatch("A-Watch", 199000)
w2 = SmartWatch("B-Watch", 149000)
w1.start_timer(10) # A-Watch: 타이머 10분 시작
w2.start_timer(5) # B-Watch: 타이머 5분 시작
아래 두 코드는 같은 의미
w1.start_timer(10)
SmartWatch.start_timer(w1, 10)
상속(Inheritance)
상속은 기존 클래스를 기반으로 기능을 추가/변경해 새 클래스를 만드는 방식
- 부모 클래스(Parent/Base class): 기본 기능 제공
- 자식 클래스(Child/Derived class): 부모 기능을 물려받고, 필요한 기능을 추가
예시: GPS 기능이 있는 스마트워치(자식 클래스)
class GPSWatch(SmartWatch):
def start_gps(self):
print(f"{self.model}: GPS 추적 시작")
사용 예
w_basic = SmartWatch("A-Watch", 199000)
w_gps = GPSWatch("A-Watch Pro", 249000)
# w_basic.start_gps() # SmartWatch에는 start_gps가 없으므로 에러
w_gps.start_gps() # A-Watch Pro: GPS 추적 시작
super()로 부모 생성자(__init__) 재사용
- 자식 클래스가 부모의 속성 초기화 로직을 그대로 쓰고, 자기만의 속성을 추가하고 싶다면 super().__init__()를 사용
예시: 배터리 용량(battery)을 추가한 GPSWatch
class GPSWatch(SmartWatch):
def __init__(self, model, price, battery):
super().__init__(model, price) # 부모 초기화 재사용
self.battery = battery # 자식 속성 추가
def start_gps(self):
print(f"{self.model}: GPS 추적 시작 (배터리 {self.battery}%)")
사용 예
w = GPSWatch("A-Watch Pro", 249000, 80)
w.start_gps()
# A-Watch Pro: GPS 추적 시작 (배터리 80%)
오버라이딩(Overriding)
- 자식 클래스가 부모 메서드의 동작을 바꾸거나 확장하고 싶을 때 같은 메서드 이름으로 다시 정의
예시: 타이머 시작 시 GPS 기록도 자동으로 켜기(기능 확장)
class AdvancedGPSWatch(GPSWatch):
def start_timer(self, minutes): # 부모의 start_timer를 재정의(오버라이딩)
print(f"{self.model}: 타이머 {minutes}분 시작")
self.start_gps() # 추가 동작(확장)
사용 예
w = AdvancedGPSWatch("A-Watch Ultra", 299000, 90)
w.start_timer(20)
# A-Watch Ultra: 타이머 20분 시작
# A-Watch Ultra: GPS 추적 시작 (배터리 90%)
다중 상속(Multiple Inheritance)
- 파이썬은 한 클래스가 여러 부모 클래스를 동시에 상속할 수 있음
예시: 운동 기록 기능 + 알림 전송 기능을 조합
class WorkoutRecorder:
def record(self):
print("운동 기록 저장 완료")
class Notifier:
def send(self):
print("알림 전송 완료")
class FitnessWatch(GPSWatch, WorkoutRecorder, Notifier):
pass
사용 예
fw = FitnessWatch("Fit-Watch", 219000, 70)
fw.start_gps() # GPSWatch에서 상속
fw.record() # WorkoutRecorder에서 상속
fw.send() # Notifier에서 상속
pass
- 아무 동작도 하지 않고 자리만 채우는 문장
- 문법적으로 블록이 필요한데 아직 구현할 내용이 없을 때 사용
클래스/메서드에서 pass
class Device:
def start(self):
pass # 나중에 구현
반복문/조건문에서 pass
for _ in range(3):
pass
if 10 > 3:
pass
# while True:
# pass # 무한 루프가 되므로 주의
Import
import 모듈
모듈(module)
- 파이썬에서 하나의 .py 파일 == 모듈
- message.py라는 파일을 만들면, 이 파일의 모듈 이름은 message
message.py
def hello():
print("안녕하세요")
import 모듈
- 모듈 전체를 가져오는 방식
main.py
import message
message.hello()
필요한 것만 import: from 모듈 import 함수/변수/클래스
- 모듈 안에서 원하는 것만 가져오는 방식
main.py
from message import hello
hello()
- 표준 라이브러리 예시: random.choice
- 표준 라이브러리도 동일하게 import해서 사용
import random
menu = ["김치찌개", "된장찌개", "제육볶음"]
print(random.choice(menu))
- random.choice(리스트)는 리스트에서 무작위 원소 1개를 뽑음
패키지(package)
- 모듈들을 묶어둔 폴더라고 보면 된다.
예시)
project/
app.py
utils/
formatter.py
notifier.py
- utils : 패키지(폴더)
- formatter.py, notifier.py : 모듈(파일)
utils/formatter.py
def pretty(text):
return f"[INFO] {text}"
utils/notifier.py
def send():
print("알림 전송 완료")
- 패키지 경로 import: import 패키지.모듈
- 점(.)으로 경로를 이어서 가져올 수 있다.
- 이렇게 하면 호출도 utils.formatter.pretty(...)처럼 경로를 끝까지 써야 함
app.py
import utils.formatter
msg = utils.formatter.pretty("서버 시작")
print(msg)
- 패키지에서 모듈만 가져오기: from 패키지 import 모듈
app.py
from utils import notifier
notifier.send()
- 모듈 안에서 특정 함수만 가져오기
from utils.formatter import pretty
print(pretty("데이터 로드 완료"))
코테에서의 기본 입출력 방식
시간 단축용 기본 세팅: 빠른 입력 함수로 바인딩
import sys
input = sys.stdin.readline
- 이후 input() 호출이 곧 sys.stdin.readline()
- 간단한 숫자 입력은 보통 int(input())로 충분
입력 패턴 모음
정수 1개
n = int(input())
한 줄에 정수 여러 개
a, b, c = map(int, input().split())
여러 줄에 정수 T개
t = int(input())
arr = [int(input()) for _ in range(t)]
문자열 한 줄 (개행 제거 필요할 때)
- readline()은 보통 끝에 \n이 붙으니 문자열은 아래처럼:
s = input().rstrip() # 오른쪽(끝) 공백/개행만 제거 (보통 strip보다 안전)
- rstrip() 쓰는 이유: strip()은 왼쪽 공백까지 지워서 의도치 않게 데이터가 바뀔 수 있음
- 예: " abc"를 입력으로 쓰는 문제에서 strip()은 위험
EOF(입력 끝)까지 계속 읽기 (테스트케이스 개수 미제공)
while True:
line = sys.stdin.readline()
if not line: # EOF면 빈 문자열이 옴
break
x = int(line)
# 처리...
또는 sys.stdin 자체를 순회:
for line in sys.stdin:
x = int(line)
# 처리...
출력 패턴 모음
한 줄 출력 (print 대신 write)
sys.stdout.write(str(ans) + "\n")
- write()는 개행 자동 없음 → \n 직접 추가
여러 줄 출력 (가장 자주 쓰는 고속 패턴: join)
out = []
for _ in range(t):
out.append(str(result))
sys.stdout.write("\n".join(out))
- print()를 t번 호출하는 것보다 빠름
- 출력이 많을수록 차이가 큼
공백으로 구분해 한 줄에 출력
out = [1, 2, 3]
sys.stdout.write(" ".join(map(str, out)) + "\n")
자주 쓰는 “입력+출력” 조합 예시
T개 입력 → T개 결과 출력
import sys
input = sys.stdin.readline
t = int(input())
out = []
for _ in range(t):
n = int(input())
out.append(str(n * 2))
sys.stdout.write("\n".join(out))
n, m 한 줄 입력 + 이후 n줄 배열 입력
import sys
input = sys.stdin.readline
n, m = map(int, input().split())
grid = [list(map(int, input().split())) for _ in range(n)]
# 예시 처리
sys.stdout.write(str(sum(map(sum, grid))) + "\n")
EOF까지 “여러 테스트케이스”
import sys
out = []
for line in sys.stdin:
x = int(line)
out.append(str(x + 1))
sys.stdout.write("\n".join(out))
기본 템플릿
import sys
input = sys.stdin.readline
# 입력
t = int(input())
out = []
for _ in range(t):
# 처리
n = int(input())
out.append(str(n)) # 결과 저장
# 출력
sys.stdout.write("\n".join(out))
코테에서 기억해야할 모듈 및 모듈 함수
sys (빠른 입출력)
import sys
input = sys.stdin.readline
n = int(input()) # 한 줄 정수
# 여러 줄 출력 (out은 문자열 리스트)
out = ["1", "2", "3"]
sys.stdout.write("\n".join(out))
collections.deque (BFS / 큐)
from collections import deque
q = deque()
q.append(1) # 뒤에 넣기
q.append(2)
x = q.popleft() # 앞에서 빼기 (큐)
print(x) # 1
collections.Counter (빈도 세기)
from collections import Counter
arr = [1, 1, 2, 3, 3, 3]
cnt = Counter(arr)
print(cnt[3]) # 3이 몇 번? -> 3
collections.defaultdict (기본값 dict)
from collections import defaultdict
d = defaultdict(int) # 없는 키는 기본값 0
d["a"] += 1
d["a"] += 1
print(d["a"]) # 2
heapq (우선순위 큐 / 최소 힙)
import heapq
h = []
heapq.heappush(h, 5)
heapq.heappush(h, 2)
heapq.heappush(h, 7)
print(heapq.heappop(h)) # 가장 작은 값 -> 2
최대 힙(큰 값 우선)은 음수로:
import heapq
h = []
heapq.heappush(h, -10)
heapq.heappush(h, -3)
print(-heapq.heappop(h)) # 10
bisect (이분 탐색 / 삽입 위치)
from bisect import bisect_left, bisect_right
arr = [1, 2, 2, 4]
print(bisect_left(arr, 2)) # 2가 처음 등장하는 위치 -> 1
print(bisect_right(arr, 2)) # 2가 끝난 다음 위치 -> 3
math (수학 함수)
from math import gcd, lcm, isqrt
print(gcd(12, 18)) # 6
print(lcm(4, 6)) # 12
print(isqrt(10)) # 3 (정수 제곱근)
itertools (조합/순열/누적합)
from itertools import combinations, permutations, product, accumulate
print(list(combinations([1, 2, 3], 2))) # (1,2) (1,3) (2,3)
print(list(permutations([1, 2, 3], 2))) # (1,2) (1,3) (2,1) ...
print(list(product([0, 1], repeat=3))) # 3자리 이진 모든 경우
print(list(accumulate([1, 2, 3]))) # [1, 3, 6]
functools.lru_cache (재귀 DP 메모이제이션)
from functools import lru_cache
@lru_cache(None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(30))
re (정규표현식: 숫자 뽑기/파싱)
import re
s = "a-12 b34"
nums = list(map(int, re.findall(r"-?\d+", s)))
print(nums) # [-12, 34]
이렇게 정리한 걸 머리 속에 집어넣고 백준에서 알고리즘 문제 그래프 파트 전까 한 바퀴 돌리면 실버 이하의 문제 정도는 대비할 수 있지 않을까 싶다.