해시 연습 6(여러 메서드)

류한선·2025년 7월 3일

실기연습-2

목록 보기
80/95

좋아, 지금부터 이 5가지 트랩을 모두 실제 시험 문제 스타일로 내고,
한 줄씩 디버깅하듯 해설 + 실전 팁으로 완전히 해부해줄게!


🧨 1. del, pop(), remove() 차이 트랩

lst = [1, 2, 3, 4]
del lst[1]
lst.remove(3)
x = lst.pop()
print(lst, x)

보기:

A. [1, 4], 4
B. [1], 4
C. [1, 3, 4], 4
D. [1, 2, 3], 4


✅ 정답: B. [1], 4


🔍 해설

lst = [1, 2, 3, 4]
del lst[1]       # 1번 인덱스 삭제 → [1, 3, 4]
lst.remove(3)    # 값 3을 삭제 → [1, 4]
x = lst.pop()    # 마지막 요소 제거 & 반환 → x = 4, 남은 리스트: [1]

💡 차이 요약

메서드대상반환값사용 예
del lst[i]인덱스❌ 없음del lst[0]
pop(i)인덱스✅ 삭제된 값x = lst.pop()
remove(x)❌ 없음lst.remove(3)

🧨 2. sorted() vs list.sort() 차이 트랩

nums = [3, 1, 4]
sorted(nums)
nums.sort()
print(nums)

보기:

A. [1, 3, 4]
B. [3, 1, 4]
C. [4, 3, 1]
D. 에러 발생


✅ 정답: A. [1, 3, 4]


🔍 해설

sorted(nums)     # 새 리스트 반환만 함 (반환값 무시됨) → 원본 영향 ❌
nums.sort()      # 리스트 자체 정렬 → 원본 영향 O
  • sorted()원본을 건드리지 않고 새 정렬된 리스트 반환
  • sort()리스트 객체 자체를 변경

💡 차이 요약

함수원본 영향반환값
sorted()❌ 없음새 리스트
.sort()✅ 있음None 반환

🧨 3. copy() vs deepcopy() 비교 트랩

import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
b[0][0] = 99
print(a)

보기:

A. [[1, 2], [3, 4]]
B. [[99, 2], [3, 4]]
C. [[1, 2], [99, 4]]
D. [[99, 2], [99, 4]]


✅ 정답: B. [[99, 2], [3, 4]]


🔍 해설

b = copy.copy(a)    # 얕은 복사 → 1단계까지만 복사
b[0][0] = 99        # b[0]과 a[0]은 같은 리스트 → a[0][0]도 변경됨

📌 copy()는 리스트의 바깥 껍데기만 복사하고,
내부 요소는 여전히 원본과 공유됨.


💡 차이 요약

함수깊이내부 요소 공유 여부
copy()얕은 복사✅ 공유됨
deepcopy()깊은 복사❌ 공유 안 됨

🧨 4. 리스트/딕셔너리 내부 참조 트랩

a = [1, 2]
b = [a, a]
a[0] = 99
print(b)

보기:

A. [[99, 2], [1, 2]]
B. [[99, 2], [99, 2]]
C. [[1, 2], [1, 2]]
D. 에러 발생


✅ 정답: B. [[99, 2], [99, 2]]


🔍 해설

a = [1, 2]
b = [a, a]        # b[0]과 b[1]이 **같은 a**를 참조
a[0] = 99         # 둘 다 같이 바뀜
  • b = [a, a]는 a를 두 번 참조하는 것이지, 복사한 게 아님
a ───► [99, 2]
 ▲
 │
 └──── b[0], b[1] 모두 같은 리스트

💡 요약

  • 리스트 안에 같은 리스트를 중복해서 넣을 때
    복사하려면 copy.deepcopy() 또는 a.copy() 사용해야 함

🧨 5. in 연산자의 진짜 동작 방식 (해시 기반)

class Person:
    def __init__(self, name):
        self.name = name

p = Person("Alice")
d = {p: 1}
print(p in d)
print(Person("Alice") in d)

보기:

A. True, True
B. True, False
C. False, False
D. 에러 발생


✅ 정답: B. True, False


🔍 해설

  • 딕셔너리는 키를 비교할 때 **hash()와 ==**을 모두 사용
  • 여기선 Person("Alice") 두 객체가 다르므로 hash도 다르고 → in 결과는 False
p in d                  # ✅ 같은 객체 → True
Person("Alice") in d    # ❌ 다른 객체 → False

✔️ 해결법 (hash, eq 오버라이드)

class Person:
    def __init__(self, name):
        self.name = name
    def __eq__(self, other):
        return self.name == other.name
    def __hash__(self):
        return hash(self.name)

이제는 Person("Alice") 객체끼리도 in dict에서 같게 인식됨.


💡 요약

키 비교 기준설명
in dicthash()== 순서로 검사
사용자 정의 객체__eq__, __hash__ 없으면 서로 다른 객체로 판단

✅ 최종 정리 요약표

트랩 주제실수 원인정확한 동작 방식
del, pop(), remove()삭제 방식 혼동인덱스 vs 값, 반환 여부 구분
sorted() vs sort()반환 vs 원본 변화 혼동sorted()는 새 리스트
copy() vs deepcopy()얕은 복사로 내부 공유deepcopy()로 안전 복사
리스트 내부 참조같은 리스트 재사용 오해참조는 한 번만 생성됨
in 연산자 (dict)객체 비교 시 Falsehash== 둘 다 필요

