파이썬 클로저와 데코레이터

파이썬 프로그래밍에서 클로저와 데코레이터는 고급 주제로 많은 초보자와 중급 개발자에게 혼란을 줄 수 있습니다. 이 강좌에서는 클로저와 데코레이터의 개념을 이해하고, 파이썬 코드에서 어떻게 활용할 수 있는지를 깊이 있게 설명하겠습니다.

클로저란 무엇인가?

클로저는 중첩 함수(내부 함수)를 사용할 때 생성되는 개념입니다. 내부 함수는 외부 함수의 지역 변수를 참조할 수 있으며, 외부 함수의 실행이 끝난 후에도 이러한 변수들을 기억하는 특징을 제공합니다. 이를 통해 내부 함수가 외부 함수의 맥락(context)을 ‘포획’할 수 있게 됩니다.

클로저의 기본 구조

클로저의 구조를 이해하기 위해 간단한 예제를 살펴보겠습니다:

def outer_function(message):
    def inner_function():
        print(message)
    return inner_function

closure = outer_function("안녕하세요, 클로저!")
closure()

위 코드에서 outer_function은 inner_function을 반환합니다. closure는 내부 함수인 inner_function을 참조하며, outer_function의 지역 변수 message에 접근할 수 있게 됩니다. 이때 message 변수는 외부 함수가 종료된 후에도 inner_function에서 접근 가능합니다.

클로저의 응용: 상태 유지

클로저는 함수가 인스턴스를 만들 수 있도록 하여 함수 사용의 유연성을 제공하며, 상태를 유지하고 싶을 때 유용합니다.

def counter():
    count = 0
    
    def increment():
        nonlocal count
        count += 1
        return count
    
    return increment

counter_instance = counter()
print(counter_instance())  # Output: 1
print(counter_instance())  # Output: 2

이 예제에서 increment 함수는 count 변수의 상태를 유지합니다. 이처럼 nonlocal 키워드는 내부 함수가 외부 함수의 변수에 대한 재할당을 할 수 있게 합니다.

데코레이터란 무엇인가?

데코레이터는 기존 함수에 추가적인 기능을 부여하는 강력한 도구입니다. 데코레이터는 함수를 인자로 받는 또 다른 함수로, 함수를 동적으로 변경하거나 확장할 수 있게 합니다.

데코레이터의 기본 구조

데코레이터는 함수를 인수로 받아서 새로운 함수를 반환하는 방식으로 작동합니다:

def simple_decorator(func):
    def wrapper():
        print("무언가를 수행하기 전에")
        func()
        print("무언가를 수행한 후에")
    return wrapper

def basic_function():
    print("나는 기본 함수입니다.")

decorated_function = simple_decorator(basic_function)
decorated_function()

이 코드는 basic_function을 감싸서 전처리와 후처리를 추가합니다.

파이썬 제공 데코레이터 @ 문법

파이썬에서는 함수에 직접 데코레이터를 적용하는 간단한 문법을 제공합니다. @ 기호를 사용하여 함수를 데코레이터로 감쌀 수 있습니다:

@simple_decorator
def another_function():
    print("나는 또 다른 함수입니다.")

another_function()

데코레이터의 실전 예제: 함수 실행 시간 측정

다음은 함수의 실행 시간을 측정하는 데코레이터의 실제 사례입니다:

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} 함수 실행 시간: {end_time - start_time:.4f} 초")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(1)

slow_function()

위 예제에서는 timing_decorator가 slow_function의 실행 시간을 측정하여 출력합니다. 이렇게 함으로써 코드에 직접적으로 영향을 주지 않고도 함수의 동작을 확장할 수 있습니다.

클로저와 데코레이터의 결합

클로저와 데코레이터는 종종 함께 사용되어 강력하고 유연한 프로그램 구조를 만듭니다. 클로저는 데코레이터가 상태를 유지하거나 어떤 데이터에 지속적으로 접근할 수 있게 해줍니다.

결론

이번 강좌에서는 파이썬의 클로저와 데코레이터에 대해 알아보았습니다. 클로저는 함수가 외부 범위의 변수를 캡처하여 참조할 수 있는 능력을 제공하며, 데코레이터는 코드에서 함수를 감싸 확장하는 방법을 제공합니다. 이 두 주제를 잘 이해하면 더욱 효율적이고 강력한 파이썬 코드를 작성할 수 있게 됩니다.

