파이썬 기초 다지기 1

류한선·2025년 7월 5일

실기연습-2

목록 보기
89/95

좋아! 이번엔 파이썬 실전 코딩과 정보처리기사 실기에서 아주 자주 등장하는 실용 문법인 9번 enumerate, zip 그리고 **10번 map, filter, reduce**에 대해
기초 개념 → 실전 예제 → 디버깅 식 흐름 해설로 줄줄이 완전 해부해줄게!


✅ 9. enumerate() & zip() — 반복문 마스터 키


🔸 9-1 enumerate() — 인덱스 + 값 동시에

🔹기본 예제

arr = ['a', 'b', 'c']
for i, val in enumerate(arr):
    print(i, val)

📌 결과:

0 a
1 b
2 c

✅ 해석:

  • enumerate(arr)(인덱스, 값) 형태로 묶어줌
  • for문 돌 때 i엔 인덱스, val엔 값이 들어감

🔹왜 쓰냐?

기존 방법:

for i in range(len(arr)):
    print(i, arr[i])

enumerate는 훨씬 깔끔하고 실수 줄어듦


🔹start 인자 사용

for i, val in enumerate(['a', 'b'], start=1):
    print(i, val)
# 1 a
# 2 b

🔸 9-2 zip() — 여러 리스트를 동시에 반복

names = ['A', 'B', 'C']
scores = [90, 80, 70]

for name, score in zip(names, scores):
    print(name, score)

📌 결과:

A 90
B 80
C 70

✅ 해석:

  • zip()은 여러 iterable을 짝지어서 하나의 튜플로 반환
  • 짧은 쪽 기준으로 멈춤

🔹리스트로 변환 가능

zipped = list(zip([1,2], [3,4]))
print(zipped)  # [(1,3), (2,4)]

🔹언팩하기 (zip → 원래대로)

zipped = [('a', 1), ('b', 2)]
letters, numbers = zip(*zipped)
print(letters)  # ('a', 'b')
print(numbers)  # (1, 2)

enumerate & zip 요약

함수역할주의
enumerate()인덱스와 값을 동시에for i, x in ... 구조
zip()여러 리스트 묶기길이 짧은 쪽 기준으로 동작

✅ 10. map(), filter(), reduce() — 함수형 프로그래밍 도구


🔸 10-1 map(function, iterable) — 변환

nums = ['1', '2', '3']
nums_int = list(map(int, nums))  # [1, 2, 3]

📌 해석:

  • 각 요소에 대해 int()를 적용해서 리스트 반환

🔹lambda와 함께 쓰기

squared = list(map(lambda x: x**2, [1, 2, 3]))
print(squared)  # [1, 4, 9]

🔸 10-2 filter(function, iterable) — 조건 필터링

even = list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4]))
print(even)  # [2, 4]

📌 해석:

  • lambda의 조건을 만족하는 값만 남김

🔸 10-3 reduce(function, iterable) — 누적 계산

from functools import reduce

total = reduce(lambda x, y: x + y, [1, 2, 3, 4])
print(total)  # 10

✅ 해석:

  • 첫 두 개 1 + 2 = 3
  • 다음 3 + 3 = 6
  • 마지막 6 + 4 = 10

✅ 실전 패턴 예제

🔸 문자열을 정수 리스트로 변환

s = "1 2 3"
arr = list(map(int, s.split()))
# [1, 2, 3]

→ 정보처리기사 실기에서 입력 처리 시 거의 필수


🔸 2배 만들고 짝수만 남기기

nums = [1, 2, 3, 4, 5]
doubled_evens = list(filter(lambda x: x % 2 == 0, map(lambda x: x*2, nums)))
print(doubled_evens)  # [4, 8]

✅ 정리 요약 테이블

함수기능예시 결과
enumerate()인덱스 + 값(0, 'a'), (1, 'b')
zip()여러 리스트 묶기(a, 90), (b, 80)
map(f, iter)각 요소 변환[f(x1), f(x2), ...]
filter(f, iter)조건 통과 요소만[x for x if f(x)]
reduce(f, iter)누적 계산f(f(f(x1,x2),x3),x4)

