From 14e5158cb96a45e354746e0837b79a5c6ec83ca2 Mon Sep 17 00:00:00 2001 From: joojae02 Date: Fri, 10 Oct 2025 04:35:29 +0900 Subject: [PATCH 1/4] chore: add chapter1 pythonic_code --- chapter1/pythonic_code.md | 223 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 chapter1/pythonic_code.md diff --git a/chapter1/pythonic_code.md b/chapter1/pythonic_code.md new file mode 100644 index 0000000..a09a0b2 --- /dev/null +++ b/chapter1/pythonic_code.md @@ -0,0 +1,223 @@ + +## **1. 컴프리헨션 (Comprehension) 활용법** + +컴프리헨션은 반복문을 사용하지 않고도 List, Dict, Set과 같은 자료구조를 매우 간결하게 생성할 수 있는 기능이다. +for 루프를 한 줄로 압축한 형태로, 가독성과 성능 면에서 이점을 가진다. + +### 리스트 컴프리헨션 (List Comprehension) +- **리스트 컴프리헨션 (List Comprehension)** 가장 일반적으로 사용되는 컴프리헨션으로, 기존 리스트를 기반으로 새로운 리스트를 생성한다. + - **기본 구문:** `[표현식 for 항목 in 반복 가능한 객체 if 조건]` +- **예시:** 0부터 9까지의 숫자 중 짝수만 제곱하여 새로운 리스트 만들기 +```python +# 기본 for문 +squares = [] +for i in range(10): + if i % 2 == 0: + squares.append(i * i) +print(squares) # [0, 4, 16, 36, 64] + +# 리스트 컴프리헨션 활용 +squares_comp = [i * i for i in range(10) if i % 2 == 0] +print(squares_comp) # [0, 4, 16, 36, 64] +``` + +### 딕셔너리 컴프리헨션 (Dictionary Comprehension) +- **딕셔너리 컴프리헨션 (Dictionary Comprehension)** 리스트 컴프리헨션과 유사하게 한 줄로 딕셔너리를 생성할 수 있다. + - **기본 구문:** `{키_표현식: 값_표현식 for 항목 in 반복 가능한 객체 if 조건}` + - **예시:** 단어 리스트를 사용하여 {단어: 단어 길이} 형태의 딕셔너리 만들기 + +```python +words = ['apple', 'banana', 'cherry'] +word_lengths = {word: len(word) for word in words} +print(word_lengths) # {'apple': 5, 'banana': 6, 'cherry': 6} +``` + +### 셋 컴프리헨션 (Set Comprehension) +- **셋 컴프리헨션 (Set Comprehension)** 중복을 허용하지 않는 셋(Set)을 생성할 때 사용한다. + - **기본 구문:** `{표현식 for 항목 in 반복 가능한 객체 if 조건}` +- **예시:** 리스트에 있는 숫자들 중 고유한 셋 만들기 +```python +numbers = [1, 2, 2, 3, 4, 5, 5] +odd_squares = {x for x in numbers if x % 2 != 0} +print(odd_squares) # {1, 2, 3, 4, 5} +``` + +### 속도 차이? + +일반적인 상황에서 List comprehension 의 동작이 유의미하게 빠르다. +아래 예제를 통해 간단하게 확인이 가능하다. +> 정확히 설명하자면 인터프리터 모드인 경우에 유의미하게 빠르다. + +```python +import timeit + +# 테스트할 코드 +setup_code = "numbers = range(10000000)" +for_loop_code = """ +squared_numbers = [] +for x in numbers: + squared_numbers.append(x**2) +""" +comprehension_code = "squared_numbers = [x**2 for x in numbers]" + +# 실행 시간 측정 +for_loop_time = timeit.timeit(stmt=for_loop_code, setup=setup_code, number=1) +comprehension_time = timeit.timeit(stmt=comprehension_code, setup=setup_code, number=1) + +print(f"For loop: {for_loop_time:.6f} seconds") +print(f"List comprehension: {comprehension_time:.6f} seconds") +``` + +```bash +For loop: 0.271319 seconds +List comprehension: 0.245245 seconds +``` + +--- + +### **2. 언패킹(Unpacking)과 제너레이터(Generator)** + +### 언패킹 (Unpacking) +- **언패킹 (Unpacking)** 언패킹은 튜플이나 리스트 같은 시퀀스 자료형의 요소들을 여러 변수에 한 번에 할당하는 기능이다. +- **예시:** +```Python +# 기본 언패킹 +a, b, c = (1, 2, 3) +print(a, b, c) # 1 2 3 + +# *를 이용한 언패킹 (나머지 요소들을 리스트로 받기) +head, *body, tail = [10, 20, 30, 40, 50] +print(head) # 10 +print(body) # [20, 30, 40] +print(tail) # 50 +``` + +### 제너레이터 (Generator) +- **제너레이터 (Generator)** 제너레이터는 모든 값을 메모리에 올리지 않고, 필요할 때마다 값을 하나씩 생성하여 반환하는 **이터레이터(iterator)**를 만드는 기능이다. +- 대용량 데이터를 처리할 때 메모리 효율성을 극대화할 수 있다. 함수 내에서 `yield` 키워드를 사용한다. + - **특징:** + - `yield`를 통해 값을 하나씩 반환하고, 함수의 상태는 그대로 유지된다. + - 다음에 `next()` 함수로 호출되면 이전에 멈췄던 지점부터 다시 실행된다. +- **예시:** 1부터 n까지의 숫자를 생성하는 제너레이터 +```Python +def number_generator(n): + print("Generator starts") + for i in range(1, n + 1): + yield i + print(f"{i} yielded") + +my_gen = number_generator(3) +print(next(my_gen)) # Generator starts, 1 출력 +print(next(my_gen)) # 1 yielded, 2 출력 +print(next(my_gen)) # 2 yielded, 3 출력 +``` + + +--- + +### **3. 매직 메서드 (Magic Methods)** + +매직 메서드(또는 특별 메서드, Special Methods)는 파이썬 클래스 내에서 `__` (더블 언더스코어)로 시작하고 끝나는 특별한 이름의 메서드이다. +이 메서드들은 `+`, `len()`, `print()`와 같은 파이썬의 내장 연산이나 함수가 해당 객체에 사용될 때 자동으로 호출된다. + +- `__init__(self, *args, **kwargs)` + - 클래스의 **생성자(constructor)** 메소드이다. +- `__str__(self)` + - `print()` 함수나 `str()` 내장 함수를 사용하여 객체를 **문자열로 변환**할 때 호출된다. + - 주로 사용자가 보기 쉬운, **비공식적인** 문자열 표현을 반환하는 데 사용된다. +- `__repr__(self)` + - `repr()` 내장 함수를 호출할 때나, 인터프리터에서 객체를 그냥 출력할 때 호출된다. + - 주로 개발자가 디버깅 목적으로 사용하는, 객체를 **명확하게 식별**할 수 있는 **공식적인** 문자열 표현을 반환하는 데 사용된다. `eval(repr(obj)) == obj`가 성립하는 것을 목표로 한다. +- `__eq__(self, other)` + - `==` 연산자를 사용하여 두 객체의 **내용이 같은지** 비교할 때 호출된다. + - 이 메서드를 구현하지 않으면, 기본적으로 두 객체의 메모리 주소를 비교한다. +- **예시:** +```Python +class Person: + def __init__(self, name, age): + self.name = name + self.age = age + + def __str__(self): + return f"{self.name}, {self.age}살" + + def __repr__(self): + return f"Person('{self.name}', {self.age})" + + def __eq__(self, other): + return self.name == other.name and self.age == other.age + +p1 = Person("Alice", 30) +p2 = Person("Alice", 30) +p3 = Person("Bob", 25) + +print(p1) # __str__ 호출 -> Alice, 30살 +print(str(p1)) # __str__ 호출 -> Alice, 30살 +print(repr(p1)) # __repr__ 호출 -> Person('Alice', 30) +print(p1 == p2) # __eq__ 호출 -> True +print(p1 == p3) # __eq__ 호출 -> False +``` + + +--- + +### **4. 데코레이터 (Decorator)** + +데코레이터는 기존 함수의 코드를 수정하지 않으면서, 함수에 **새로운 기능을 추가하거나 수정**할 때 사용하는 강력한 디자인 패턴이다. + +함수를 인자로 받아서, 새로운 기능이 추가된 또 다른 함수를 반환하는 형태로 동작한다. +- 주로 로깅, 실행 시간 측정, 접근 제어 등 AOP(관점 지향 프로그래밍)에 유용하게 사용된다. +- **기본 구조:** +```Python +def decorator_function(original_function): + def wrapper_function(*args, **kwargs): + # --- 함수 실행 전 처리 --- + print(f"{original_function.__name__} 함수 실행 전입니다.") + + result = original_function(*args, **kwargs) # 원래 함수 실행 + + # --- 함수 실행 후 처리 --- + print(f"{original_function.__name__} 함수 실행 후입니다.") + return result + return wrapper_function +``` +- **사용법 (`@` 구문):** 기능을 추가하고 싶은 함수 위에 `@데코레이터_이름`을 붙여준다 +- **예시:** 함수의 실행 시간을 측정하는 데코레이터 +```Python +import time + +def measure_time(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 + +@measure_time +def slow_function(delay): + print(f"{delay}초 대기 시작...") + time.sleep(delay) + print("대기 완료!") + return "완료" + +slow_function(2) + +``` + +**실행 결과:** +``` +2초 대기 시작... +대기 완료! +'slow_function' 실행 시간: 2.0021초 +``` + +## 출처 + +- https://docs.python.org/ko/3.13/tutorial/controlflow.html#unpacking-argument-lists +- https://docs.python.org/ko/3.13/reference/datamodel.html#special-method-names +- https://wikidocs.net/192021 +- https://docs.python.org/ko/3.13/tutorial/datastructures.html#list-comprehensions +- https://docs.python.org/ko/3.13/tutorial/classes.html#iterators +- https://docs.python.org/ko/3.13/tutorial/classes.html#generators \ No newline at end of file From a8e6a6bd86074987697de15efbcbc66621def383 Mon Sep 17 00:00:00 2001 From: joojae02 Date: Fri, 10 Oct 2025 04:44:32 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore:=20markdown=20=EB=AC=B8=EB=B2=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter1/pythonic_code.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapter1/pythonic_code.md b/chapter1/pythonic_code.md index a09a0b2..078a4d3 100644 --- a/chapter1/pythonic_code.md +++ b/chapter1/pythonic_code.md @@ -75,7 +75,7 @@ List comprehension: 0.245245 seconds --- -### **2. 언패킹(Unpacking)과 제너레이터(Generator)** +## **2. 언패킹(Unpacking)과 제너레이터(Generator)** ### 언패킹 (Unpacking) - **언패킹 (Unpacking)** 언패킹은 튜플이나 리스트 같은 시퀀스 자료형의 요소들을 여러 변수에 한 번에 할당하는 기능이다. @@ -115,7 +115,7 @@ print(next(my_gen)) # 2 yielded, 3 출력 --- -### **3. 매직 메서드 (Magic Methods)** +## **3. 매직 메서드 (Magic Methods)** 매직 메서드(또는 특별 메서드, Special Methods)는 파이썬 클래스 내에서 `__` (더블 언더스코어)로 시작하고 끝나는 특별한 이름의 메서드이다. 이 메서드들은 `+`, `len()`, `print()`와 같은 파이썬의 내장 연산이나 함수가 해당 객체에 사용될 때 자동으로 호출된다. @@ -161,7 +161,7 @@ print(p1 == p3) # __eq__ 호출 -> False --- -### **4. 데코레이터 (Decorator)** +## **4. 데코레이터 (Decorator)** 데코레이터는 기존 함수의 코드를 수정하지 않으면서, 함수에 **새로운 기능을 추가하거나 수정**할 때 사용하는 강력한 디자인 패턴이다. From 938eea443859e81b4e06342c6471645c3af79748 Mon Sep 17 00:00:00 2001 From: joojae02 Date: Fri, 10 Oct 2025 04:46:32 +0900 Subject: [PATCH 3/4] chore: add iterator --- chapter1/pythonic_code.md | 74 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/chapter1/pythonic_code.md b/chapter1/pythonic_code.md index 078a4d3..dca263f 100644 --- a/chapter1/pythonic_code.md +++ b/chapter1/pythonic_code.md @@ -92,6 +92,79 @@ print(body) # [20, 30, 40] print(tail) # 50 ``` +### 이터레이터 (Iterator) + +이터레이터는 파이썬에서 **반복 가능한 객체(iterable)**를 순회할 때 사용되는 객체이다. +이터레이터는 `__iter__()`와 `__next__()` 메서드를 구현한 객체로, 한 번에 하나씩 요소를 반환하며 순회 상태를 기억한다. + +#### 이터레이터의 특징 +- **지연 평가(Lazy Evaluation)**: 필요할 때만 값을 생성하므로 메모리 효율적이다 +- **상태 유지**: 현재 위치를 기억하고 다음 호출 시 그 다음 요소를 반환한다 + +#### 이터레이터 vs 이터러블 +- **이터러블(Iterable)**: `__iter__()` 메서드를 가진 객체 (리스트, 튜플, 문자열 등) +- **이터레이터(Iterator)**: `__iter__()`와 `__next__()` 메서드를 모두 가진 객체 + +#### 기본 사용법 +```python +# 리스트는 이터러블이지만 이터레이터는 아니다 +my_list = [1, 2, 3, 4, 5] +print(hasattr(my_list, '__iter__')) # True +print(hasattr(my_list, '__next__')) # False + +# iter() 함수로 이터레이터 생성 +my_iterator = iter(my_list) +print(hasattr(my_iterator, '__next__')) # True + +# next() 함수로 요소 하나씩 가져오기 +print(next(my_iterator)) # 1 +print(next(my_iterator)) # 2 +print(next(my_iterator)) # 3 +``` + +#### 커스텀 이터레이터 클래스 +```python +class CountDown: + def __init__(self, start): + self.current = start + + def __iter__(self): + return self + + def __next__(self): + if self.current <= 0: + raise StopIteration + else: + self.current -= 1 + return self.current + 1 + +# 사용 예시 +counter = CountDown(5) +for num in counter: + print(num) # 5, 4, 3, 2, 1 + +# 또는 next() 함수로 직접 사용 +counter2 = CountDown(3) +print(next(counter2)) # 3 +print(next(counter2)) # 2 +print(next(counter2)) # 1 +``` + +#### 제너레이터와의 관계 +제너레이터는 이터레이터의 한 종류로, `yield` 키워드를 사용하여 더 간단하게 이터레이터를 만들 수 있다: +```python +def countdown_generator(start): + yield start + yield start+1 + yield start+2 + +# 제너레이터는 자동으로 이터레이터가 된다 +gen = countdown_generator(1) +print(next(gen)) # 1 +print(next(gen)) # 2 +print(next(gen)) # 3 +``` + ### 제너레이터 (Generator) - **제너레이터 (Generator)** 제너레이터는 모든 값을 메모리에 올리지 않고, 필요할 때마다 값을 하나씩 생성하여 반환하는 **이터레이터(iterator)**를 만드는 기능이다. - 대용량 데이터를 처리할 때 메모리 효율성을 극대화할 수 있다. 함수 내에서 `yield` 키워드를 사용한다. @@ -217,6 +290,7 @@ slow_function(2) - https://docs.python.org/ko/3.13/tutorial/controlflow.html#unpacking-argument-lists - https://docs.python.org/ko/3.13/reference/datamodel.html#special-method-names +- https://wikidocs.net/134909 - https://wikidocs.net/192021 - https://docs.python.org/ko/3.13/tutorial/datastructures.html#list-comprehensions - https://docs.python.org/ko/3.13/tutorial/classes.html#iterators From 6b024594dc9fa91b4fe306f90a6e5e56ede1a365 Mon Sep 17 00:00:00 2001 From: joojae02 Date: Fri, 10 Oct 2025 04:51:32 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore:=20=EB=8C=80=EC=86=8C=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter1/pythonic_code.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chapter1/pythonic_code.md b/chapter1/pythonic_code.md index dca263f..aa7b7a7 100644 --- a/chapter1/pythonic_code.md +++ b/chapter1/pythonic_code.md @@ -80,7 +80,7 @@ List comprehension: 0.245245 seconds ### 언패킹 (Unpacking) - **언패킹 (Unpacking)** 언패킹은 튜플이나 리스트 같은 시퀀스 자료형의 요소들을 여러 변수에 한 번에 할당하는 기능이다. - **예시:** -```Python +```python # 기본 언패킹 a, b, c = (1, 2, 3) print(a, b, c) # 1 2 3 @@ -172,7 +172,7 @@ print(next(gen)) # 3 - `yield`를 통해 값을 하나씩 반환하고, 함수의 상태는 그대로 유지된다. - 다음에 `next()` 함수로 호출되면 이전에 멈췄던 지점부터 다시 실행된다. - **예시:** 1부터 n까지의 숫자를 생성하는 제너레이터 -```Python +```python def number_generator(n): print("Generator starts") for i in range(1, n + 1): @@ -205,7 +205,7 @@ print(next(my_gen)) # 2 yielded, 3 출력 - `==` 연산자를 사용하여 두 객체의 **내용이 같은지** 비교할 때 호출된다. - 이 메서드를 구현하지 않으면, 기본적으로 두 객체의 메모리 주소를 비교한다. - **예시:** -```Python +```python class Person: def __init__(self, name, age): self.name = name @@ -241,7 +241,7 @@ print(p1 == p3) # __eq__ 호출 -> False 함수를 인자로 받아서, 새로운 기능이 추가된 또 다른 함수를 반환하는 형태로 동작한다. - 주로 로깅, 실행 시간 측정, 접근 제어 등 AOP(관점 지향 프로그래밍)에 유용하게 사용된다. - **기본 구조:** -```Python +```python def decorator_function(original_function): def wrapper_function(*args, **kwargs): # --- 함수 실행 전 처리 --- @@ -256,7 +256,7 @@ def decorator_function(original_function): ``` - **사용법 (`@` 구문):** 기능을 추가하고 싶은 함수 위에 `@데코레이터_이름`을 붙여준다 - **예시:** 함수의 실행 시간을 측정하는 데코레이터 -```Python +```python import time def measure_time(func):