06장 파이썬 프로그래밍, 어떻게 시작해야 할까?

파이썬은 현대 프로그래밍 세계에서 가장 인기 있는 프로그래밍 언어 중 하나로, 그 사용 범위와 응용 분야는 날이 갈수록 확장되고 있습니다. 초보자와 전문가 모두 쉽게 접근할 수 있는 이 언어는 간결함과 생산성을 중요시하는 개발자 사이에서 특히 매력적입니다. 이번 글에서는 파이썬 프로그래밍을 시작하기 위해 필요한 기본적인 정보와 단계별 가이드라인을 제공하겠습니다.

1. 파이썬이란 무엇인가?

파이썬은 Guido van Rossum이 1991년에 처음 발표한 고급 프로그래밍 언어로, 코드의 가독성과 간결함을 최우선으로 고려하여 설계되었습니다. 파이썬의 주요 철학 중 하나는 “가독성이 좋을수록 코드가 더 낫다”라는 것입니다. 이 때문에 파이썬은 다음과 같은 특징을 가지고 있습니다:

  • 쉽고 명확한 문법: 파이썬의 문법은 영어와 유사하여 초보자도 쉽게 배울 수 있습니다.
  • 광범위한 표준 라이브러리: 다양한 분야에 활용할 수 있는 라이브러리를 기본적으로 제공합니다.
  • 플랫폼 독립성: Windows, macOS, Linux 등 다양한 운영 체제에서 실행할 수 있습니다.
  • 느슨한 데이터 타입: 변수에 데이터 타입을 명시적으로 지정할 필요 없이 성격에 따라 다룰 수 있습니다.

2. 파이썬 설치하기

파이썬을 시작하기 위해 첫 번째 단계는 파이썬 인터프리터를 설치하는 것입니다. 설치 과정은 여러분의 운영 체제에 따라 약간씩 다를 수 있습니다. 아래의 단계를 따라 파이썬을 설치해 보세요.

Windows에 파이썬 설치하기

  1. 파이썬 공식 웹사이트로 이동하여 최신 버전을 다운로드합니다.
  2. 다운로드한 설치 파일을 실행하고, 설치 과정에서 “Add Python to PATH” 옵션을 꼭 선택합니다. 이 설정을 통해 명령 프롬프트에서 파이썬 명령어를 사용할 수 있습니다.
  3. 설치가 완료되면 “cmd” 창을 열고 python --version을 입력하여 설치가 정상적으로 완료되었는지 확인합니다.

macOS에 파이썬 설치하기

  1. macOS에는 기본적으로 파이썬이 설치되어 있습니다. 하지만 가장 최신 버전을 사용하기 위해 공식 웹사이트에서 최신 설치 프로그램을 다운로드하는 것이 좋습니다.
  2. 다운로드한 설치 파일을 실행하여 지시에 따라 설치합니다.
  3. 터미널을 열고 python3 --version을 입력하여 설치를 확인합니다.

Linux에 파이썬 설치하기

  1. 대부분의 Linux 배포판에는 기본적으로 파이썬이 설치되어 있습니다. 최신 버전을 설치하거나 업데이트하려면 터미널을 열고 sudo apt-get update와 sudo apt-get install python3 명령을 사용하세요.
  2. 설치가 완료되면 python3 --version을 통해 버전을 확인합니다.

3. 개발 환경 설정

파이썬 설치 후에는 코드를 작성하고 실행할 환경을 설정해야 합니다. 여러 가지 방법이 있지만, 대표적인 도구는 다음과 같습니다:

Python IDLE

Python IDLE은 파이썬과 함께 제공되는 기본 통합 개발 환경(IDE)으로, 가벼운 코드 편집 및 실행 환경을 제공합니다. 간단한 스크립트를 작성하고 실행하는 데 유용합니다.

Visual Studio Code

Visual Studio Code는 Microsoft에서 개발한 IDE로, 광범위한 플러그인 지원과 강력한 디버깅 도구를 제공합니다. 다양한 프로그래밍 언어를 지원하며, 파이썬 개발에도 많이 사용됩니다. Python 확장 플러그인을 설치하여 파이썬 프로그래밍을 시작하세요.