아주 좋은 질문이야!
바로 그 **** 연산자는 파이썬에서 "거듭제곱(제곱, 제곱근 등)"을 나타내는 연산자야.


** 연산자: 거듭제곱 (Exponentiation)

x ** y

x의 y제곱, 즉 "x를 y번 곱한 것"을 의미해.


🔹예제

print(2 ** 3)  # 2 * 2 * 2 = 8
print(5 ** 2)  # 5 * 5 = 25
print(9 ** 0.5)  # 9의 제곱근 = 3.0

📌 결과:

8
25
3.0

🔹해석:

코드의미계산 결과
2 ** 32의 3제곱8
3 ** 23의 2제곱9
9 ** 0.59의 제곱근 (½ 제곱)3.0
16 ** 0.254제곱근2.0

🔹실제 예제 흐름 해설:

squared = list(map(lambda x: x**2, [1, 2, 3]))

이 코드는 다음과 같이 동작해:

흐름:

  1. map(lambda x: x**2, [1, 2, 3])
    → 각각 x=1, x=2, x=3에 대해
    x**21**2=1, 2**2=4, 3**2=9

  2. 그 결과가 [1, 4, 9]이 되고

  3. list()로 묶어서 리스트로 반환


🔹시각화:

xx**2
11
24
39

🔹**는 왜 쓰일까?

  • 수학 계산에서 간결하고 읽기 쉬움
  • 제곱근, 지수 계산에서 필수
  • 알고리즘 문제에서 거듭제곱, 제곱 비교, 범위 탐색 등에 자주 등장

🔸참고로…

표현의미
x ** 0.5제곱근
x ** 2제곱
x ** 3세제곱
x ** -1역수 (1/x)

✅ 요약

기호의미예시
**거듭제곱2 ** 3 = 8, 9 ** 0.5 = 3.0

좋아! 너가 말한 ** 연산자는 두 가지 전혀 다른 쓰임이 있어서, 이걸 잘 구분하는 게 실전에서 실수를 막는 핵심 포인트야.


** 두 가지 용도 정리

형태의미예시
x ** y거듭제곱 연산자2 ** 3 = 8
**kwargs / **딕셔너리딕셔너리 언팩/가변 인자def f(**kwargs) / f(**d)

✅ 1. ** = 거듭제곱 (앞에서 설명한 내용)

print(2 ** 3)     # 8
print(9 ** 0.5)   # 3.0

✅ 2. **kwargs: 키워드 인자 받을 때 사용