좋아! 이번엔 요청한 5가지 주제를 하나씩 실전 코드 문제 + 보기 + 한 줄씩 쪼개서 완전 해부 + 핵심 요약으로 다뤄볼게.
정보처리기사 실기나 면접에서도 진짜 자주 나오는 트랩들이니 천천히 같이 파헤치자.


🧨 1. str() vs repr() 실전 트랩

class Person:
    def __str__(self):
        return "str method"
    def __repr__(self):
        return "repr method"

p = Person()
print(str(p))
print(repr(p))
print(p)
print([p])

보기:

A.

str method  
repr method  
str method  
repr method

B.

repr method  
str method  
repr method  
str method

C.

str method  
str method  
str method  
str method

D.
에러 발생


✅ 정답: A


🔍 한 줄 해설

  • str(p)__str__() 호출 → "str method"
  • repr(p)__repr__() 호출 → "repr method"
  • print(p) → 내부적으로 str(p) 호출 → "str method"
  • print([p]) → 리스트 출력 시 각 요소 repr() 호출 → "repr method"

💡 핵심 정리

  • str()print()사람이 읽기 좋은 형태 출력 (즉, __str__)
  • repr()와 컬렉션 출력은 개발자용 표현 (즉, __repr__)

🧨 2. *args**kwargs 인자 전달 혼동 트랩

def func(a, b=2, *args, **kwargs):
    print(f"a={a}, b={b}, args={args}, kwargs={kwargs}")

func(1, 3, 4, 5, x=6, y=7)

보기:

A. a=1, b=3, args=(4, 5), kwargs={'x': 6, 'y': 7}
B. a=1, b=2, args=(3, 4, 5), kwargs={'x': 6, 'y': 7}
C. a=1, b=3, args=(), kwargs={'x': 6, 'y': 7}
D. 에러 발생


✅ 정답: A


🔍 한 줄 해설

  • a=1 → 첫 번째 위치 인자
  • b=3 → 두 번째 위치 인자 (기본값 대신 전달됨)
  • args=(4,5) → 위치 인자 초과분 (4,5)
  • kwargs={'x':6, 'y':7} → 키워드 인자 모두 수집

💡 핵심 정리

  • *args는 위치 인자 추가 수집
  • **kwargs는 키워드 인자 추가 수집
  • 기본 인자도 위치 인자로 덮어쓰기 가능

🧨 3. __init__에서 기본값 변경 문제 (가변 객체 주의)

class Test:
    def __init__(self, data=[]):
        self.data = data

t1 = Test()
t1.data.append(1)
t2 = Test()
print(t2.data)

보기:

A. []
B. [1]
C. None
D. 에러 발생


✅ 정답: B


🔍 한 줄 해설

  • 기본 인자인 data=[]함수 정의 시 한 번만 생성
  • t1.datat2.data가 같은 리스트 공유됨 → [1] 포함된 상태
  • 따라서 print(t2.data) 출력 시 [1]

✔️ 올바른 코드

class Test:
    def __init__(self, data=None):
        if data is None:
            data = []
        self.data = data

💡 핵심 정리

  • 가변 기본 인자(리스트, 딕셔너리 등)는 초기값으로 절대 쓰면 안 됨
  • None으로 초기화하고 함수 내에서 새 객체 생성해야 함

🧨 4. 불변 객체(int, str) 참조 최적화 트랩

a = 1000
b = 1000
print(a is b)

x = 10
y = 10
print(x is y)

보기:

A. True, True
B. False, False
C. False, True
D. True, False


✅ 정답: C


🔍 한 줄 해설

  • 파이썬은 -5~256 사이 정수는 메모리를 최적화해서 공유
  • 1000은 범위를 벗어나서 서로 다른 객체임 → a is b는 False
  • 10은 캐싱되어 같은 객체 참조 → x is y는 True

💡 핵심 정리

  • 작은 숫자와 짧은 문자열은 메모리 재사용
  • 큰 숫자나 긴 문자열은 새 객체 생성
  • is객체 동일성 비교이며, ==와 혼동하지 말 것

🧨 5. 리스트 vs 튜플 해석 실수

a = [1, 2, 3]
b = (1, 2, 3)
print(type(a), type(b))
a[0] = 99
b[0] = 99

보기:

A. <class 'list'> <class 'tuple'>
에러 발생
B. <class 'list'> <class 'tuple'>
[99, 2, 3] 출력
C. <class 'list'> <class 'tuple'>
[1, 2, 3] 출력
D. 에러 발생


✅ 정답: A


🔍 한 줄 해설

  • 리스트는 가변(mutable) → 요소 수정 가능
  • 튜플은 불변(immutable)b[0] = 99에서 TypeError 발생

💡 핵심 정리

  • 리스트는 값 변경 가능
  • 튜플은 생성 후 변경 불가 → 수정 시 에러

🧠 전체 정리표

주제핵심 트랩 요약
str() vs repr()출력 상황에 따라 호출 메서드 다름
*args, **kwargs위치, 키워드 인자 혼동 주의
__init__ 기본값 변경가변 객체 기본값 공유 주의
불변 객체 최적화작은 숫자/문자열 객체 재사용
리스트 vs 튜플튜플은 불변이라 수정 시 에러 발생

0개의 댓글