Jupyter Notebook

Jupyter Notebook은 데이터 과학과 머신러닝 프로젝트에 널리 사용되는 도구로, 코드와 설명, 시각화를 하나의 문서에서 결합할 수 있습니다. 설치하려면 pip install jupyter를 입력한 후 jupyter notebook 명령으로 실행합니다.

파이썬으로 하위 디렉터리 검색하기

파일과 디렉터리를 다루는 일은 프로그래밍에서 매우 흔합니다. 특히, 하위 디렉터리를 검색하는 것은 시스템 파일의 정리, 로그 파일의 분석 등 다양한 목적으로 사용됩니다. 이 강좌에서는 파이썬을 사용하여 하위 디렉터리를 효과적으로 검색하는 방법에 대해 자세히 알아보겠습니다.

파이썬은 파일과 디렉터리를 조작할 수 있는 여러 가지 라이브러리를 제공합니다. 이 글에서는 os 모듈과 glob 모듈, 그리고 pathlib 모듈을 사용하여 파이썬에서 하위 디렉터리를 검색하는 방법을 설명할 것입니다. 각 방법의 장단점을 비교하고, 최상의 사용 예제를 제시합니다.“` ### 1. Using the `os` Module “`html

os 모듈 사용하기

os 모듈은 운영체제와 상호작용할 수 있는 다양한 기능을 제공합니다. 이 모듈을 사용하면 파일과 디렉터리를 생성, 삭제, 변경할 수 있고, 파일의 경로와 속성, 권한 등을 조작할 수 있습니다. 특히, os.walk() 함수는 디렉터리 트리를 순회하면서 하위 디렉터리와 파일을 검색하는 데 유용합니다.

os.walk() 함수

os.walk() 함수는 루트 디렉터리부터 시작하여 모든 하위 디렉터리를 순회하면서 경로, 디렉터리명, 파일명을 가져옵니다. 함수의 반환 값은 튜플이며, 각 요소는 (디렉터리 경로, 디렉터리 내의 모든 하위 폴더 목록, 디렉터리 내의 모든 파일 목록)을 포함합니다.


import os

def search_subdirectories(root_dir):
    for dirpath, dirnames, filenames in os.walk(root_dir):
        print(f'현재 디렉터리 경로: {dirpath}')
        print(f'하위 디렉터리들: {dirnames}')
        print(f'파일들: {filenames}')
        print('---------------------')
        
search_subdirectories('/mnt/data')  # 검색할 루트 디렉터리의 경로를 지정하세요.

위 코드에서는 os.walk()를 사용하여 주어진 디렉터리의 모든 하위 디렉터리 및 파일을 출력합니다. 각 경로에 대해 현재 디렉터리, 하위 디렉터리 및 파일들을 콘솔에 출력합니다.

필터링 구현하기

대규모 디렉터리에서 특정 파일 확장자나 이름 패턴만 필요할 경우, 필터링을 통해 원하는 정보만 검색할 수 있습니다. 다음 코드는 사용자가 ‘.txt’ 파일만 검색할 수 있도록 필터링을 시연합니다.


def search_text_files(root_dir):
    for dirpath, dirnames, filenames in os.walk(root_dir):
        text_files = [f for f in filenames if f.endswith('.txt')]
        if text_files:
            print(f'{dirpath}에서 찾은 텍스트 파일: {text_files}')
        
search_text_files('/mnt/data')  # 검색할 디렉터리를 지정하세요.

위의 예에서는 ‘.txt’ 확장자를 가진 파일만 검색하여 출력합니다. 필요에 따라 다른 패턴이나 조건으로 필터링하여 유연하게 사용할 수 있습니다.“` ### 2. Using the `glob` Module “`html

glob 모듈 사용하기

glob 모듈은 유닉스 스타일의 경로 이름 패턴을 사용하여 파일을 검색할 수 있도록 합니다. 간단한 패턴 매칭을 통해 특정 확장자나 이름 패턴에 해당하는 파일을 쉽게 검색할 수 있습니다.

glob.glob() 함수

