From 4b54f5feb4c1f3925e67dd7e9b847f4a693ce83e Mon Sep 17 00:00:00 2001 From: erun1012 Date: Sat, 11 Oct 2025 19:55:08 +0900 Subject: [PATCH] add session1 --- Chapter1/pythonic_code(1).md | 76 +++++++++++++++++++++ Chapter1/pythonic_code(2).md | 94 ++++++++++++++++++++++++++ Chapter1/pythonic_code(3).md | 53 +++++++++++++++ Chapter1/pythonic_code(4).md | 124 +++++++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+) create mode 100644 Chapter1/pythonic_code(1).md create mode 100644 Chapter1/pythonic_code(2).md create mode 100644 Chapter1/pythonic_code(3).md create mode 100644 Chapter1/pythonic_code(4).md diff --git a/Chapter1/pythonic_code(1).md b/Chapter1/pythonic_code(1).md new file mode 100644 index 0000000..ac0f4f0 --- /dev/null +++ b/Chapter1/pythonic_code(1).md @@ -0,0 +1,76 @@ +## 1. 컴프리헨션 문법 +> 파이썬의 자료구조 데이터를 **간결하게** 생성할 수 있는 문법 + +### 리스트 컴프리헨션 +> 리스트를 만드는 간결한 방법을 제공 + +```python +numbers = [] +for i in range(5): + numbers.append(i*2) + +#컴프리헨션 표현 +numbers = [i*2 for i in range(5)] +# [0, 2, 4, 6, 8] + +#조건문을 넣어도 됨 +even = [i for i in range(10) if i % 2 == 0] +# [0, 2, 4, 6, 8] + +#if 중첩도 가능 +data = [i for i in range(1,11) if i % 2 == 0 if i<5] +# [0, 2, 4] +``` + +```python +date = [(x,y) for x in range(1,6) for y in range(1,4)] + +# for 문과 비교 +date2 = [] +for i in range(1,6): + for j in range(1,4): + data2.append((i,j)) + +# [(1, 1), (1, 2), (1, 3), +# (2, 1), (2, 2), (2, 3), +# (3, 1), (3, 2), (3, 3), +# (4, 1), (4, 2), (4, 3), +# (5, 1), (5, 2), (5, 3)] +``` + +### 딕셔너리 컴프리헨션 + +**유의할 점 : for문 앞에 키:값을 적는다는 것과 대괄호가 중괄호로 바뀐 것** + +```python +squares = [x: x**2 for x in range(5)] +# {0:0, 1:1, 2:4, 3:9, 4:16} +``` + +zip 함수 결합 +```python +name = ["왕춘삼", "김덕팔", "황갑득"] +age = [23, 14, 42] + +data = {key: value for (key, value) in zip(name, age) if value > 20} + +# 출력결과 +{'왕춘삼': 23, '황갑득': 42} +``` + +### 셋(집합) 컴프리헨션 + +**유의할 점 : 딕셔너리 컴프리헨션과 비슷, 키:값 형태가 아닌 것만 유의** + +```python +unique = {x%3 for x in range(10)} +# {0, 1, 2} +``` + +- 반복문 + 조건문을 한 줄로 표현가능 +- 가독성과 효율성 향상 +- **단, 복잡한 로직은 가독성을 해침** + + +참고 문서 +https://tibetsandfox.tistory.com/25 diff --git a/Chapter1/pythonic_code(2).md b/Chapter1/pythonic_code(2).md new file mode 100644 index 0000000..d23afb4 --- /dev/null +++ b/Chapter1/pythonic_code(2).md @@ -0,0 +1,94 @@ +## 2. 언패킹(Unpacking)과 제너레이터(Generator) + +### 언패킹 +> 여러 값을 한 번에 변수에 풀어 넣는 기능 + +```python +a, b, c = [1, 2, 3] +print(a,b,c) +# 1 2 3 + +#리스트나 튜플 등 반복 가능한 객체면 다 가능 +numbers = [1, 2, 3, 4, 5] +first, *middle, last = numbers +print(first, middle, last) +# 1 {2,3,4}, 5 +``` + +### 제너레이터 +>데이터를 필요할 때만 하나씩 생성하는 지연평가 방식 함수 +```python +def count_up_to(n): + for i in range(1,n+1): + yield i + +for num in count_up_to(5): + print(num) +#1, 2, 3, 4, 5 +``` +함수 안에 yield 키워드를 사용하면 제너레이터이다. +yield가 값을 생성(반환)하고, 함수의 상태는 유지된 채 중단되었다가 +다음 호출로 그 지점에서 재개된다. + +yield 키워드 +```python +def func(): + yield 1 + yield 2 + yield 3 + +foo = func() + +print(next(foo)) # 1 +print(next(foo)) # 2 +print(next(foo)) # 3 +``` +### return 과의 차이점 + +제너레이터 함수는 yield 를 통해 값을 반환. +next 메소드나 for문 순회 등을 통해 값들을 리턴받을 수 있음. +**yield가 호출된다고 해서 함수가 종료되는 것은 아님** + +제너레이터 내부에서 return을 사용하면 현재 값에 상관없이 StopIteration 예외 발생 + +```python +def func(): + print("1 리턴 전") + yield 1 + print("1 리턴 후, 2 리턴 전") + yield 2 + print("2 리턴 후, 3 리턴 전") + yield 3 + print("3 리턴 후") + + +foo = func() + +print(next(foo)) +print(next(foo)) +print(next(foo)) + +1 리턴 전 +1 +1 리턴 후, 2 리턴 전 +2 +2 리턴 후, 3 리턴 전 +3 +``` + + +표현식 : 리스트 컴프리헨션과 동일하지만 **[] 대신 () 사용** +-> 값을 즉시 모두 만들지 않음 + +```python +lst=[x*2 for x in range(5)] +gen=(x*2 for x in range(5)) +``` + +- 전체 시퀀스를 메모리에 올리지 않음 -> 큰 파일, 로그, 스트리밍 데이터 처리에 적합 +- 필요할 때만 계산 -> 파이프라인에서 불필요한 계산 회피 +- 로컬 변수로 상태를 유지하면서 반복 로직 구현 가능 +- **디버깅 복잡, 한 번만 소비 가능. 다시 쓰려면 재생성** + +참고 문서 +https://tibetsandfox.tistory.com/28 diff --git a/Chapter1/pythonic_code(3).md b/Chapter1/pythonic_code(3).md new file mode 100644 index 0000000..7809fa9 --- /dev/null +++ b/Chapter1/pythonic_code(3).md @@ -0,0 +1,53 @@ +## 매직 메서드 +> 클래스에 특수 동작을 정의하는 메서드 (자동 호출됨) / `__이름__` 형식 + +- `__str__` vs `__repr__` + +```python +class User: + def __init__(self, name): + self.name = name + + def __str__(self): + return f"User: {self.name}" # print()용 + + def __repr__(self): + return f"User(name='{self.name}')" # 개발자용 (디버깅) + +user = User("Gahee") +print(user) # User: Gahee +user # User(name='Gahee') +``` + +→ print(user) → `__str__` 호출 + +→ user → `__repr__` 호출 : 대화형 콘솔 or Jupyter 등 + +→ repr(user) → 명시적으로 `__repr__` 호출 + +→ str(user) → 명시적으로 `__str__` 호출 + +→ `__str__` 가 없으면 자동으로 `__repr__` 사용 + + +- `__eq__` (== 비교 연산자 오버라이드) + +```python +class Point: + def __init__(self, x, y): + self.x, self.y = x, y + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + +p1 = Point(1, 2) +p2 = Point(1, 2) +print(p1 == p2) # True +``` + +→ a == b 를 하면, 내부적으로 호출 + +→ 클래스에 `__eq__`를 안 만들면 ==는 ‘객체가 같은 메모리 주소를 가리키는지’ 비교 + +- `__add__` : a + b 를 하면 내부적으로 실행 +- `__len__` : len() 실행하면 내부에서 진짜 리스트의 길이를 반환 \ No newline at end of file diff --git a/Chapter1/pythonic_code(4).md b/Chapter1/pythonic_code(4).md new file mode 100644 index 0000000..71afacd --- /dev/null +++ b/Chapter1/pythonic_code(4).md @@ -0,0 +1,124 @@ +## 데코레이터(Decorator) +> 어떤 함수를 인자로 받아 꾸며준 후 다시 함수로 리턴하는 함수 +> 함수 내부에 변화 주지 않고 로직을 추가하고 싶을 때 사용 +**데코레이터는 꾸며주는 함수 내부에 직접적 수정이나 로직 변환 불가** + +```python +def hello(): + print("안녕!") + +def decorator(func): + def wrapper(): + print("함수 실행 전") + func() + print("함수 실행 후") + return wrapper + +decorated = decorator(hello) +decorated() + +# 함수 실행 전 +# 안녕! +# 함수 실행 후 +``` +어떤 함수를 데코레이터로 꾸며주려면 그 함수의 선언부 위에 @데코레이터명을 적어주면 됨 +@ 문법으로 더 깔끔하게 + +```python +def decorator(func): + def wrapper(): + print("시작") + func() + print("끝") + return wrapper + +@decorator +def greet(): + print("안녕 파이썬!") + +greet() + +# 시작 +# 안녕 파이썬! +# 끝ㅁ +``` + +예시 추가 +```python +def say_hello(): + print("Hello") + +def decorator(func): + def sentence(*args, **kwargs): + print("Nice to meet you") + return func(*args, **kwargs) + + return sentence + +@decorator +def say_hello(): + print("Hello") + +say_hello() + +# 실행 결과 +Nice to meet you +Hello +``` + +데코레이터 동작 파악 +```python +def decorator(func): #1 + def sentence(*args, **kwargs): #3 + print("Nice to meet you") #6 + return func(*args, **kwargs) #7 + + return sentence #4 + +@decorator #3 +def say_hello(): #2 + print("Hello") #8 + + +say_hello() #5 +``` +#1 decorator 함수를 선언 +#2 say_hello 함수 선언 +#3 say_hello 함수를 decorator 함수로 꾸며줌. 이는 variable = decorator(say_hello)와 동일함. 따라서 sentence 함수도 이때 선언 +#4 decorator 함수로 꾸며주었기에 say_hello 함수는 sentence 함수의 로직을 실행 +#5 say_hello 함수 실행 +#6 say_hello 함수는 sentence 함수의 로직을 가지고 있기 때문에 sentence 함수의 로직 실행 +#7 decorator로 꾸며준 함수인 say_hello 함수를 호출하여 리턴 +#8 호출된 say_hello 함수가 실행 + +class와 함께 사용도 가능 +```python +class Decorator: + def __init__(self, func): # 꾸며줄 함수를 매개변수로 전달 + self.func = func # 꾸며줄 함수를 속성에 저장 + + def __call__(self, *args, **kwargs): + print("Nice to meet you") + self.func() #속성에 저장된 함수 호출 + print(f"My name is {args[0]}") + + +@Decorator +def say_hello(): + print("Hello") + + +say_hello("Fox") + +#실행 결과 +Nice to meet you +Hello +My name is Fox +``` + +- 코드의 중복을 최소화하고 재사용성을 높일 수 있음 +- 가독성 높일 수 있음. 로직 수정이 필요할 때도 데코레이터만 수정하면 됨 +- **중첩해서 사용하면 디버깅 난이도 상승** + +참고문서 +https://tibetsandfox.tistory.com/10