def greet(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

greet(name="Hansun", age=25)

📌 결과:

name = Hansun
age = 25

✅ 해석:

  • **kwargs키워드 인자를 딕셔너리 형태로 묶어서 받는다
  • 내부에서는 kwargs = {"name": "Hansun", "age": 25} 처럼 처리됨

✅ 3. **dict = 딕셔너리 언팩(풀기)

🔹함수에 딕셔너리를 인자로 넘길 때

def add(a, b):
    return a + b

params = {'a': 3, 'b': 5}
print(add(**params))  # 8

📌 해석:

  • add(**params)는 → add(a=3, b=5)처럼 호출됨
  • **는 딕셔너리 params키-값으로 분해해서 함수에 넘김

🔸 정리 시각화

# 호출 예시
def f(a, b): ...

params = {'a': 1, 'b': 2}

f(**params)   ← f(a=1, b=2)

✅ 차이 요약 정리표

쓰임예시의미
거듭제곱x ** yxy 제곱
키워드 인자 받기def f(**kwargs)키워드 인자를 dict로 받음
딕셔너리 언팩f(**dict)dict를 분해해서 인자로 넘김

✅ 실전 꿀팁

실수 유형올바른 형태
**(a, b)**{'a': 1, 'b': 2}
f(1, 2, 3)**args 사용 ❌*args 사용해야 함 ✅

✅ 예제 통합 비교

def profile(name, age):
    print(f"{name} is {age} years old.")

info = {'name': 'Hansun', 'age': 25}

profile(**info)  # 언팩 호출 → profile(name='Hansun', age=25)

좋아, 이제 정말 중요한 걸 하게 됐어.
많은 사람들이 헷갈리는

*args vs **kwargs
*** 연산자의 다른 쓰임 (언팩, 곱셈 등)

총정리 표 + 디버깅 예제 + 실전 용례로 완전 해부해줄게.


*args vs **kwargs: 함수에서 가변 인자 받기


🔹1. *args: 위치 인자 (positional arguments)

def add_all(*args):
    print(args)

add_all(1, 2, 3)  
# 출력: (1, 2, 3)

🔍 해석:

  • *args는 인자들을 튜플로 받음 → (1, 2, 3)
  • 함수 내부에서 for x in args:처럼 순회 가능

🔹2. **kwargs: 키워드 인자 (keyword arguments)

def show_info(**kwargs):
    print(kwargs)

show_info(name="Hansun", age=25)
# 출력: {'name': 'Hansun', 'age': 25}

🔍 해석:

  • **kwargs는 인자들을 딕셔너리로 받음
  • 키-값 형태로 넘긴 것을 자동으로 dict화

🔸비교 요약표

항목예시내부 구조
*argsf(1, 2, 3)(1, 2, 3) (튜플)
**kwargsf(a=1, b=2){'a': 1, 'b': 2} (딕셔너리)

✅ 함수 호출 시 * / ** 언팩 (반대로 풀기)


🔹1. *리스트 → 함수 위치 인자로 넘기기

def add(a, b, c):
    print(a + b + c)

args = [1, 2, 3]
add(*args)  # == add(1, 2, 3)

🔹2. **딕셔너리 → 함수 키워드 인자로 넘기기

def intro(name, age):
    print(f"{name} is {age} years old.")

params = {'name': 'Hansun', 'age': 25}
intro(**params)  # == intro(name='Hansun', age=25)

🔸 시각화 흐름 예제

def f(x, y, z):
    print(x, y, z)

args = [10, 20, 30]
f(*args)  # == f(10, 20, 30)

kwargs = {'x': 10, 'y': 20, 'z': 30}
f(**kwargs)  # == f(x=10, y=20, z=30)

*** 연산자의 "다른 쓰임"


🔹1. 리스트/튜플 언팩 (병합 or 추출)

a = [1, 2]
b = [3, 4]
c = [*a, *b]
print(c)  # [1, 2, 3, 4]

🔹2. 딕셔너리 언팩 (병합)

d1 = {'x': 1}
d2 = {'y': 2}
d = {**d1, **d2}
print(d)  # {'x': 1, 'y': 2}

🔹3. 곱셈 연산자로서의 *

print([0] * 3)  # [0, 0, 0]
print("Hi" * 2)  # "HiHi"

✅ 여기에선 단순한 반복 곱셈 연산자


✅ 전체 정리표

문법의미예시
*args위치 인자 묶기def f(*args):(1,2,3)
**kwargs키워드 인자 묶기def f(**kwargs):{'a':1}
*리스트리스트 언팩 (풀기)f(*[1,2,3])f(1,2,3)
**딕트딕셔너리 언팩f(**{'x':1})f(x=1)
[0]*3반복[0, 0, 0]
"a"*4문자열 반복"aaaa"

✅ 실전 문제에서 이걸 어떻게 헷갈리는가?

실수 예시문제점해결 방법
f(*{'a': 1})dict는 키만 언팩됨 → 에러f(**{'a': 1})로 해야 함
*args = (1,2,3)문법 에러함수 인자에서만 사용
[0]*3]*4얕은 복사 트랩[[0]*3 for _ in range(4)]

✅ 실제 함수에서 *args, **kwargs 동시 사용 예제

def all_info(*args, **kwargs):
    print("Positional:", args)
    print("Keyworded:", kwargs)

all_info(1, 2, name='Hansun', age=25)

📌 결과:

Positional: (1, 2)
Keyworded: {'name': 'Hansun', 'age': 25}

✅ 마무리 요약

  • * : 위치 인자, 리스트 언팩, 반복, 곱셈
  • ** : 키워드 인자, 딕셔너리 언팩, 제곱
  • *args, **kwargs는 함수 정의/호출에서 모두 중요
  • 실기에서는 dict*, **를 혼합한 문제 자주 나옴

좋아! 지금부터 파이썬 실전 코딩에서 실수하면 터지는 트랩 11~13번, 즉