glob.glob() 함수는 지정한 패턴과 일치하는 모든 경로명을 반환합니다. 파이썬 3.5 이상에서는 ** 패턴을 사용하여 재귀적으로 하위 디렉터리를 검색할 수 있습니다.


import glob

def search_with_glob(pattern):
    files = glob.glob(pattern, recursive=True)
    for file in files:
        print(file)
        
search_with_glob('/mnt/data/**/*.txt')  # 하위 디렉터리까지 포함하여 모든 .txt 파일 검색

위 코드에서는 ** 패턴을 사용하여 모든 텍스트 파일을 대상 디렉터리 및 하위 디렉터리에서 검색합니다. glob 모듈은 사용이 간편하면서도 매우 강력한 파일 검색 기능을 제공합니다.“` ### Conclusion “`html

결론

이번 강좌에서는 파이썬을 사용하여 하위 디렉터리를 검색하는 방법을 배웠습니다. os.walk() 함수는 깊이 우선 탐색을 통한 디렉터리 트리 순회를 가능하게 하며, glob 모듈은 패턴 매칭을 통한 간단하고 강력한 파일 검색을 제공합니다. 각 방법은 사용 목적에 따라 선택하여 적용할 수 있습니다.

파이썬의 또 다른 파일 관련 모듈에는 pathlib가 있으며, 이 모듈은 객체 지향적인 접근 방식을 제공하여 파일 경로 조작을 더욱 직관적으로 수행할 수 있습니다. pathlib에 대해서는 별도의 강좌에서 다루도록 하겠습니다.

이 강좌를 통해 여러분이 파일 탐색 작업을 수행하는 데 필요한 기초와 팁을 얻으셨길 바랍니다. 추가 질문이 있거나 특정 사용 사례에 대해 논의하고 싶으신 경우 아래 댓글 섹션에 남겨주세요.

파이썬 강좌: 탭 문자를 공백 문자 4개로 변환하기

프로그램밍에서 다양한 형식의 데이터를 다루다 보면, 종종 탭(Tab) 문자를 포함한 데이터를 만나게 됩니다. 탭 문자는 텍스트 파일에서 들여쓰기를 구현하거나 데이터를 열로 구분할 때 자주 사용됩니다. 하지만 일부 경우에서는 탭이 아닌 공백 문자로 들여쓰기를 해야 할 상황도 존재합니다. 이 강좌에서는 파이썬을 사용하여 탭 문자를 공백 문자 4개로 변환하는 방법을 자세히 설명하겠습니다.

기본적인 문자열 처리

파이썬에서 문자열 처리는 매우 간단하고 직관적인 작업입니다. 기본적으로 파이썬은 여러 내장 함수를 제공하여 문자열을 조작할 수 있도록 돕습니다. 이 중에서 replace() 메소드는 특정 문자를 다른 문자로 바꾸는 데 유용합니다. 다음은 이 메소드를 사용하는 간단한 예제입니다.


text = "Hello,\tWorld!"
# \t는 탭 문자를 나타냅니다.

# 탭 문자를 공백 문자 4개로 변환
text = text.replace("\t", "    ")
print(text)
    

위의 예제는 ‘Hello,’와 ‘World!’ 사이의 탭 문자를 공백 4개로 대체합니다. 이 방법은 소규모 문자열 처리에 매우 편리합니다.

파일 내의 탭 문자 대체하기

대규모 데이터 파일 또는 스크립트 파일의 모든 탭 문자를 공백으로 대체하는 것 또한 유용합니다. 파이썬에서는 파일 입출력을 통해 간단히 처리할 수 있습니다. 다음은 파일에서 탭 문자를 공백 4개로 변환하는 방법입니다.

1. 파일 읽기

기본적으로 파이썬에서는 open() 함수를 사용하여 파일을 읽을 수 있습니다. 파일을 읽을 때는 일반적으로 읽기 모드(‘r’)를 사용하여 텍스트를 불러옵니다.


# sample.txt 파일에 탭 문자가 포함되어 있다고 가정합니다.
with open("sample.txt", "r") as file:
    content = file.read()
    

2. 탭 문자 대체

파일의 내용을 불러온 후에는 앞서 사용한 replace() 메소드를 다시 활용하여 모든 탭 문자를 공백으로 변경합니다.


