💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    문자열, 리스트, 딕셔너리와 관련된 기본함수 | ✅저자: 이유정(박사)

    🔹반복(iteration)의 개념과 구조

    🔹 이터러블(Iterable)이란? "하나씩 꺼낼 수 있는 값들의 모음"이에요.
    즉, for문으로 반복할 수 있는 객체를 말합니다. 예: 문자열, 리스트, 튜플, 딕셔너리, range 등

    🔹 이터레이터(Iterator)란? 이터러블에서 하나씩 꺼낼 수 있게 도와주는 도구입니다.
    반복할 준비가 된 상태라고 보면 됩니다. 이터레이터는 한 번에 하나씩 데이터를 꺼낼 수 있는 도구예요. 그래서 한꺼번에 모든 데이터를 메모리에 올리지 않고, 필요한 만큼만 꺼내서 처리할 수 있어요.

    ✅ 예시 상황 1: 대용량 데이터 처리

    • 예를 들어 10GB짜리 로그 파일이 있다고 해봅니다.
    • 이걸 한 번에 메모리에 올리면 컴퓨터가 버틸 수 없습니다.
    • 이터레이터를 쓰면 한 줄씩 읽으면서 처리할 수 있어서 메모리 부담이 적어집니다.
    with open("bigfile.txt") as f:
        for line in f:  # 이게 이터레이터 방식
            process(line)
    

    ✅ 예시 상황 2: 중간 상태 유지

    • 예를 들어 데이터를 처리하다가 어디까지 했는지 기억하고 싶을 때,
    • 이터레이터는 현재 위치(상태)를 내부적으로 기억하고 있어요.
    • 그래서 next()를 부르면 그다음 값부터 이어서 꺼내줘요.
    nums = iter([1, 2, 3, 4, 5])
    print(next(nums))  # 1
    print(next(nums))  # 2
    # 나중에 다시 계속 이어서
    print(next(nums))  # 3
    

    상태 기억이라는 의미는 next()를 계속 호출하면 이어서 꺼낼수 있다는 의미의 상태 기억이지 그 위치를 밖으로 알려주거나 에러가 나서 프로그램이 종료 됐다가 다시 그상태를 이어서 실행할수는 없습니다.

    이터레이터는 메모리를 아끼면서 데이터를 하나씩 순차적으로 다룰 수 있게 해주는 도구이고, 특히 데이터가 크거나, 진행 상태를 유지하면서 처리해야 하는 작업에 매우 유용합니다.

    ◽ 페이지 네이션 vs 이터레이터
    페이지 네이션기능은 사용자 기반의 페이지 분할도구이며, 
    이터레이터는 서버 쪽에서 대량 데이터를 순차 처리하기 위한 도구
    (메모리절약)입니다.
    

    유튜브 영상은 한꺼번에 모든 데이터를 꺼내 놓을 수 없습니다.
    인스타그램 게시물은 끝없이 업로드되기 때문에, 전체를 한 번에 불러오는 것은 비효율적입니다.
    그러나 사용자가 보는 화면에는 일정 개수씩 나누어 보여주고,
    필요할 때만 다음 내용을 요청합니다.

    이렇게 사용자에게 데이터를 "조금씩 나눠 보여주는 UI 기능"이 페이지네이션(Pagination)이고,
    서버에서는 전체 데이터를 한 번에 가져오는 대신, 필요한 만큼만 꺼내기 위해 이터레이터(iterator) 방식이 사용됩니다.


    ✅ 이터레이터가 주로 사용되는 5대 분야
    분야 활용 예시
    1. 데이터 처리 / 분석 파일, 로그, CSV, 대용량 데이터 한 줄씩 처리
    2. 웹 크롤링 / API 통신 페이지 수를 모를 때 yieldnext()로 데이터 하나씩 수집
    3. 머신러닝 / 딥러닝 배치(batch) 단위로 학습 데이터를 꺼낼 때 (DataLoader, Generator)
    4. 게임 개발 / 시뮬레이션 프레임 단위로 상태 업데이트 (next()로 단계별 진행)
    5. 스트리밍 처리 실시간 로그, 센서 데이터, 사용자 입력 등 무한 데이터 처리

    ◽ Django에서 데이터를 가져올 때 보통 이렇게 합니다.
    items = MyModel.objects.all()
    

    이건 데이터가 수십만 개일 경우 한꺼번에 메모리에 올라가게 되어 서버가 느려지거나 멈출 수도 있어요.

    그래서 Django는 대용량 데이터를 처리할 때,
    이터레이터 방식으로 데이터를 "하나씩 천천히" 가져올 수 있게 도와주는 기능을 제공합니다.

    </> 일반방식 (비추천 ❌ ) 그러나 개발 테스트시에는 활용할수 있음

    # 게시글을 모두 불러오고 메모리에 올림 (비효율적)
    posts = Post.objects.all()
    
    for post in posts:
        send_email(post.author_email, post.title)
    

    문제점: .all()은 데이터를 한꺼번에 다 가져옴 → 메모리 폭발 위험 데이터가 수천~수만 개라면 서버에 부담이 큼

    ✅ 이터레이터 사용 방식 (추천 ✅)

    # 이터레이터로 데이터를 하나씩 가져옴 (메모리 절약)
    posts = Post.objects.all().iterator()
    
    for post in posts:
        send_email(post.author_email, post.title)
    

    이점: .iterator()를 쓰면 DB에서 하나씩 꺼내며 처리함 메모리에 한 번에 안 올리니 서버가 안정적 큰 데이터셋에서도 빠르고 안전하게 처리 가능

    ✅ 실제 사용 예시 (장고 뷰에서)

    from django.http import HttpResponse
    from .models import Post
    
    def notify_users(request):
        count = 0
        for post in Post.objects.all().iterator():
            send_email(post.author_email, post.title)
            count += 1
    
        return HttpResponse(f"{count}개의 메일을 보냈습니다.")
    

    📝 문제1] 다음 중 이터러블(iterable)객체가 아닌 것은 무엇인가요?

    A. 리스트 ["a", "b", "c"]
    B. 문자열 "hello"
    C. 정수 123
    D. 튜플 ("x", "y", "z")

    ✅ 정답: C

    • 정수는 반복할 수 없는 객체입니다.
    • 리스트, 튜플, 문자열은 모두 for문에 넣을 수 있는 이터러블입니다.

    📝 문제2] 다음 중 이터레이터(iterator)의 특징으로 올바른 설명은 무엇인가요?

    A. iter() 함수는 이터레이터에서만 호출할 수 있다.
    B. next()는 리스트나 튜플에서 직접 호출할 수 있다.
    C. 이터레이터는 내부적으로 현재 위치를 기억하고 next()로 이어서 꺼낼 수 있다.
    D. 이터레이터는 for문에서 사용할 수 없다.

    ✅ 정답: C

    • A: iter()는 이터러블에 호출하여 이터레이터를 생성
    • B: 리스트는 next()가 안 되고, 먼저 iter()로 변환해야 함
    • D: 이터레이터도 for문에 사용할 수 있음

    📝 문제3] 다음 코드 실행 후, 두 번째 for문에서 어떤 결과가 출력될까요?

    nums = iter([10, 20, 30])
    
    for n in nums:
        print(n)
    
    for n in nums:
        print(n)
    

    A. 10 20 30 / 10 20 30
    B. 10 20 30 / (아무것도 출력되지 않음)
    C. SyntaxError 발생
    D. TypeError 발생

    ✅ 정답: B

    • 이터레이터는 한 번 순회하면 끝입니다.
    • 두 번째 for문에서는 이미 다 소비된 상태이므로 출력 없음.

    📝 문제4] 현재 회사 서버의 로그는 이터레이터를 사용하여 "ERROR" 메시지를 필터링하고 있습니다.
    하지만 이터레이터는 한 번만 순회할 수 있어, 로그를 두 번 이상 분석해야 할 경우 재호출이 번거롭고 비효율적입니다.

    아래 코드는 이터레이터 방식으로 작성된 기존 코드입니다:

    logs = (
        "2025-05-15 10:01:05 INFO 서버 시작됨",
        "2025-05-15 10:02:14 ERROR 포트 충돌",
        "2025-05-15 10:03:20 INFO 연결 성공",
        "2025-05-15 10:04:01 ERROR 디스크 공간 부족",
        "2025-05-15 10:05:22 INFO 종료 신호 수신"
    )
    
    log_iter = iter(logs)
    
    print("에러 알림 로그:")
    while True:
        try:
            line = next(log_iter)
            if "ERROR" in line:
                print(f"[관리자 알림] 문제 발생: {line}")
        except StopIteration:
            break
    
    # 다시 순회 시도
    print("\n전체 로그 다시 보기:")
    for line in log_iter:
        print(line)  # 출력 없음 (이터레이터는 한 번만 사용 가능)
    

    요구사항:

    • 위 코드를 이터러블 방식(for문 사용)으로 바꿔서:
      1. "ERROR" 로그만 필터링해서 출력
      2. 전체 로그를 다시 한 번 출력
    • 왜 이터러블 방식이 더 유리한지 한 문장으로 설명하세요.

    ✅ 정답 코드:

    # 이 튜플은 여러 줄의 로그 메시지를 포함하고 있음
    logs = (
        "2025-05-15 10:01:05 INFO 서버 시작됨",
        "2025-05-15 10:02:14 ERROR 포트 충돌",
        "2025-05-15 10:03:20 INFO 연결 성공",
        "2025-05-15 10:04:01 ERROR 디스크 공간 부족",
        "2025-05-15 10:05:22 INFO 종료 신호 수신"
    )
    
    # 1단계: "ERROR"가 포함된 로그만 출력합니다
    print("에러 알림 로그:") # 안내 메시지 출력
    
    # 튜플 logs를 순회하면서 각 줄을 변수 line에 하나씩 꺼냅니다.
    for line in logs:
    
    	# 만약 해당 줄에 "ERROR"가 포함되어 있다면,
        if "ERROR" in line:
    
    		# "[관리자 알림]"이라는 메시지와 함께 해당 로그를 출력합니다.
            print(f"[관리자 알림] 문제 발생: {line}")
    
    # ✅ 2단계: 전체 로그를 다시 출력합니다.
    print("\n전체 로그 다시 보기:") # 줄 바꿈 후 안내 메시지 출력
    
    # logs를 다시 순회하여 모든 로그를 출력합니다.
    # 튜플은 이터러블이기 때문에 여러 번 순회해도 문제 없습니다.
    for line in logs:
        print(line)
    
    튜플은 이터러블이라서 for문을 몇 번 돌리든 항상 처음부터 다시 순회가
    가능합니다. 즉, 튜플, 리스트, 딕셔너리데이터는 모두 이터리블이며 
    for문으로 순회할수 있는 반복 가능한 객체입니다.
    반면 이터레이터는 한 번 순회하면 끝나기 때문에, 반복이 어렵습니다.
    

    🖨️ 출력 결과:

    에러 알림 로그:
    [관리자 알림] 문제 발생: 2025-05-15 10:02:14 ERROR 포트 충돌
    [관리자 알림] 문제 발생: 2025-05-15 10:04:01 ERROR 디스크 공간 부족
    
    전체 로그 다시 보기:
    2025-05-15 10:01:05 INFO 서버 시작됨
    2025-05-15 10:02:14 ERROR 포트 충돌
    2025-05-15 10:03:20 INFO 연결 성공
    2025-05-15 10:04:01 ERROR 디스크 공간 부족
    2025-05-15 10:05:22 INFO 종료 신호 수신
    

    🔍 해설: 이터러블은 for문에서 반복할 때마다 새 이터레이터를 생성하므로,
    데이터를 여러 번 반복해서 순회할 수 있어 이터레이터보다 훨씬 유연하고 실용적입니다. 단, 대용량 데이터의 경우에는 메모리를 많이 차지할 수 있어 비효율적일 수 있습니다.


    🔹iter() 함수란?
    iter() 함수는 이터러블(iterable)한 객체(예: 리스트, 튜플, 문자열
    등)를 이터레이터(iterator)로 변환해주는 내장 함수입니다.
    for문에서 반복이 가능한 모든 자료형은 내부적으로 iter()가
    호출됩니다. 이터레이터는 next()로 하나씩 꺼낼 수 있는 상태를 가진
    객체입니다.
    
    🔹next() 함수란?
    next()는 이터레이터(iterator)에서 다음 값을 하나 꺼내서 반환해주는
    내장 함수입니다. 내부적으로 이터레이터가 현재 어디까지 읽었는지
    기억하고 있어서, next()를 호출할 때마다 다음 항목을 순서대로
    반환합니다.
    

    즉, 이터레이터 함수는 한번만 순회되는 구조입니다. 그래서 재사용을 할수 없습니다.

    </> 예시코드: 리스트를 이터레이터로 변환해 next()로 하나씩 꺼내기

    fruits = ["사과", "바나나", "포도"] 
    
    it = iter(fruits) # 이대로 출력하면 객체원형이 됩니다.
    print(next(it)) 
    print(next(it)) 
    print(next(it))
    print(next(it))  # StopIteration 에러 → 다 꺼냄
    

    🖨️ 출력결과:

    사과
    바나나
    포도
    Traceback (most recent call last):
      File "E:\windows_v\test2.py", line 7, in <module>
        print(next(it))  # StopIteration 에러 → 다 꺼냄
              ~~~~^^^^
    StopIteration
    

    🔍 해설:

    • iter(fruits)로 리스트를 이터레이터로 변환
    • next(it)는 값을 하나씩 꺼내는 함수
    • 더 이상 꺼낼 값이 없으면 StopIteration 오류가 발생
    • it은 한 번 쭉 꺼내면 끝이에요.
    • 다시 처음부터 꺼내고 싶으면 iter(numbers)로 새로 만들어야 해요.

    📝 문제1] 다음 코드는 next()로 리스트의 값을 꺼내고 있습니다.
    이 코드를 이터러블 방식의 for문으로 수정하세요.

    fruits = ["사과", "바나나", "포도"]
    it = iter(fruits)
    print(next(it))
    print(next(it))
    print(next(it))
    

    ✅ 정답 코드:

    fruits = ["사과", "바나나", "포도"]
    
    # for문을 사용하여 반복적으로 요소를 꺼냄
    for fruit in fruits:
        print(fruit)
    

    🖨️ 출력 결과:

    사과
    바나나
    포도
    

    🔍 해설:

    • 기존 코드는 next()를 직접 3번 호출했기 때문에 리스트 길이만큼 정확히 써야 합니다.
    • for문은 내부적으로 iter()next()를 자동으로 사용하므로 반복 구조가 간단하고 안전합니다.
    • 리스트는 이터러블이므로 for문에서 직접 사용할 수 있습니다.

    🔹 with 문이란?
    with는 자동으로 열고, 자동으로 닫아주는 자원 관리 문법입니다.  
    보통 open()처럼 파일이나 네트워크 등 “열고 닫아야 하는 자원”에 
    사용합니다.
    

    📖 문법, 구문(syntax):

    with 열기_함수 as 변수명:
        작업문들
    

    </>예시코드:

    # 경로안에 sample.txt파일을 저장한다.
    
    with open("sample.txt", "r", encoding="utf-8-sig") as f:
        # f는 파일 객체이며, 한 줄씩 반복해서 읽을 수 있는 이터러블입니다.
        for line in f:
            # 각 줄을 출력하면서 끝에 붙은 줄바꿈 문자(\n)를 제거합니다.
            print(line.strip())
    

    withtry-finally처럼:

    • 열고(open())
    • 사용하고(for line in f)
    • 끝나면 자동으로 닫아줍니다.

    📝 문제1] 아래는 이터레이터 방식으로 텍스트 파일에서 로그를 읽고 "ERROR"가 포함된 줄만 출력하는 코드입니다.
    이 코드를 for문으로 바꿔서 더 간결하고 안전하게 리팩터링하세요.

    f = open("log.txt", "r", encoding="utf-8-sig")
    log_iter = iter(f)
    
    while True:
        try:
            line = next(log_iter)
            if "ERROR" in line:
                print("오류:", line.strip())
        except StopIteration:
            break
    
    f.close()
    

    ✅ 정답 코드:

    with open("log.txt", "r", encoding="utf-8-sig") as f:
        for line in f:
            print(line.strip())
    
    utf-8-sig는 BOM이 포함된 UTF-8 파일을 안전하게 읽기 위해 사용하는
    인코딩입니다.
    BOM이 붙어 있으면 utf-8만으로는 오류가 나고, utf-8-sig로 정확히 
    해석할 수 있어요.
    

    🔹 축약표현식

    🔹 리스트 내포(List Comprehension)

    for문을 한 줄로 요약한 축약형 표현 방식
    

    📖 문법, 구문(syntax):

    [값을_어떻게_만들지 for 변수 in 반복할_데이터]
    

    </>예시코드:

    # 일반 `for`문
    words = ["Apple", "Banana", "Cat", "Django", "Zoo"]
    
    result = []  # 결과를 담을 빈 리스트 생성
    
    for word in words:
        if len(word) >= 5:              # 길이가 5 이상인 단어만
            result.append(word.lower()) # 소문자로 바꿔서 리스트에 추가
    
    print(result)
    
    # 리스트 컴프리헨션 list comprehension
    words = ["Apple", "Banana", "Cat", "Django", "Zoo"]
    
    result = [word.lower() for word in words if len(word) >= 5]
    print(result)
    

    🖨️ 출력결과:

    ['apple', 'banana', 'django']
    

    🔹 세트 내포(Set Comprehension)

    리스트 컴프리헨션과 거의 동일하지만, 중복 없이 고유한 값들만 저장하
    는 set(집합)을 만듭니다.
    

    📖 문법, 구문(syntax):

    { 표현식 for 변수 in 반복가능한_객체 if 조건 }
    

    </>예시코드:

    # 일반 for문
    numbers = [1, 2, 2, 3, 4, 4]
    
    unique_squares = set()  # 결과를 저장할 빈 집합 생성
    
    for x in numbers:
        square = x ** 2         # 제곱 계산
        unique_squares.add(square)  # 집합에 추가 (중복은 자동 제거)
    
    print(unique_squares)
    
    # 셋 컴프리헨션 set comprehension
    numbers = [1, 2, 2, 3, 4, 4]
    
    unique_squares = {x**2 for x in numbers}
    print(unique_squares)  
    

    🖨️ 출력결과:

    {16, 1, 4, 9}
    

    🔹 딕셔너리 내포(Dictionary Comprehension)

    반복 가능한 객체를 기반으로 key: value 쌍을 생성해서 딕셔너리를 
    만드는 표현입니다.
    

    📖 문법, 구문(syntax):

    { 키_표현식: 값_표현식 for 변수 in 반복가능한_객체 if 조건 }
    

    </>예시코드:

    # 일반 for문
    words = ["apple", "banana", "cherry"]
    word_lengths = {}  # 빈 딕셔너리 생성
    for word in words:
        word_lengths[word] = len(word)  # 키: 단어, 값: 단어 길이
    print(word_lengths)
    
    # 딕셔너리 컴프리헨션 dictionary comprehension
    words = ["apple", "banana", "cherry"]
    word_lengths = {word: len(word) for word in words}
    print(word_lengths)  
    

    🖨️ 출력결과:

    {'apple': 5, 'banana': 6, 'cherry': 6}
    

    🔹 제너레이터 표현식(Generator Expression)

    리스트 컴프리헨션과 매우 비슷하지만, 리스트처럼 전체를 메모리에 
    올리지 않고 필요할 때 하나씩 꺼내 쓰는 이터레이터를 만듭니다.
    

    📖 문법, 구문(syntax):

    ( 표현식 for 변수 in 반복가능한_객체 if 조건 )
    

    </>예시코드:

    # 일반for문 next()처럼 하나씩 꺼내기
    squares = []  # 리스트에 미리 값을 저장
    for x in range(5):
        squares.append(x ** 2)
    
    # next처럼 하나씩 꺼내 출력
    print(squares[0])  # 0
    print(squares[1])  # 1
    print(squares[2])  # 4
    
    # 제너레이터 표현식
    squares = (x**2 for x in range(5))
    print(next(squares))  # 0
    print(next(squares))  # 1
    print(next(squares))  # 4
    

    ✔️ next()로 하나씩 꺼낼 수 있음. 메모리 절약에 유리!


    📝 문제1] 다음 리스트에서 중복을 제거하고, 각 숫자를 제곱한 결과를 세트로 만들어 출력하세요.
    단, 짝수만 제곱합니다. (세트 내포 - 중복 제거 응용)

    nums = [2, 3, 4, 4, 5, 6, 6, 7]
    

    🖨️ 출력 결과:

    {16, 36, 4}
    

    ✅ 정답 코드:

    nums = [2, 3, 4, 4, 5, 6, 6, 7]
    unique_even_squares = {x**2 for x in nums if x % 2 == 0}
    print(unique_even_squares)
    

    🔍 해설:

    • 세트 내포는 중복을 자동 제거합니다.
    • x % 2 == 0 조건을 통해 짝수만 필터링합니다.

    📝 문제2] 다음 문자열 리스트에서 길이가 4자 이상인 단어들의 첫 글자만 뽑아서 중복 없이 출력하세요. (세트 내포 - 문자열 조건 필터링)

    words = ["data", "dev", "AI", "api", "node", "java", "go"]
    

    🖨️ 출력 결과:

    {'a', 'd', 'g'}
    

    ✅ 정답 코드:

    words = ["data", "dev", "AI", "api", "node", "java", "go"]
    short_first_letters = {word[0] for word in words if len(word) => 4}
    print(short_first_letters)
    

    🔍 해설:

    • 각 단어의 word[0]은 첫 글자입니다.
    • 길이 조건을 만족하는 단어만 대상으로 세트 생성.

    📝 문제3] 다음 사용자 목록에서 이름을 키로, 나이를 값으로 갖는 딕셔너리를 만드세요. 단, 나이가 30세 이상인 사용자만 포함합니다. (딕셔너리 내포 - 값 가공)

    users = [
        {"name": "Alice", "age": 25},
        {"name": "Bob", "age": 35},
        {"name": "Charlie", "age": 40}
    ]
    

    🖨️ 출력 결과:

    {'Bob': 35, 'Charlie': 40}
    

    ✅ 정답 코드:

    users = [
        {"name": "Alice", "age": 25},
        {"name": "Bob", "age": 35},
        {"name": "Charlie", "age": 40}
    ]
    age_filtered = {user["name"]: user["age"] for user in users if user["age"] >= 30}
    print(age_filtered)
    

    🔍 해설:

    • user["name"]: user["age"]로 딕셔너리 구성
    • 조건 필터링으로 나이 30 이상만 포함

    📝 문제4] HTTP 헤더 정보를 담은 리스트에서, 각 항목을 딕셔너리로 변환하세요. 키는 소문자로, 값은 문자열로 유지합니다. (딕셔너리 내포 - 데이터 포맷 변환)

    headers = [
        ("Host", "example.com"),
        ("Authorization", "Bearer xyz"),
        ("Content-Type", "application/json")
    ]
    

    🖨️ 출력 결과:

    {'host': 'example.com', 'authorization': 'Bearer xyz', 'content-type': 'application/json'}
    

    ✅ 정답 코드:

    headers = [("Content-Type", "application/json"), ("Authorization", "Bearer xyz")]
    header_dict = {k.lower(): v for k, v in headers}
    print(header_dict)
    

    🔍 해설:

    • (k, v) 튜플을 순회하며 k.lower()로 키 소문자화
    • 실무에서 HTTP header 처리할 때 유용한 패턴

    📝 문제5] 1부터 1,000,000까지의 정수 중에서 3의 배수의 합을 구하되,
    리스트를 만들지 않고 제너레이터 표현식을 사용해 처리하세요. (제너레이터 표현식 - 메모리 절약)

    sum()함수는 숫자들의 합을 계산하는데 사용됩니다. sum(iterable, start=0)

    🖨️ 출력 결과:

    166,666,833,333
    

    ✅ 정답 코드:

    total = sum(x for x in range(1_000_001) if x % 3 == 0)
    print(f"{total:,}")
    

    🔍 해설:

    • x for x in ...은 리스트를 만들지 않고 하나씩 순회함 (제너레이터)
    • sum()과 함께 쓰면 메모리 효율적인 집계 가능

    💡 리스트 내포는 코드의 가독성을 높이고,
    리스트 생성 작업을 매우 간단하게 처리할 수 있는 파이썬의 강력한 문법입니다. 특히 데이터 가공, 필터링, 변환 작업에 자주 활용돼요.


    🔹 여러 줄 문자열 작성 시 주의점

    파이썬은 여러 줄의 문자열을 나열할 때 문법 오류가 발생하기 쉬워요.  
    특히 list, print(), return 구문 안에 긴 문자열을 여러 줄에 나눠 
    쓸 경우 연결이 되지 않거나 줄바꿈이 생겨서 원하는 출력이 안될 수 있음
    

    ❌ 잘못된 코드 1: list 안에 긴 문자열을 줄바꿈해서 쓴 경우

    my_list = ["이 문자열은 너무 길어서
    다음 줄에 나눠 작성했어요."]
    
    print(my_list)
    

    🛑 오류 발생:

    SyntaxError: unterminated string literal
    

    🔍 이유:

    • 리스트 내부에서 "문자열"을 줄바꿈해서 쓰면 파이썬은 문자열이 끝났는지 모르기 때문에 문법 오류 발생

    ❌ 잘못된 코드 2: return 구문에서 줄바꿈된 문자열

    def get_message():
        return "이 문장은 너무 길어서
        두 줄로 나눴어요."
    

    🛑 오류 발생:

    SyntaxError: unterminated string literal
    

    🔍 이유:

    • return 구문에서도 문자열이 줄바꿈되면 문자열이 닫히지 않은 채 끝났다고 판단함

    ⭕ 해결 방법 1: join() 사용

    lines = ["이 문자열은", "join 함수로", "합쳤어요"]
    message = " ".join(lines)
    print(message)
    

    ⭕ 해결 방법 2: 여러 줄 문자열 """ """ 사용 (출력에 줄바꿈 포함됨)

    def get_message():
        return """이 문장은 너무 길어서
    두 줄로 나눠졌어요."""
    

    ◽ 대표적인 iterable 자료형
    자료형 예시 설명
    리스트 [1, 2, 3] 값들을 하나씩 순서대로 꺼낼 수 있음
    튜플 (10, 20, 30) 리스트와 비슷하지만 수정 불가
    문자열 "hello" 문자 하나하나도 꺼낼 수 있음
    딕셔너리 {"a": 1, "b": 2} 기본적으로 키를 반복함
    집합(set) {1, 2, 3} 순서는 없지만 꺼내는 건 가능
    range() range(5) 0부터 4까지 숫자를 생성함
    • 튜플, 리스트는 모두 이터러블입니다.

      • 여러 개의 값을 담고 있고,
      • 그 값을 하나씩 꺼내서 사용할 수 있기 때문입니다.
    • for문, * 전개 연산자, in 조건문에서 사용할 수 있어요.


    🔹 내장함수

    파이썬이 기본적으로 준비해 둔, 바로 쓸 수 있는 함수들입니다.
    내장함수(built-in function)는 “함수 호출”을 통해 직접 사용할 수 
    있는 도구입니다.
    함수 이름을 쓰고, 괄호 () 안에 필요한 값을 넣는 것을 함수 호출이라고
    합니다.
    

    📘 수학/숫자 관련 함수

    함수 설명
    abs(x) 숫자의 절댓값을 반환합니다
    round(x,n) 소수점 이하 n자리까지 반올림합니다
    max(iterable) 최대값 반환합니다
    min(iterable) 최솟값 반환합니다
    sum(iterable) 합계를 계산합니다
    pow(x, y) xy제곱을 계산합니다
    divmod(x, y) xy로 나눈 몫과 나머지를 튜플로 반환합니다
    예시
    abs(-10)10
    round(3.14159, 2)3.14
    max(3, 10, 7)10
    min(3, 10, 7)3
    sum([1, 2, 3])6
    pow(2, 3)8
    divmod(7, 3)(2, 1)
    </> 예시코드:
    print(abs(-10))         # 10
    print(round(3.1415, 2)) # 3.14
    print(max(1, 5, 3))     # 5
    print(min(1, 5, 3))     # 1
    print(sum([4, 5, 6]))   # 15
    print(pow(2, 4))        # 16
    print(divmod(10, 3))    # (3, 1)
    

    🔹 리스트에 적용되는 기본 함수: min( ), max( ), sum( )
    파이썬에서는 숫자 리스트에 대해 최솟값, 최댓값, 합계를 쉽게 구할 
    수 있는 기본 내장 함수를 제공해요.
    
    함수 설명
    min() 리스트에서 가장 작은 값 반환
    max() 리스트에서 가장 큰 값 반환
    sum() 리스트에 있는 모든 값의 합 계산
    📖 문법, 구문(syntax):
    max(iterable, key=기준함수)
    min(iterable, key=기준함수) 
    sum(iterable, start=0) 
    

    </> 예시코드: 제품별 월간 매출에서 최다 판매 상품, 최저 판매 상품, 총합 매출 구하기

    # 각 상품별 3월 매출 데이터 (단위: 원)
    products = [
        {"name": "에어컨", "sales": 3200000},
        {"name": "선풍기", "sales": 850000},
        {"name": "노트북", "sales": 2150000},
        {"name": "세탁기", "sales": 2750000},
        {"name": "청소기", "sales": 650000}
    ]
    # 최다 판매 상품 일반함수
    def top_product(item):
    	return item["sales"]
    top_product = max(products, key=top_product)
    print(top_product)
    
    # 최다 판매 상품 람다함수
    top_product = max(products, key=lambda item: item["sales"])
    
    # ----------------------------------------
    
    # 최저 판매 상품 일반함수
    def low_product(item):
        return item["sales"]
    low_product = min(products, key=low_product)
    print(low_product)
    
    # 최저 판매 상품 람다함수
    low_product = min(products, key=lambda item: item["sales"])
    
    # ----------------------------------------
    # 전체 상품 매출 합계 일반 for문
    total_sales = 0
    for item in products:
    	total_sales += item["sales"]
    print(total_sales)
    
    # 전체 상품 매출 합계 제너레이터 표현식 ( 표현식 for 변수 in 반복가능한_객체 if 조건 )
    total_sales = sum(item["sales"] for item in products)
    
    # ----------------------------------------
    print("최다 판매 상품:", top_product["name"], "-", top_product["sales"], "원")
    print("최저 판매 상품:", low_product["name"], "-", low_product["sales"], "원")
    print("전체 매출 합계:", total_sales, "원")
    

    🖨️ 출력결과:

    최다 판매 상품: 에어컨 - 3200000 원  
    최저 판매 상품: 청소기 - 650000 원  
    전체 매출 합계: 9600000

    🔍 해설:

    • max(리스트, key=람다식) → 각 딕셔너리에서 "sales" 값 기준으로 최댓값을 가진 항목을 반환
    • min(리스트, key=람다식)"sales" 값 기준으로 최솟값을 가진 항목을 반환
    • sum(표현식 for item in 리스트) → 모든 상품의 "sales" 값을 누적합산

    📝 문제1] 매출 데이터에서 요약 통계 구하기 다음은 한 주간의 일별 매출 기록입니다.
    매출 데이터를 기반으로 최고 매출일, 최저 매출일, 총 매출을 구하세요.

    sales = {
        "Mon": 120000,
        "Tue": 90000,
        "Wed": 150000,
        "Thu": 70000,
        "Fri": 110000
    }
    

    🖨️ 출력 결과:

    최고 매출일: Wed - 150,000원
    최저 매출일: Thu - 70,000원
    총 매출: 540,000

    ✅ 정답 코드:

    sales = {
        "Mon": 120000,
        "Tue": 90000,
        "Wed": 150000,
        "Thu": 70000,
        "Fri": 110000
    }
    
    # 최댓값(가장 많이 번 날)과 최솟값(가장 적게 번 날)
    max_day = max(sales, key=sales.get)  # 매출이 가장 높은 요일
    min_day = min(sales, key=sales.get)  # 매출이 가장 낮은 요일
    total_sales = sum(sales.values())    # 총 매출
    
    print("최고 매출일:", {max_day: ,} - {sales[max_day]: ,} , "원")
    print("최저 매출일:", min_day, "-", sales[min_day], "원")
    print("총 매출:", total_sales, "원")
    

    🔍 해설:

    • max(sales, key=sales.get): 딕셔너리에서 값(매출)이 가장 큰 키(요일)를 반환
    • min(...): 가장 낮은 매출을 가진 요일을 찾음
    • sum(sales.values()): 딕셔너리의 값만 합산해서 총합을 구함

    📝 문제2] 다음은 한 회사의 상품별 3월 매출 데이터입니다.
    이 데이터를 활용하여 아래 물음에 답하세요. (월간 매출 분석)

    sales = {
        "키보드": 125000,
        "모니터": 345000,
        "마우스": 85000,
        "노트북": 890000,
        "스피커": 142000
    }
    

    문제:

    1. 매출이 가장 높은 제품과 그 금액은?
    2. 매출이 가장 낮은 제품과 그 금액은?

    🖨️ 출력 결과:

    최고 매출: 노트북 - 890000 원  
    최저 매출: 마우스 - 85000 원  
    총 매출: 1587000

    ✅ 정답 코드:

    sales = {
        "키보드": 125000,
        "모니터": 345000,
        "마우스": 85000,
        "노트북": 890000,
        "스피커": 142000
    }
    
    max_item = max(sales, key=sales.get)
    min_item = min(sales, key=sales.get)
    total = sum(sales.values())
    
    print(f"최고 매출: {max_item} - {sales[max_item]} 원")
    print(f"최저 매출: {min_item} - {sales[min_item]} 원")
    print(f"총 매출: {total} 원")
    

    🔍 해설:

    • 리스트의 모든 숫자를 더한 값 → 4 + 8 + 2 + 6 = 20
    • sum() 함수는 리스트에 있는 값들을 자동으로 합산해줘요

    📝 문제3] 다음은 각 직원의 1분기 실적(건수)입니다.
    성과 데이터를 활용하여 아래를 구하세요. (직원 성과 평가)

    performance = {
        "Alice": 23,
        "Bob": 15,
        "Charlie": 31,
        "Diana": 18,
        "Ethan": 26
    }
    

    문제:

    1. 가장 많은 실적을 낸 직원과 그 건수는?
    2. 실적이 가장 낮은 직원은?
    3. 평균 실적은 얼마인가? (소수점은 반올림하지 않고 표시)

    🖨️ 출력 예시:

    최다 실적자: Charlie - 31건  
    최저 실적자: Bob - 15건  
    평균 실적: 22.6

    ✅ 정답 코드:

    performance = {
        "Alice": 23,
        "Bob": 15,
        "Charlie": 31,
        "Diana": 18,
        "Ethan": 26
    }
    
    max_emp = max(performance, key=performance.get)
    min_emp = min(performance, key=performance.get)
    average = sum(performance.values()) / len(performance)
    
    print(f"최다 실적자: {max_emp} - {performance[max_emp]}건")
    print(f"최저 실적자: {min_emp} - {performance[min_emp]}건")
    print(f"평균 실적: {average}건")
    

    🔍 해설:

    • max(performance, key=performance.get): 실적이 가장 높은 직원 반환
    • min(...): 실적이 가장 낮은 직원 반환
    • sum(...) / len(...): 전체 실적 평균 계산 (소수 포함)

    📘 형변환 함수 (타입 변경)

    함수 설명 예시
    int() 정수로 변환 int("5")5
    float() 실수로 변환 float("3.14")3.14
    str() 문자열로 변환 str(123)"123"
    bool() 논리값으로 변환 bool(0)False
    list() 리스트로 변환 list("abc")['a', 'b', 'c']
    tuple() 튜플로 변환 tuple([1, 2])(1, 2)
    set() 집합으로 변환 set("hello"){'h', 'e', 'l', 'o'}
    dict() 딕셔너리로 변환 dict([(1, 'a'), (2, 'b')]){1: 'a', 2: 'b'}

    </> 예시코드:

    print(int("10"))       # 10
    print(float("3.5"))    # 3.5
    print(str(100))        # '100'
    print(bool(""))        # False
    print(list("hi"))      # ['h', 'i']
    print(tuple([3, 4]))   # (3, 4)
    print(set("aabb"))     # {'a', 'b'}
    print(dict([(1, 'one'), (2, 'two')]))  # {1: 'one', 2: 'two'}
    

    📘 반복/자료형 함수

    함수 설명
    len(x) 길이 반환. 문자열, 리스트, 튜플 등에 사용 가능
    range(start, stop, step) 숫자 범위 생성
    enumerate(x) 인덱스와 값을 함께 반환
    zip(a, b) 두 시퀀스를 병렬 처리. 튜플 쌍 반환
    reversed(x) 역순 객체 반환
    sorted(x) 정렬된 리스트 반환 (원본은 유지됨)
    dict.items() 딕셔너리의 (key, value) 쌍을 튜플 형태로 반환. 반복문에서 자주 사용됨
    예시
    len("hello")5
    range(1, 5)[1, 2, 3, 4]
    enumerate(['a', 'b'])
    zip([1,2],[3,4])
    reversed([1,2,3])
    sorted([3, 1, 2])[1, 2, 3]
    list({'a':1, 'b':2}.items())[('a', 1), ('b', 2)]

    🔹 enumerate( ) 함수와 반복문 조합하기
    enumerate() 함수는 반복 가능한 객체(리스트, 문자열 등)를 순회할 때 
    각 요소와 함께 인덱스(번호)도 함께 가져올 수 있게 해주는 함수예요.
    일반적인 for문에서는 인덱스를 따로 관리해야 하지만,  
    enumerate()를 사용하면 자동으로 번호와 값을 동시에 다룰 수 있어요.
    

    📖 문법, 구문(syntax):

    enumerate(iterable, start=0)
    

    </> 예시코드: 리스트를 enumerate()로 인덱스와 함께 출력하기

    fruits = ["사과", "바나나", "포도"]  
    
    for i, fruit in enumerate(fruits):     
    	print(i, fruit)
    

    🖨️ 출력결과:

    0 사과 
    1 바나나 
    2 포도
    

    🔍 해설:

    • enumerate(fruits)는 (0, "사과"), (1, "바나나") ... 형태의 튜플을 반환
    • i는 인덱스(순번), fruit은 리스트 요소
    • 순서와 데이터를 동시에 다루고 싶을 때 매우 유용

    </> 예시코드: 서버 로그 항목에 번호를 붙여 중요 에러 표시

    # 서버에서 수집된 로그 목록
    logs = [
        "INFO: 시스템 정상 작동",
        "ERROR: 사용자 인증 실패",
        "WARNING: 디스크 공간 부족",
        "ERROR: 데이터베이스 연결 실패",
        "INFO: 백업 완료"
    ]
    
    # 로그 항목마다 번호를 붙이며 에러 로그는 ★ 표시
    for i, log in enumerate(logs, start=1):
        marker = "★" if "ERROR" in log else " "  # 에러 로그 강조
        print(f"{i:02d}. {marker} {log}")
    

    🖨️ 출력 결과:

    1.   INFO: 시스템 정상 작동
    2. ★ ERROR: 사용자 인증 실패
    3.   WARNING: 디스크 공간 부족
    4. ★ ERROR: 데이터베이스 연결 실패
    5.   INFO: 백업 완료
    

    🔍 해설:

    • enumerate(logs, start=1) 로그에 1번부터 번호 매김
    • i:02d 번호를 항상 2자리로 출력 (01, 02, ...)
    • "★" if "ERROR" in log else " " 에러 로그는 눈에 띄게 표시

    🔹zip 함수의 기본 개념
    두 리스트를 인덱스 기준으로 묶어서  
    (1, 3), (2, 4) 이런 식의 쌍(pair)으로 만들어주는 함수예요.
    

    📖 문법, 구문(syntax):

    zip(iterable1, iterable2, ..., iterableN)
    

    </> 예시코드: 리스트를 enumerate()로 인덱스와 함께 출력하기

    z = zip([1, 2], [3, 4])
    print(list(z))
    
    # -----------------
    names = ["영희", "철수"]
    ages = [22, 25]
    
    for name, age in zip(names, ages):
        print(f"{name}의 나이는 {age}세입니다.")
    

    🖨️ 출력결과:

    [(1, 3), (2, 4)]
    
    영희의 나이는 22세입니다.
    

    📝 문제1] 다음 로그 리스트를 enumerate()를 사용해 번호와 함께 출력하되,
    "ERROR"가 포함된 항목 앞에는 [!ERROR] 표시를 붙여 강조하세요.
    번호는 1부터 시작합니다.

    logs = [
        "INFO 서버 시작",
        "ERROR 인증 실패",
        "WARNING 디스크 부족",
        "ERROR 연결 오류",
        "INFO 백업 완료"
    ]
    

    🖨️ 출력 결과:

    1.          INFO 서버 시작
    2. [!ERROR] ERROR 인증 실패
    3.          WARNING 디스크 부족
    4. [!ERROR] ERROR 연결 오류
    5.          INFO 백업 완료
    

    ✅ 정답 코드:

    logs = [
        "INFO 서버 시작",
        "ERROR 인증 실패",
        "WARNING 디스크 부족",
        "ERROR 연결 오류",
        "INFO 백업 완료"
    ]
    
    for i, log in enumerate(logs, start=1):
        tag = "[!ERROR]" if "ERROR" in log else "        "
        print(f"{i:02d}. {tag} {log}")
    

    🔍 해설:

    • enumerate(..., start=1)로 번호를 1번부터 출력
    • i:02d는 번호를 항상 2자리로 출력 (01, 02, ...)
    • "ERROR" 포함 여부에 따라 [!ERROR] 표시

    📝 문제2] 사용자 점수 등급 출력 아래의 사용자 점수 리스트를 사용하여, 각 사용자에 대해 번호, 이름, 점수, 등급을 출력하세요.

    • 점수가 90 이상: A
    • 80 이상: B
    • 나머지: C
    users = [("민수", 92), ("영희", 81), ("철수", 75)]
    

    🖨️ 출력 결과:

    1. 이름: 민수, 점수: 92, 등급: A  
    2. 이름: 영희, 점수: 81, 등급: B  
    3. 이름: 철수, 점수: 75, 등급: C
    

    ✅ 정답 코드:

    users = [("민수", 92), ("영희", 81), ("철수", 75)]
    
    for i, (name, score) in enumerate(users, start=1):
        if score >= 90:
            grade = "A"
        elif score >= 80:
            grade = "B"
        else:
            grade = "C"
        print(f"{i}. 이름: {name}, 점수: {score}, 등급: {grade}")
    

    🔍 해설:

    • enumerate(..., start=1) → 번호 부여
    • for i, (name, score) → 튜플의 요소를 동시에 언패킹
    • 조건문을 활용한 실시간 등급 분류 처리

    📝 문제3] 사용자가 입력한 문장 줄 번호 붙여 출력하기 사용자로부터 여러 줄의 문장을 입력받아 리스트에 저장한 후,
    줄 번호를 붙여 출력하세요.
    입력은 3줄로 제한하며, 줄 번호는 1부터 시작합니다.

    🖨️ 출력 예시:

    3줄의 문장을 입력하세요:
    > 첫눈이 왔다
    > 창밖이 하얗다
    > 커피가 생각났다
    
    입력한 문장:
    1: 첫눈이 왔다
    2: 창밖이 하얗다
    3: 커피가 생각났다
    

    ✅ 정답 코드:

    lines = []
    
    print("3줄의 문장을 입력하세요:")
    for _ in range(3):
        line = input("> ")
        lines.append(line)
    
    print("\n 입력한 문장:")
    for i, line in enumerate(lines, start=1):
        print(f"{i}: {line}")
    

    🔍 해설:

    • enumerate(..., start=1)로 번호 붙이기
    • 입력을 리스트에 저장한 뒤 출력 시 순서 매김
    • 실무에서 사용자 입력 기록, 에디터 기능, 파일 줄 표시 등에 활용 가능

    🔹 reversed( ) 함수로 리스트 뒤집기
    reversed() 함수는 리스트나 문자열 같은 순서가 있는 자료형(시퀀스)을
    뒤에서부터 거꾸로 순회(iteration)할 수 있게 해주는 내장 함수예요.
    즉, 리스트나 문자열을 거꾸로 하나씩 꺼낼 수 있게 도와주는 파이썬 도구
    입니다.
    

    ⚠️ 하지만! 주의할 점이 있어요: 원래 리스트는 그대로 유지되고, 거꾸로 꺼내볼 수 있는 도구(반복자)를 만들어줍니다.

    📖 문법, 구문(syntax):

    reversed(iterable)
    

    </> 예시코드: 최신 알림 로그를 최근 순으로 출력하기

    # 시간순으로 저장된 시스템 알림 로그 (오래된 것 → 최신순)
    notifications = [
        "[08:12] 서버 시작됨",
        "[09:05] 사용자 로그인",
        "[09:47] 오류 발생: DB 연결 실패",
        "[10:02] 자동 백업 완료",
        "[10:45] 관리자 로그아웃"
    ]
    
    # 가장 최근 알림이 먼저 보이도록 역순으로 출력
    print("최신 알림 내역 (최근순):")
    for idx, notice in enumerate(reversed(notifications), start=1):
        print(f"{idx}. {notice}")
    

    🖨️ 출력결과:

    최신 알림 내역 (최근순):
    1. [10:45] 관리자 로그아웃
    2. [10:02] 자동 백업 완료
    3. [09:47] 오류 발생: DB 연결 실패
    4. [09:05] 사용자 로그인
    5. [08:12] 서버 시작됨
    

    ◽ 리스트로 저장하고 가공하고 싶을 때

    # 알림 로그: 시간순으로 저장됨 (오래된 → 최신)
    notifications = [
        "[08:12] 서버 시작됨",
        "[09:05] 사용자 로그인",
        "[09:47] 오류 발생: DB 연결 실패",
        "[10:02] 자동 백업 완료",
        "[10:45] 관리자 로그아웃"
    ]
    
    # reversed()를 사용해 역순으로 만들고, list()로 리스트로 저장
    recent_logs = list(reversed(notifications))
    
    # 최근 2개 알림 추출 (슬라이싱)
    latest_two = recent_logs[:2]
    
    # 출력
    print("최근 알림 2개:")
    for i, log in enumerate(latest_two, start=1):
        print(f"{i}. {log}")
    

    🖨️ 출력결과:

    최근 알림 2개:
    1. [10:45] 관리자 로그아웃
    2. [10:02] 자동 백업 완료
    

    🔍 해설:

    • reversed(notifications) 알림을 뒤집음 (최신 → 오래된 순)
    • list(...) 이터레이터를 리스트로 변환하여 인덱싱 가능
    • [:2] 최근 2개의 항목 추출
    • enumerate(..., start=1) 번호를 1부터 붙여 출력

    reversed() vs sort().reverse() 차이점 reversed()는 그냥 순서만 뒤집어 보여주는 도구이고, .sort().reverse()는 정렬된 순서를 직접 바꾸는 작업

    </> 예시코드: reversed() 사용

    # 시간순으로 기록된 상품 가격 변화 (오래된 → 최신)
    price_log = [10000, 12000, 11500, 13000]
    
    # 최근 가격부터 보기 (순서만 뒤집음, 원본은 그대로 유지)
    for i, price in enumerate(reversed(price_log), start=1):
        print(f"{i}일 전 가격: {price}원")
    
    print("원본 가격 로그:", price_log)
    

    🖨️ 출력 결과:

    1일 전 가격: 130002일 전 가격: 115003일 전 가격: 120004일 전 가격: 10000원
    원본 가격 로그: [10000, 12000, 11500, 13000]
    

    🔍 해설:

    • reversed(price_log)는 원본을 수정하지 않고 거꾸로 보는 뷰(iterator)를 제공합니다.
    • 로그 데이터, 시계열 데이터, 거래 내역 등 기록 순서를 유지한 채로 최근부터 순회할 때 사용됩니다.

    </> 예시코드: sort() + reverse() 사용 – 가격 순으로 정렬 후 내림차순 보고

    # 상품별 가격 목록 (정렬이 필요함)
    product_prices = [42000, 39000, 50000, 32000]
    
    # 가장 비싼 상품부터 보기 (내림차순 정렬)
    product_prices.sort()     # 오름차순 정렬
    product_prices.reverse()  # 뒤집어서 내림차순
    
    print("가격순 정렬 결과 (내림차순):")
    for i, price in enumerate(product_prices, start=1):
        print(f"{i}. {price}원")
    

    🖨️ 출력 결과:

    가격순 정렬 결과 (내림차순):
    1. 500002. 420003. 390004. 32000

    🔍 해설:

    • .sort() → 정렬 (기본은 오름차순)
    • .reverse() → 정렬된 결과를 뒤집어 *림차순
    • 원본 리스트 product_prices는 이 과정을 거치며 영구히 변경됩니다.

    📝 문제1] 최근 로그를 최신순으로 출력하기 다음은 시스템 로그가 저장된 리스트입니다.
    이 로그를 reversed()를 사용하여 최신 로그부터 출력하세요.
    출력 형식은 "n번 로그: 메시지"이며, n은 1부터 시작합니다.

    logs = [
        "08:01 시스템 시작",
        "08:45 사용자 로그인",
        "09:10 데이터 저장",
        "10:30 시스템 종료"
    ]
    

    🖨️ 출력 예시:

    최신 로그:
    1번 로그: 10:30 시스템 종료
    2번 로그: 09:10 데이터 저장
    3번 로그: 08:45 사용자 로그인
    4번 로그: 08:01 시스템 시작
    

    ✅ 정답 코드:

    logs = [
        "08:01 시스템 시작",
        "08:45 사용자 로그인",
        "09:10 데이터 저장",
        "10:30 시스템 종료"
    ]
    
    print("최신 로그:")
    for i, log in enumerate(reversed(logs), start=1):
        print(f"{i}번 로그: {log}")
    

    🔍 해설:

    • reversed(logs) → 리스트 순서를 거꾸로 보기 (최근 로그부터)
    • enumerate(..., start=1) → 번호 매기기
    • 실무에서 알림, 에러 로그, 기록 리스트 최신순 표시에 매우 유용

    📝 문제2] 사용자 최근 입력값 3개를 거꾸로 출력하기 사용자에게 입력을 5번 받아 리스트에 저장하고,
    가장 최근 입력 3개만 거꾸로 출력하세요.

    🖨️ 출력 결과:

    단어 입력: apple
    단어 입력: banana
    단어 입력: cherry
    단어 입력: date
    단어 입력: egg
    
    최근 입력 3개:
    1. egg
    2. date
    3. cherry
    

    ✅ 정답 코드:

    inputs = []
    
    # 사용자 입력 5회 받기
    for _ in range(5):
        word = input("단어 입력: ")
        inputs.append(word)
    
    # 최근 입력 3개만 추출 → 역순으로 출력
    print("\n 최근 입력 3개:")
    for i, word in enumerate(reversed(inputs[-3:]), start=1):
        print(f"{i}. {word}")
    

    🔍 해설:

    • inputs[-3:] → 최근 3개 슬라이싱
    • reversed(...) → 거꾸로 출력 (최신순)
    • 실무에서 사용자 이력, 검색 기록, 최근 알림 등의 처리 방식과 유사

    📝 문제3] 날짜별 매출 데이터를 역순으로 출력하기 다음은 날짜별 매출 기록입니다.
    최근 날짜부터 매출을 출력하되, 출력은 "날짜 - 금액원" 형식으로 작성하세요.

    sales = [
        ("2024-01-01", 150000),
        ("2024-01-02", 178000),
        ("2024-01-03", 162500)
    ]
    

    🖨️ 출력 예시:

    최근 매출 내역:
    2024-01-03 - 1625002024-01-02 - 1780002024-01-01 - 150000

    ✅ 정답 코드:

    sales = [
        ("2024-01-01", 150000),
        ("2024-01-02", 178000),
        ("2024-01-03", 162500)
    ]
    
    print("최근 매출 내역:")
    for date, amount in reversed(sales):
        print(f"{date} - {amount}원")
    

    🔍 해설:

    • 튜플 목록을 reversed()로 순회
    • 언패킹하여 날짜, 금액으로 출력
    • 실무에서 정렬 없이 입력 순서 유지 + 최신순 출력 시 많이 사용

    📘 타입 확인 및 특수 기능 함수

    함수 설명
    type(x) 자료형 확인
    id(x) 객체의 고유 식별자 반환
    isinstance(x, T) x가 타입 T(자료형타입)의 인스턴스인지 확인
    callable(x) 호출 가능한 객체인지 확인 (함수인지 등)
    eval(str) 문자열 코드를 실행하고 결과 반환
    exec(str) 문자열 코드 실행 (결과 반환 없음)
    예시
    type("hi")<class 'str'>
    id(5)
    isinstance(5, int)True
    callable(print)True
    eval("2+3")5
    exec("x=5")print(x)

    </> 예시코드:

    print(type([1,2]))          # <class 'list'>
    print(id(100))              # 객체 고유값 (숫자 다름)
    print(isinstance("hi", str))  # True
    print(callable(len))        # True
    print(eval("3 * 4"))        # 12
    exec("a = 10")              # 실행됨
    print(a)                    # 10
    

    🔹 id() 함수: 중요도는 높지 않으나 이해 차원에서 정리한 내장함수입니다. 변수나 객체의 "고유 주소값(ID)"을 반환합니다.
    메모리상의 위치처럼, 값은 같아도 id는 다를 수 있음.

    🧾쉽게말하면: 파이썬이 어떤 값을 저장할 때, 메모리에 올려놓는 위치(주소)가 있어요.
    id()는 이 주소를 숫자 형태로 보여주는 함수입니다. 그러나 숫자처럼 변하지 않는 값을 불변객체라고 하며 메모리 재사용(최적화)를 위해 이렇게 주소의 위치를 지정합니다.

    🧐 id함수는 언제 사용되나? 참조확인: 같은 객체인지 확인 불변 객체 최적화 확인: 정수, 문자열 등의 공유 여부 파악 디버깅: 함수 안팎에서 객체가 바뀌었는지 추적

    </> 예시코드:

    a = 10
    b = 10
    c = 20
    
    print("a의 id:", id(a))
    print("b의 id:", id(b))
    print("c의 id:", id(c))
    

    🖨️ 출력결과: 컴퓨터마다 다름

    a의 id: 140706765241328
    b의 id: 140706765241328
    c의 id: 140706765241648
    

    🔍 해설:

    • ab는 값도 같고 같은 객체로 인식되어 같은 ID를 가짐.
    • c는 값이 다르기 때문에 ID도 다름.

    🔹 isinstance(x, T) 함수 x가 T 자료형인지 확인합니다.
    결과는 True 또는 False로 반환됩니다.

    </> 예시코드:

    x = 123
    y = "hello"
    z = [1, 2, 3]
    
    print(isinstance(x, int))     # True
    print(isinstance(y, str))     # True
    print(isinstance(z, list))    # True
    print(isinstance(y, int))     # False
    

    🖨️ 출력결과: 컴퓨터마다 다름

    True
    True
    True
    False
    

    🔍 해설:

    • xint, ystr, zlist이기 때문에 각각의 타입 확인이 가능.
    • y는 문자열이므로 int인지 묻는 건 False.

    🔹 exec(str) 함수 문자열 형태로 된 파이썬 코드를 실행합니다.
    eval()은 결과를 반환하지만, exec()는 결과 없이 실행만 합니다.

    </> 예시코드:

    code = """
    x = 5
    y = 10
    z = x + y
    print("계산 결과:", z)
    """
    
    exec(code)  # 문자열 코드 실행
    

    🖨️ 출력결과: 컴퓨터마다 다름

    계산 결과: 15
    

    🔍 해설:

    • exec()code 문자열을 마치 코드처럼 실행함.
    • 변수 선언도 가능하고, 출력도 할 수 있음.
    • 주로 동적으로 코드를 만들거나 실행할 때 사용됨.

    🔹 eval() 함수 문자열을 파이썬 코드를 실제로 실행하는 함수입니다. 간단한 계산기 만들기나 동적으로 코드 실행하기 및 작은 언어(DSL)를 구현할때 사용합니다. 그러나 문자열이 무엇이든 실행하기 때문에 외부에서 입력한 값이 위험한 코드일 경우에는 그냥 실행해버립니다. 그래서 보안에 취약하기 때문에 실제 서비스에는 거의 사용하지 않습니다. 꼭 써야 한다면 믿을수 있는 내부 코드에서만 사용합니다.

    📖 문법, 구문(syntax):

    eval(expression[, globals[, locals]])
    
    • expression: 문자열로 된 유효한 파이썬 표현식
    • globals, locals: 선택적으로 실행할 스코프(전역/지역 변수) 지정

    </> 예시코드:

    x = 10
    expression = "x * 2 + 5"
    result = eval(expression)
    print("결과:", result)
    

    🖨️ 출력결과:

    결과: 25
    

    🔹 callable(object) 함수 현업에서는 객체가 정말 함수처럼 실행 가능한지 아닌지 헷갈리때가 많습니다. 그래서 콜러블 함수를 활용해 실행 가능한지 확인하는 테스트 코드를 자주 사용합니다.

    📖 문법, 구문(syntax):

    callable(object)
    
    • 사용자에게 받은 값이 함수일지 아닐지 몰라서.
    • 클래스 인스턴스인데 실행하려다가 에러 나는 걸 방지하려고.
    • 동적으로 실행할 코드를 미리 확인하고 안전하게 실행하려고.

    </> 예시코드: 다양한 객체를 테스트

    def my_func():
        return "나는 함수입니다."
    
    class MyClass:
        def __call__(self):
            return "나는 실행 가능한 객체입니다."
    g = Greeter()
    g()  # 사실은 g.__call__()을 의미함 # obj()
    
    
    class MyEmptyClass:
        pass
    
    x = 10               # 숫자
    y = "hello"          # 문자열
    z = [1, 2, 3]        # 리스트
    obj1 = MyClass()     # __call__ 있는 클래스
    obj2 = MyEmptyClass()  # 아무 메서드 없는 클래스
    
    test_cases = [my_func, MyClass, obj1, obj2, x, y, z]
    
    for i, item in enumerate(test_cases, 1): # (i=index, item=value)
        print(f"{i}. {type(item).__name__}: callable? {callable(item)}")
    

    🖨️ 출력결과:

    1. function: callable? True
    2. type: callable? True
    3. MyClass: callable? True
    4. MyEmptyClass: callable? False
    5. int: callable? False
    6. str: callable? False
    7. list: callable? False
    
    번호 객체 설명 callable() 결과 이유
    1 일반 함수 my_func True 함수는 당연히 실행 가능
    2 클래스 자체MyClass True 클래스는 ()로 인스턴스를 만들 수 있어서 호출 가능
    3 __call__() 가진 객체 인스턴스 True 함수처럼 obj() 호출 가능
    4 아무 메서드 없는 객체 False 실행할 수 없음
    5 숫자 False 실행 대상 아님
    6 문자열 False 실행할 수 없음
    7 리스트 False 실행할 수 없음

    🔹 __call__()이란? 어떤 객체에 () 괄호를 붙이면 실행되도록 만드는 비밀스런 메서드(함수)예요.

    class MyClass:
        def __call__(self):
            return "나는 실행 가능한 객체입니다."
    
    g = MyClass()       # 올바르게 클래스 이름 사용
    print(g())          # 사실은 g.__call__()을 실행한 것과 같음
    

    📘 기타 유용한 함수

    함수 설명 예시
    input() 사용자 입력 input("이름: ")
    print() 값을 화면에 출력 print("안녕")
    help() 도움말 출력 help(str)
    dir() 객체의 속성/함수 목록 보기 dir(list)
    chr() 숫자를 문자로 변환 chr(65)'A'
    ord() 문자를 아스키 코드(숫자)로 변환 ord('A')65
    bin() 2진수 문자열 반환 bin(5)'0b101'
    hex() 16진수 문자열 반환 hex(255)'0xff'
    oct() 8진수 문자열 반환 oct(8)'0o10'
    </> 예시코드:
    print(chr(97))        # 'a'
    print(ord('a'))       # 97
    print(bin(7))         # '0b111'
    print(hex(16))        # '0x10'
    print(oct(10))        # '0o12'
    print(dir(str))       # str 관련 함수 목록 출력
    # help(print)         # 주석 해제 시 도움말 출력됨
    

    🔹 dir() 함수 어떤 객체가 가지고 있는 속성(변수)이나 메서드(함수)를 리스트로 반환합니다.
    쉽게 말해, "무엇을 할 수 있는지" 목록을 보여주는 도구입니다.

    </> 예시코드:

    word = "hello"
    print(dir(word))
    

    🖨️ 출력 결과 (일부 생략):

    ['__add__', '__class__', '__contains__', ..., 'capitalize', 'count', 'endswith', 'find', 'isalpha', 'isdigit', 'lower', 'upper', 'strip']
    

    🔍해설: word는 문자열이니까, dir(word)는 문자열이 가진 기능(메서드)들을 보여줍니다.

    즉, dir(대상)은 무엇이 가능한지를 보여주는 함수입니다.


    ✅ Django 모델 객체에 적용

    # 예시 모델
    from django.db import models
    
    class User(models.Model):
        username = models.CharField(max_length=100)
        email = models.EmailField()
    

    사용 예시 (views.py나 shell에서)

    user = User(username="eunice", email="eunice@example.com")
    
    # 1. 속성 목록 확인
    print("모델 속성:", dir(user))
    
    # 2. 속성 존재 여부 확인
    if not hasattr(user, "phone"):
        print("phone 속성이 정의되어 있지 않음")
    
    # 3. 속성 값 접근
    print("이메일:", getattr(user, "email", "이메일 없음"))
    
    # 4. 동적 속성 추가 (일시적)
    setattr(user, "nickname", "유니")  # DB에는 저장되지 않음
    
    print("닉네임:", getattr(user, "nickname", "없음"))
    

    🔹 chr() 함수 정수(아스키/유니코드 번호)를 해당하는 문자(Character)로 바꿔줍니다.

    </> 예시코드: 대문자 A

    print(chr(65))  # 아스키 코드 65는 'A'
    

    🖨️ 출력 결과 (일부 생략):

    A
    

    </> 예시코드: 한글도 가능 (유니코드 사용)

    print(chr(44032))  # 유니코드 44032는 '가'
    

    🖨️ 출력 결과 (일부 생략):

    </> 예시코드: 반복문과 함께 사용하면 문자표 만들기

    for i in range(65, 70):  # A(65) ~ E(69)
        print(i, "→", chr(i))
    

    🖨️ 출력 결과 (일부 생략):

    65 → A
    66 → B
    67 → C
    68 → D
    69 → E
    

    💭직접 풀어보세요.

    📝 문제1] 아래 3개의 문장을 줄바꿈 없이 하나로 출력해보세요.
    ["파이썬은", "정말", "재밌어요!"]

    🖨️ 출력 결과:

    파이썬은 정말 재밌어요!
    

    ✅ 정답 코드:

    words = ["파이썬은", "정말", "재밌어요!"] 
    sentence = " ".join(words) 
    print(sentence)
    

    🔍 해설:

    • 공백 " "을 구분자로 리스트의 문자열을 합침
    • join()은 문자열 리스트를 하나의 문장으로 만들 때 유용

    📝 문제2] 다음 리스트에서 "콜라"를 제외한 항목들로만 새 리스트를 만들어 출력해보세요.
    ‼️ 단, 리스트 내포(list comprehension) 문법을 사용하고, for 반복문과 if 조건을 함께 활용하세요.

    drinks = ["물", "주스", "콜라", "커피", "우유"]
    

    ✨ 힌트: 리스트 내포 구조:

    [리스트들 for 리스트안에 한개의 객체 in 리스트들 if 리스트안에 한개의 객체 != "콜라"]
    

    🖨️ 출력 결과:

    ['물', '주스', '커피', '우유']
    

    ✅ 정답 코드:

    drinks = ["물", "주스", "콜라", "커피", "우유"]
    filtered = [drink for drink in drinks if drink != "콜라"]
    print(filtered)
    

    🔍 해설:

    • for drink in drinks: 리스트 drinks에서 음료를 하나씩 꺼냄
    • if drink != "콜라": 콜라가 아닌 항목만 선택
    • → 선택된 항목을 filtered 리스트에 담음

    📝 문제4]사용자 조회 수 상위 3명 추출 (이터레이터 + sorted + next) 다음 딕셔너리에서, 조회 수 기준으로 상위 3명의 이름을 순서대로 출력하세요.

    views = {
        "alice": 120,
        "bob": 150,
        "carol": 110,
        "dave": 300,
        "erin": 200
    }
    

    🖨️ 출력 결과

    dave
    erin
    bob
    

    ✅ 정답 코드:

    top3_iter = iter(sorted(views.items(), key=lambda x: x[1], reverse=True))
    for _ in range(3):
        print(next(top3_iter)[0])
    

    🔍 해설

    • sorted()로 값 기준 정렬 → (이름, 조회수) 튜플 목록
    • iter()로 이터레이터 변환
    • next()로 순차 접근
    • next()는 데이터를 순서대로 하나씩 꺼낼 수 있어 메모리 효율적

    📝 문제5] 예상 출력 결과는?

    </>문제 코드:

    cities = ["서울", "부산", "대구"]
    
    for i, city in enumerate(cities):
        print(f"{i+1}. {city}")
    

    보기: A:

    0. 서울  
    1. 부산  
    2. 대구  
    

    B:

    1. 서울  
    2. 부산  
    3. 대구 
    

    C:

    서울  
    부산  
    대구 
    

    ✅ 정답: B

    🖨️ 출력 결과:

    1. 서울  
    2. 부산  
    3. 대구  
    

    🔍 해설:

    • enumerate(cities)i=0부터 시작
    • 하지만 print(f"{i+1}. {city}")로 출력 시 +1을 했기 때문에 1부터 시작하는 번호가 붙어요

    📝 문제6] 빈칸 채우기 다음 코드에서 ___에 들어갈 가장 적절한 코드는?

    fruits = ["사과", "배", "포도"]
    
    for idx, fruit in ___:
        print(f"{idx}: {fruit}")
    

    보기: A. range(fruits)
    B. enumerate(fruits)
    C. list(fruits)
    D. fruits.items()

    ✅ 정답: B. enumerate(fruits)

    🖨️ 출력 결과:

    0: 사과  
    1: 배  
    2: 포도   
    

    🔍 해설:

    • enumerate(fruits)는 인덱스와 값을 한 번에 꺼내줍니다.
    • range()는 인덱스만, fruits.items()는 딕셔너리 전용이라 리스트에서는 사용 불가입니다.
    • list(fruits)는 값을 꺼내긴 하지만 인덱스를 자동으로 붙여주지 않습니다.

    📝 문제7] 인덱스는 0부터 시작한다. 그런데 인덱스를 1부터 시작하게 하려면?

    🖨️ 출력 결과:

    1. 고양이  
    2. 강아지  
    3. 햄스터  
    

    ✅ 정답코드:

    animals = ["고양이", "강아지", "햄스터"]
    
    for idx, animal in enumerate(animals, start=1):
        print(f"{idx}. {animal}")  
    

    🔍 해설:

    • enumerate(리스트, start=숫자)를 사용하면 인덱스를 원하는 숫자부터 시작 가능!
    • 이 기능은 설문지, 문제 번호 붙일 때 아주 유용합니다.

    📝 문제8] 리스트 컴프리헨션으로 짝수 제곱만 구하기 리스트 [1~10]에서 짝수만 골라 제곱한 리스트를 생성하세요.

    🖨️ 출력 결과

    [4, 16, 36, 64, 100]
    

    ✅ 정답코드:

    result = [x**2 for x in range(1, 11) if x % 2 == 0]
    print(result)  
    

    🔍 해설

    • for x in range(1, 11) → 1~10 순회
    • if x % 2 == 0 → 짝수만 필터링
    • x**2 → 제곱 계산

    📝 문제9] 짝수의 제곱을 리스트에 담기 다음 코드를 실행하면 어떤 리스트가 출력될까요?

    # 짝수의 제곱값을 저장할 빈 리스트 생성
    array = []
    
    # 0부터 20 미만까지, 2씩 증가시키며 반복
    for i in range(0, 20, 2):
        array.append(i * i)
    
    # 리스트 출력
    print(array)
    

    ❓ 예상되는 출력 결과는?

    A. [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    B. [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
    C. [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    D. [0, 4, 16, 36, 64, 100, 144, 196]

    ✅ 정답: B

    🖨️ 정답 출력:

    [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
    
    i i * i (제곱값) array에 추가된 값
    0 0 [0]
    2 4 [0, 4]
    4 16 [0, 4, 16]
    6 36 [0, 4, 16, 36]
    8 64 [0, 4, 16, 36, 64]
    10 100 [0, 4, 16, 36, 64, 100]
    12 144 [0, 4, 16, 36, 64, 100, 144]
    14 196 [0, 4, 16, 36, 64, 100, 144, 196]
    16 256 [0, 4, 16, 36, 64, 100, 144, 196, 256]
    18 324 [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
    🔍 해설:
    • range(0, 20, 2)는 0부터 18까지 2씩 증가하는 짝수만 반복합니다.
    • i * ii의 제곱값을 의미합니다.
    • 각 제곱값은 array.append(...)로 리스트에 하나씩 저장됩니다.
    • 마지막에 array를 출력하면 짝수 제곱만 담긴 리스트가 나옵니다.

    📝 문제10] 위 코드를 리스트 내포(list comprehension)로 바꾸면?

    array = []
    
    for i in range(0, 20, 2):
        array.append(i * i)
    
    print(array)
    

    ✅ 정답:

    array = [i * i for i in range(0, 20, 2)]
    

    📝 문제11] 다음 코드의 출력 결과를 예상하세요

    test = (
        "이렇게 입력해도 "
        "하나의 문자열로 연결되어 "
        "생성됩니다."
    )
    print("test:", test)
    

    ❓ 출력 결과는?

    A. 줄바꿈되어 출력됨
    B. 괄호가 출력됨
    C. 문자열이 자동 연결되어 한 줄로 출력됨
    D. 문법 오류가 발생함

    ✅ 정답: C

    🖨️ 정답 출력:

    test: 이렇게 입력해도 하나의 문자열로 연결되어 생성됩니다.
    

    🔍 해설:

    • 파이썬에서는 문자열을 괄호 ( ) 안에 여러 줄로 나열하면 자동으로 하나의 문자열로 연결됩니다.
    • + 기호 없이도 작동하며, 줄바꿈도 자동 제거됩니다.

    📝 문제12] reversed()와 join을 활용한 문자열 뒤집기 문자열 "Python은 강력하다"를 공백 없이 뒤집어 출력하세요.

    🖨️ 정답 결과:

    다력강 은nohtyP
    

    ✅ 정답 코드:

    s = "Python은 강력하다"
    print(''.join(reversed(s)))
    

    🔍 해설

    • reversed(s) → 문자열 뒤에서부터 순회하는 이터레이터
    • ''.join(...) → 문자 하나씩 붙여서 문자열로 재조합

    📝 문제13] 다음 중 짝수일 때의 출력 결과는?

    number = 6
    
    if number % 2 == 0:
        print("\n".join([
            "입력한 문자열은 {}입니다.",
            "{}는(은) 짝수입니다."
        ]).format(number, number))
    

    🖨️ 정답 출력:

    입력한 문자열은 6입니다.
    6는(은) 짝수입니다.
    

    🔍 해설:

    • join()은 리스트의 각 문자열을 한 줄로 연결하며 줄바꿈(\n)으로 붙입니다.
    • .format(){}에 각각 값을 채워 넣습니다.
    • format(number, number) → 두 개의 {} 자리에 같은 숫자 6이 들어감

    📝 문제14] generator expression으로 누적합 100 넘는 시점 구하기 1부터 무한히 더하다가 누적합이 100을 처음 넘는 시점의 숫자를 구하세요.

    🖨️ 정답 출력:

    14 # 수정됨
    

    ✅ 정답코드:

    gen = (x for x in range(1, 1000))
    total = 0
    for n in gen:
        total += n
        if total > 100:
            print(n)
            break
    

    🔍 해설:

    • 제너레이터 표현식은 메모리 절약에 유리
    • for 반복하면서 누적합 계산
    • break로 조건 만족 시 즉시 종료

    📝 문제15] 아래 코드 실행 시 출력 결과는? (짝수 입력 시)

    number = 10
    if number % 2 == 0:
        print("""\
    입력한 문자열은 {}입니다.
    {}는(은) 짝수입니다.""".format(number, number))
    

    🖨️ 출력 결과:

    입력한 문자열은 10입니다.
    10는(은) 짝수입니다.
    

    🔍 해설:

    • """\" ← 백슬래시를 붙이면 첫 줄 줄바꿈 없이 바로 출력됩니다.
    • 여러 줄 문자열을 출력할 때 들여쓰기 없이 자연스럽게 출력 가능

    📝 문제16] 사용자 입력값이 홀수인지 짝수인지 판별해, 결과를 아래와 같이 출력하는 프로그램을 리스트와 join()을 활용하여 작성해보세요.

    # 입력예시
    정수 입력> 9
    
    # 출력예시
    입력한 문자열은 9입니다.
    9는(은) 홀수입니다.
    

    ✅ 정답 코드:

    # 출력예시
    number = int(input("정수 입력> "))
    
    if number % 2 == 0:
        print("\n".join([
            "입력한 문자열은 {}입니다.",
            "{}는(은) 짝수입니다."
        ]).format(number, number))
    else:
        print("\n".join([
            "입력한 문자열은 {}입니다.",
            "{}는(은) 홀수입니다."
        ]).format(number, number))
    

    📝 문제17] dictionary comprehension으로 키 값 바꾸기 다음 딕셔너리에서, 값을 키로, 키를 값으로 뒤집은 새 딕셔너리를 만들어라.

    lang = {
        "python": 1,
        "java": 2,
        "c++": 3
    }
    

    🖨️ 출력 결과:

    {1: 'python', 2: 'java', 3: 'c++'}
    

    ✅ 정답 코드

    reversed_lang = {v: k for k, v in lang.items()}
    print(reversed_lang)
    

    🔍 해설

    • 딕셔너리 컴프리헨션은 key: value 쌍을 바꿔 생성 가능
    • 키 중복 주의: 값이 중복되면 마지막 값만 남음

    📝 문제18] 다음 코드를 실행했을 때 출력 결과로 알맞은 것은?

    example_dictionary = {
        "키A": "값A",
        "키B": "값B",
        "키C": "값C",
    }
    
    for key, element in example_dictionary.items():
        print("dictionary[{}] = {}".format(key, element))
    

    ❓ 출력 결과는?

    A.

    dictionary[값A] = 키A   
    dictionary[값B] = 키B   
    dictionary[값C] = 키C
    

    B.

    dictionary['key'] = 'value'   
    dictionary['key'] = 'value'   
    dictionary['key'] = 'value'
    

    C.

    dictionary[키A] = 값A   
    dictionary[키B] = 값B   
    dictionary[키C] = 값C
    

    D.

    키A:값A  
    키B:값B  
    키C:값C
    

    ✅ 정답: C

    🖨️ 출력 결과:

    dictionary[키A] = 값A   
    dictionary[키B] = 값B   
    dictionary[키C] = 값C
    

    🔍 해설:

    • example_dictionary.items()는 딕셔너리 안의 (key, value) 쌍들을 꺼냅니다.
    • 반복문에서 for key, element in ...: 구문은 각각의 쌍을 한 번에 분해해서 변수에 담는 구조예요.
    • format(key, element)를 사용하여 dictionary[키] = 값 형태로 출력됩니다.

    📝 문제19] 빈칸 채우기 문제 다음 코드에서 ___에 들어갈 가장 적절한 함수는 무엇인가요?

    fruit_colors = {
        "사과": "빨강",
        "바나나": "노랑"
    }
    
    for name, color in ___:
        print(f"{name}의 색깔은 {color}입니다.")
    

    보기 A. fruit_colors.values()
    B. fruit_colors.keys()
    C. fruit_colors.items()
    D. fruit_colors.list()

    ✅ 정답: C. fruit_colors.items()

    🔍 해설:

    • items()는 딕셔너리에서 (키, 값) 형태로 꺼낼 수 있도록 해줍니다.
    • values()keys()는 각각 값 또는 키만 꺼내기 때문에 두 변수를 사용할 수 없습니다.

    📝 문제20] 다음 코드 실행 시 출력 결과로 알맞은 것은?

    numbers = [1, 2, 3, 4, 5, 6]
    r_num = reversed(numbers)
    
    print("reversed_numbers:", r_num)
    print(next(r_num))
    print(next(r_num))
    print(next(r_num))
    

    보기: A.

    reversed_numbers: [6, 5, 4, 3, 2, 1]
    6
    5
    4
    

    B.

    reversed_numbers: <list_reverseiterator object at ...>
    6
    5
    4
    

    C.

    reversed_numbers: [1, 2, 3, 4, 5, 6]
    1
    2
    3
    

    D.

    reversed_numbers: <reversed_list>
    3
    4
    5
    

    ✅ 정답: B

    ✅ 출력 결과 예시 (메모리 주소는 실행 환경마다 다름)

    reversed_numbers: <list_reverseiterator object at 0x7f7d0d69ada0>
    6
    5
    4
    

    🔍 해설

    • reversed(numbers)는 역방향으로 값을 꺼낼 수 있는 반복자(iterator)를 반환함
    • next(r_num)으로 하나씩 값을 꺼낼 수 있음

    📝 문제21] enumerate로 라인 넘버 붙여 출력하기 (오타수정됨) 리스트 ["apple", "banana", "cherry"]에 각 항목 앞에 번호를 붙여 출력하세요.

    🖨️ 출력 결과

    1. apple
    2. banana
    3. cherry
    

    ✅ 정답 코드

    fruits = ["apple", "banana", "cherry"]
    for i, fruit in enumerate(fruits, 1):
        print(f"{i}. {fruit}")
    

    🔍 해설

    • enumerate(iterable, start=1) → (인덱스, 값) 반환
    • 반복하면서 순번 매기기 쉽게 가능

    📝 문제22] set comprehension으로 공통 문자 추출 (결과 수정됨) 두 문자열에서 공통된 문자만 추출해서 출력하세요.

    a = "developer"
    b = "explorer"
    

    🖨️ 출력 결과

    {'o', 'r', 'e', 'l', 'p'}
    

    ✅ 정답 코드

    common = {ch for ch in a if ch in b}
    print(common)
    

    🔍 해설

    • set은 중복 제거
    • ch in b 조건으로 공통 문자만 남김

    📝 문제23] 다음 코드 중 실제로 [5, 4, 3, 2, 1] 리스트를 생성하는 코드는?

    list_a = [1, 2, 3, 4, 5]
    list_reversed = ___
    print(list(list_reversed))
    

    보기 A. list_a.reverse()
    B. list_a[::-1]
    C. reversed(list_a)
    D. list(reversed(list_a))

    ✅ 정답: D

    🔍 해설

    • reversed()는 반복자(iterator)를 반환하기 때문에 list()로 감싸야 실제 리스트로 보임
    • list_a.reverse()는 값을 제자리에서 바꿔버리므로 반환값이 None
    • list_a[::-1]는 슬라이싱으로 리스트를 뒤집지만, 질문 조건은 reversed() 함수 기준임

    📝 문제24] 숫자 리스트에서 짝수만 문자열로 바꾸기 리스트 [1, 2, 3, 4, 5, 6]에서 짝수만 골라 문자열 "짝수: 2" 형태로 바꿔 리스트로 만드세요.

    🖨️ 출력 결과

    ['짝수: 2', '짝수: 4', '짝수: 6']
    

    ✅ 정답 코드

    nums = [1, 2, 3, 4, 5, 6]
    result = [f"짝수: {n}" for n in nums if n % 2 == 0]
    print(result)
    

    🔍 해설

    • if n % 2 == 0: 짝수만 선택
    • f"짝수: {n}": 문자열 포맷으로 표현

    📝 문제25] next()와 iter()로 리스트 3개만 출력 리스트 [100, 200, 300, 400, 500]에서 처음 3개만 출력하세요 (반복문 금지).

    🖨️ 출력 결과

    100
    200
    300
    

    ✅ 정답 코드:

    data = [100, 200, 300, 400, 500]
    it = iter(data)
    print(next(it))
    print(next(it))
    print(next(it))
    

    🔍 해설

    • iter()로 이터레이터 생성
    • next()를 직접 호출하여 원하는 수만 꺼냄

    📝 문제26] 리스트에서 짝수 개수 세기 (comprehension + len) 리스트 [10, 15, 22, 33, 40, 55]에서 짝수가 몇 개인지 구하세요.

    🖨️ 출력 결과

    3
    

    ✅ 정답 출력:

    nums = [10, 15, 22, 33, 40, 55]
    count = len([n for n in nums if n % 2 == 0])
    print(count)
    

    🔍 해설

    • 컴프리헨션으로 조건 만족하는 항목만 리스트화
    • len()으로 개수 카운팅

    📝 문제27] 다음 기존 코드를 리스트 내포 방식으로 바꾸면 어떤 코드가 될까요?

    array = []
    
    for i in range(0, 20, 2):
        array.append(i * i)
    

    ❓ 보기 A. [i for i in range(0, 20, 2)]
    B. [i * 2 for i in range(0, 20, 2)]
    C. [i * i for i in range(0, 20, 2)]
    D. [i ** 2 if i % 2 == 0 for i in range(20)]

    ✅ 정답: C

    🖨️ 출력 결과:

    [0, 4, 16, 36, 64, 100, 144, 196, 256, 324]
    

    🔍 해설:

    • range(0, 20, 2)는 0부터 19까지 2씩 증가 → 짝수만 순회
    • i * i는 각 숫자의 제곱값

    📝 문제28] 다음 리스트 내포의 출력 결과는?

    result = [x for x in range(10) if x % 2 == 0]
    print(result)
    

    보기: A. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    B. [1, 3, 5, 7, 9]
    C. [0, 2, 4, 6, 8]
    D. [2, 4, 6, 8, 10]

    ✅ 정답: C

    🔍 해설:

    • range(10) → 0부터 9까지 숫자
    • if x % 2 == 0 → 짝수만 조건 통과
    • 결과는 [0, 2, 4, 6, 8]

    📝 문제29] 사용자에게 이름을 3번 입력받아 리스트에 저장하세요. 그리고 각 이름 앞에 번호를 붙여서 출력하세요.

    🖨️ 출력 예시 (입력: 영희, 민수, 정우):

    1. 영희  
    2. 민수  
    3. 정우
    

    ✅ 정답 코드:

    names = []
    
    for i in range(3):
        name = input(f"{i+1}번째 이름 입력: ")
        names.append(name)
    
    for idx, name in enumerate(names, start=1):
        print(f"{idx}. {name}")
    

    🔍 해설:

    • enumerate(..., start=1)을 사용하면 번호 + 항목을 동시에 가져올 수 있음

    📝 문제30] 다음 3행 2열의 리스트에서 각 요소의 행/열 위치와 값을 출력하고,
    값이 50 이상이면 '🔥 주목' 이라는 표시를 함께 출력하세요.

    nums = [     
    	[10, 20],     
    	[30, 40],     
    	[50, 60] 
    ]
    

    🌟 힌트:

    • enumerate()를 사용해 행/열의 인덱스를 함께 가져옵니다.
    • 조건에 따라 특정 값에만 강조 마크(🔥)를 붙입니다.

    🖨️ 출력 결과:

    00열 → 10   
    01열 → 20   
    10열 → 30   
    11열 → 40   
    20열 → 50 🔥 주목  
    21열 → 60 🔥 주목
    

    ✅ 정답 코드:

    nums = [
        [10, 20],
        [30, 40],
        [50, 60]
    ]
    
    for i, row in enumerate(nums):
        for j, value in enumerate(row):
            if value >= 50:
                mark = "🔥 주목"
            else:
                mark = ""
            print(f"{i}{j}열 → {value} {mark}")
    

    ✅ 정답 코드: 삼항조건식으로 표현

    for i, row in enumerate(nums):
        for j, value in enumerate(row):
            mark = "🔥 주목" if value >= 50 else ""
            print(f"{i}{j}열 → {value} {mark}")
    
    TOP
    preload preload