🔹 11. try-except 예외 처리
🔹 12. 자주 쓰이는 모듈들 (heapq, itertools, collections)
🔹 13. is==의 차이 (비교 연산 트랩)


를 하나씩, 개념 → 실제 코드 흐름 → 왜 그렇게 되는가 형식으로 완전히 해부해서 알려줄게.


✅ 11. try / except — 예외 처리 구조


🔸기본 구조

try:
    # 오류가 날 수 있는 코드
    risky_code()
except SomeError:
    # 예외 발생 시 실행할 코드
    handle_it()

🔸예제: ZeroDivisionError 처리

try:
    x = 5 / 0
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")

📌 결과:

0으로 나눌 수 없습니다.

🔸실행 흐름 설명

  • try: 블록에서 예외가 발생하면
  • 해당 예외 타입(ZeroDivisionError)에 맞는 except 블록으로 점프
  • 오류 메시지는 출력하고 프로그램은 종료되지 않음

🔸실전 응용: 여러 예외 처리

try:
    num = int(input("숫자 입력: "))
    print(10 / num)
except ValueError:
    print("숫자를 입력하세요.")
except ZeroDivisionError:
    print("0으로 나누지 마세요.")

✅ 요약

요소역할
try:예외 발생할 수 있는 코드 블록
except:예외 발생 시 실행할 코드
finally:예외 여부와 무관하게 항상 실행됨 (선택)

✅ 12. 주요 내장 모듈 (실기와 알고리즘에서 매우 자주 등장)


🔸 1. heapq — 우선순위 큐 (최소 힙)

import heapq

heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 5)

print(heapq.heappop(heap))  # 1 ← 가장 작은 값부터 나감

✅ 자동 정렬되는 큐!
→ 정보처리기사 실기에서 최단거리, 스케줄링 문제에 자주 등장


🔸 2. itertools — 반복자 도구들

from itertools import permutations, combinations

print(list(permutations([1, 2], 2)))  # [(1, 2), (2, 1)]
print(list(combinations([1, 2, 3], 2)))  # [(1,2), (1,3), (2,3)]

✅ 순열, 조합, 중복 순열, 누적 합 등 다양한 반복자 제공
→ 경우의 수, 조합 탐색 문제에서 자주 사용됨


🔸 3. collections — 자료구조 단축버전 모음

🔹deque (양방향 큐)

from collections import deque

q = deque([1, 2, 3])
q.appendleft(0)
q.append(4)
print(q)  # deque([0, 1, 2, 3, 4])

🔹defaultdict

from collections import defaultdict

d = defaultdict(int)
d['a'] += 1
print(d['a'])  # 1

✅ 요약

모듈용도핵심 함수
heapq우선순위 큐heappush, heappop
itertools순열/조합permutations, combinations
collections구조deque, defaultdict, Counter

✅ 13. == vs is — 완전히 다르다!


🔸개념 차이

연산자의미
==값이 같은가?
is동일한 객체인가? (같은 메모리 주소?)

🔸예제 비교

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)  # True → 값이 같음
print(a is b)  # False → 다른 객체 (주소 다름)

🔸같은 객체일 때

a = [1, 2]
b = a  # 같은 객체 가리킴

print(a == b)  # True
print(a is b)  # True ← 이건 진짜 같은 메모리

🔸주의! 작은 숫자/문자열은 캐싱된다

x = 256
y = 256
print(x is y)  # True (캐싱)

x = 257
y = 257
print(x is y)  # False (캐싱 안 됨)

s1 = "hello"
s2 = "hello"
print(s1 is s2)  # True

✅ 정리 요약

비교==is
의미값 비교객체(메모리) 비교
리스트True / FalseFalse
같은 변수 대입TrueTrue
숫자/문자열상황에 따라 True (캐싱)자주 헷갈림

✅ 11~13 요약표

항목설명실전 예시
try-except예외 발생을 안전하게 처리try: 5/0 except:
heapq최소값 빠른 접근heappush, heappop
itertools조합, 순열 반복permutations
collections자료구조 간편 버전deque, defaultdict
== vs is값 vs 객체 비교a==b vs a is b

0개의 댓글