content = content.replace("\t", "    ")
    

3. 변경된 내용 파일에 쓰기

변경된 내용을 원본 파일에 다시 쓰거나 새로운 파일로 저장할 수 있습니다. 파일 쓰기는 쓰기 모드(‘w’)로 파일을 열어 수행합니다.


# 탭 문자가 공백으로 변경된 내용을 다시 저장
with open("sample_modified.txt", "w") as file:
    file.write(content)
    

위의 코드는 원본 파일인 ‘sample.txt’의 모든 탭 문자를 찾아 공백 4개로 변환한 후, 결과를 ‘sample_modified.txt’라는 새로운 파일에 저장합니다. 이를 통해 데이터 변환이 끝난 후에도 원본 데이터를 보존할 수 있습니다.

전체 스크립트 실행

지금까지 설명한 내용을 바탕으로 전체 스크립트를 실행하여 시도해볼 수 있습니다. 다음은 위의 모든 과정을 하나로 합친 코드입니다.


def replace_tabs_with_spaces(input_file, output_file):
    """
    주어진 입력 파일의 모든 탭 문자를 공백 문자 4개로 대체하여 출력 파일로 저장합니다.

    :param input_file: 탭 문자가 포함된 원본 파일 경로
    :param output_file: 탭 문자가 공백으로 변경된 내용을 저장할 파일 경로
    """
    with open(input_file, "r") as file:
        content = file.read()
    
    # 탭 문자를 공백 4개로 변환
    content = content.replace("\t", "    ")

    with open(output_file, "w") as file:
        file.write(content)

# 스크립트 실행
replace_tabs_with_spaces("sample.txt", "sample_modified.txt")
    

결론

이 강좌에서는 파이썬을 이용하여 문자열의 탭 문자를 공백 문자 4개로 쉽게 변환하는 방법을 살펴보았습니다. 문자열 자체가 아닌 파일 내의 데이터를 변환하는 방법을 통해 일상 업무의 자동화를 손쉽게 이룰 수 있습니다. 이처럼 파이썬과 같은 강력한 프로그래밍 언어를 활용하면 데이터 변환과 처리를 더욱 효율적으로 수행할 수 있게 됩니다.

이 강좌가 여러분의 프로그래밍 실력을 향상시키는 데 도움이 되었기를 바랍니다. 추가적인 질문이나 더 알고 싶은 것이 있다면 언제든지 댓글로 남겨주세요!

파이썬으로 간단한 메모장 만들기

안녕하세요, 오늘은 간단한 파이썬 메모장 프로그램을 만들어보겠습니다. 이 강좌에서는 PyQt를 사용하여 GUI 어플리케이션을 구축하고, 파일 입출력을 통해 메모를 저장하고 불러오는 방법에 대해 다룰 것입니다. 이를 통해 여러분은 파이썬의 기본적인 GUI 프로그래밍과 파일 처리에 대한 이해를 높일 수 있을 것입니다.

1. 파이썬 GUI 프로그래밍

GUI는 Graphical User Interface의 약자로, 사용자가 쉽게 프로그램을 사용할 수 있도록 하는 그래픽 기반의 인터페이스입니다. PyQt는 파이썬에서 가장 널리 사용되는 GUI 툴킷 중 하나로, 강력하고 다양한 위젯을 제공합니다. 이번 강좌에서는 PyQt5를 사용하여 간단한 메모장을 만들 것입니다.

2. 필요한 도구 설치

먼저 PyQt5를 설치해야 합니다. 다음 명령어를 실행하여 PyQt5를 설치합니다:

pip install PyQt5

3. 프로젝트 구조 설정

프로젝트의 기본 구조를 설정하겠습니다. 프로젝트 폴더를 생성하고, 파이썬 스크립트를 위한 파일을 생성합니다:

mkdir python-notepad
cd python-notepad
touch notepad.py

이제 본격적으로 코드를 작성해 보겠습니다.

4. PyQt5로 GUI 생성하기

PyQt5를 사용할 때는 QWidget 또는 그 상속 클래스의 인스턴스를 사용하여 창을 만들어야 합니다. 기본적인 메모장 인터페이스를 만들기 위해 필요한 요소는 다음과 같습니다:

  • 텍스트 입력을 위한 QTextEdit 위젯
  • 파일을 열고 저장할 수 있는 기능
  • 편리한 메뉴바

4.1. 기본 코드 작성하기

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QTextEdit, QFileDialog, QMessageBox
from PyQt5.QtGui import QIcon

class Notepad(QMainWindow):
    def __init__(self):
        super().__init__()

        # QTextEdit 위젯을 생성합니다
        self.textEdit = QTextEdit(self)
        self.setCentralWidget(self.textEdit)

        # 메모장의 초기 세팅을 합니다
        self.initUI()

    def initUI(self):
        # 메뉴바 생성
        menubar = self.menuBar()

        # 파일 메뉴 생성
        fileMenu = menubar.addMenu('파일')

        # 열기 액션 추가
        openFile = QAction(QIcon('open.png'), '열기', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('파일 열기')
        openFile.triggered.connect(self.showDialog)
        fileMenu.addAction(openFile)

        # 저장 액션 추가
        saveFile = QAction(QIcon('save.png'), '저장', self)
        saveFile.setShortcut('Ctrl+S')
        saveFile.setStatusTip('파일 저장')
        saveFile.triggered.connect(self.saveFile)
        fileMenu.addAction(saveFile)

        # 종료 액션 추가
        exitAction = QAction('종료', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('응용 프로그램 종료')
        exitAction.triggered.connect(self.close)
        fileMenu.addAction(exitAction)

        # 상태바 활성화
        self.statusBar()

        # 메인 윈도우 설정
        self.setGeometry(300, 300, 600, 400)
        self.setWindowTitle('메모장')
        self.show()

    def showDialog(self):
        fname, _ = QFileDialog.getOpenFileName(self, '파일 열기', '/', "Text files (*.txt)")
        
        if fname:
            with open(fname, 'r', encoding='utf-8') as f:
                self.textEdit.setText(f.read())

    def saveFile(self):
        fname, _ = QFileDialog.getSaveFileName(self, '파일 저장', '/', "Text files (*.txt)")
        
        if fname:
            with open(fname, 'w', encoding='utf-8') as f:
                f.write(self.textEdit.toPlainText())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Notepad()
    sys.exit(app.exec_())
    

5. 코드 분석

위 코드는 매우 기본적인 PyQt5 응용 프로그램입니다. 이 코드를 통해 여러분은 파일을 열고, 편집하며, 저장할 수 있는 간단한 메모장 기능을 구현할 수 있습니다. 각 부분은 다음과 같이 구성되어 있습니다:

5.1. Notepad 클래스

Notepad 클래스는 QMainWindow 클래스를 상속하며, PyQt 응용 프로그램에서 윈도우의 주요 기능을 담당합니다. 여기서는 QTextEdit 위젯을 중앙에 배치한 후, 메뉴바를 통해 파일을 열고 저장할 수 있는 기능을 추가했습니다.

5.2. initUI 메서드

메모리의 초기 UI 설정을 담당하며 메뉴바와 상태바를 생성하고, 열기, 저장, 종료와 같은 액션을 메뉴에 추가합니다. 각 액션은 사용자 상호작용에 대해 특정 메서드를 호출하도록 설정되어 있습니다.

5.3. showDialog와 saveFile 메서드

showDialog 메서드는 파일 열기 대화창을 통해 사용자가 선택한 파일을 읽어들여 QTextEdit에 표시합니다. saveFile 메서드는 파일 저장 대화창을 통해 사용자가 지정한 경로에 현재 QTextEdit에 입력된 텍스트를 저장합니다.

6. 마무리

기본적인 파이썬 메모장을 PyQt5를 사용하여 제작하였습니다. 이 프로그램은 파일을 열고 편집하여 저장할 수 있는 간단한 기능을 구현합니다. 이를 통해 PyQt5의 기본적인 사용법과 함께 파이썬을 활용한 GUI 애플리케이션 개발 방법을 익혔습니다. 이 기초적인 메모장 예제를 통해 여러분은 더 복잡하고 다양한 기능을 갖춘 애플리케이션을 제작할 수 있을 것입니다. 꼭 다양한 실습을 통해 능력을 향상시키세요!

감사합니다!