본문 바로가기
TIL _Today I Learned/2024.08

[DAY 21] Flask

by gamdong2 2024. 8. 8.
[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 9기
학습일 : 2024.08.08

📕 학습 목록

  • 파이썬 문법 (*args / **kwargs, 데코레이터)
  • 프레임워크 (Flask)

 

📗 기억할 내용

1) 파이썬 문법

① *args / **kwargs

  • at 파이썬, 파라미터를 나타내는 구문
*args
  - 위치 인수의 튜플을 함수에 전달
  - 함수 호출 시 전달된 모든 위치 인수들을 하나의 튜플로 묶어줌

**kwargs
  - 키워드 인수의 딕셔너리를 함수에 전달
  - 함수 호출 시 전달된 모든 키워드 인수들을 하나의 딕셔너리로 묶어줌

*args / **kwargs 결합 사용
  - 두 가지를 함께 사용; 위치 인수 / 키워드 인수 모두 받을 수 있음
# (1) *args 예시

# add_numbers() : 여러 개의 숫자를 받아 그 합계를 계산하는 사용자 정의 함수
# args : 가변 개수의 숫자 인수(튜플)
def add_numbers(*args):
    print(f"args: {args}")  # 인수를 튜플로 출력
    total = sum(args)  # args의 모든 숫자를 더함
    return total

# 함수 호출
print(add_numbers(1, 2, 3)) 
'''
args: (1, 2, 3)
6
'''
print(add_numbers(10, 20, 30, 40))
'''
args: (10, 20, 30, 40)
100
'''
# (2) **kwargs 예시

# print_user_info() : 사용자 정보를 받아 출력하는 사용자 정의 함수
# kwargs : 가변 개수의 키워드 인수(딕셔너리)
def print_user_info(**kwargs):
    print(f"kwargs: {kwargs}")  # 인수를 딕셔너리로 출력
    for key, value in kwargs.items():  # .items() : 딕셔너리의 키-값을 한쌍의 튜플로 반환 (key, value)
    	print(f"{key}: {value}")

# 함수 호출
print_user_info(name="Alice", age=30, city="New York")
'''
kwargs: {'name': 'Alice', 'age': 30, 'city': 'New York'}  # 함수에 전달된 키워드 인수들이 딕셔너리로 변환됨
name: Alice
age: 30
city: New York
'''
# (3) *args / **kwargs 결합 사용

# describe_pet() : 반려동물의 이름, 다양한 특성, 추가 정보를 출력하는 사용자 정의 함수
# pet_name : '애완동물 이름' 인수
# args : '애완동물 특성' 가변 위치 인수
# kwargs : '추가 정보' 가변 키워드 인수
def describe_pet(pet_name, *args, **kwargs):
    print(f"Pet Name: {pet_name}")
    # 특성 출력
    if args:
    	print("Features:")
        for feature in args:
            print(f" - {feature}")   
    # 추가 정보 출력
    if kwargs:
    	print("Additional Info:")
        for key, value in kwargs.items():
            print(f" - {key}: {value}")
            
# 함수 호출
describe_pet("GamDong", "Cute", "Lovely", bread="Poodle", age=5)
'''
Pet Name: GamDong
Features:
 - Cute
 - Lovely
Additional Info:
 - bread: Poodle
 - age : 5
'''

 

② 데코레이터

  • 다른 함수를 인수로 받아 새로운 함수를 반환하는 함수
  • 기존 함수에 추가적인 기능을 부여
  • 코드의 반복을 줄임; 깔끔
# [데코레이터 함수 예제]

# 함수를 인수로 받는 데코레이터 함수
def my_decorator(func):  # say_hello 함수를 인수로 받아 wrapper 함수를 반환
    def wrapper():
    	print("함수 호출 전 작업")
        func()
        print("함수 호출 후 작업")
    return wrapper  # my_decorator 함수는 wrapper 함수를 반환; 데코레이터가 실제로 동작하게 함

# 데코레이터 적용
@my_decorator  # say_hello 함수가 my_decorator 에 의해 장식됨
def say_hello():
    print("안녕하세요!")  
    
say_hello()  # say_hello 함수 호출시, 실제로는 wrapper 함수가 호출됨
    
'''
함수 호출 전 작업
안녕하세요!
함수 호출 후 작업
'''
[작동 순서]
1. say_hello() 함수 호출
2. @데코레이터에 의해, say_hello() 함수가 my_decorator() 함수의 인수로 들어감; func 자리에 옴
3. inner 함수 실행하다가, func() 차례에서 say_hello() 함수 실행
4. 다시 남은 inner 함수 실행
# [매개변수를 가진 함수와 함께 사용]
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("함수 호출 전 작업")
        result = func(*args, **kwargs)
        print("함수 호출 후 작업")
        return result
    return wrapper  # 반환을 안해주면 my_decorator 함수는 wrapper 함수를 정의만 하고 끝남

@my_decorator
def greet(name):
    print(f"안녕하세요, {name}님!")

greet("철수")

'''
함수 호출 전 작업
안녕하세요, 철수님!
함수 호출 후 작업
'''
# [데코레이터 체이닝] : 여러 데코레이터를 하나의 함수에 적용. 데코레이터는 위 → 아래로 적용됨

def decorator1(func)
    def wrapper():
        print("데코레이터 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("데코레이터 2")
        func()
    return wrapper
    
@decorator1
@decorator2
def say_hello():
    print("안녕하세요!")
     
say_hello()

'''
데코레이터1
데코레이터2
안녕하세요!
'''

 

2) 프레임워크

① 라이브러리 vs 프레임워크

  • 라이브러리 (Library)
라이브러리 :  특정 기능을 수행하기 위해 사용자가 호출하는 도구 • 함수들의 집합
- 단순한 기능을 제공
- 개발자가 원하는 라이브러리를 호출하여 사용
  • 프레임워크 (Framework)
프레임워크 : 애플리케이션의 구조와 흐름을 제어하기 위해, 사용자가 작성할 코드의 전체적인 구조를 정해둔 것
- 개발 전체를 진행하는 뼈대 • 기반 구조
- 개발에 대한 전체적인 흐름을 주도
- 프레임워크가 정해준대로 개발자가 개발을 진행
- 프레임워크 내부에 기능구현을 위한 라이브러리 • 코드들 내장

 
② Flask

  • 플라스크 : 파이썬으로 작성된 마이크로 웹 프레임워크    * 마이크로 : 특정 도구 • 라이브러리를 강요하지 x
  • 웹 애플리케이션을 구축하는 데 필요한 핵심 기능을 제공
# [1. Flask 설치]
pip install flask
# [2.Flask 모듈 호출]
# Flask : Flask 애플리케이션을 생성
# request : 클라이언트의 요청 데이터를 다룸
# render_template : HTML 파일을 렌더링   * 렌더링 : 서버가 클라이언트에게 보낼 HTML 페이지를 생성하는 과정.이때 사용되는 것이 템플릿(템플릿:미리 작성된 HTML 파일)
from flask import Flask, request, render_template


# [3. Flask 애플리케이션 생성]
# __name__ : 현재 모듈의 이름을 애플리케이션의 인자로 전달 → Flask 애플리케이션 인스턴스 생성
app = Flask(__name__)


# [4. 홈 페이지 경로 설정]
# 웹 서버가 특정 url 경로에 대해 어떤 기능을 수행할지 정의
@app.route('/')  # 기본 경로('/')로 들어오는 요청을 처리하는 함수; 기본 경로에 대한 route를 설정   * route : url(클라이언트's 요청) - 함수(서버's 처리 로직)를 연결
def home():  # 기본 경로에 접근할 때 실행되는 사용자 정의 함수
    return render_template('home.html')  # home.html 템플릿을 렌더링 → 반환


# [5. 인사말 페이지로 경로 설정]
@app.route('/greet', methods=['POST'])  # '/greet' 경로에 대한 POST 요청을 처리하는 route를 설정
def greet():  # '/greet' 경로에 접근할 때 실행되는 사용자 정의 함수
    name = request.form['name']  # 폼 데이터에서 'name' 값을 호출
    return render_template('greet.html', name=name)  # greet.html 템플릿 렌더링 → name 값을 템플릿에 전달


# [6. 애플리케이션 실행]
if __name__ == '__main__':  # 이 코드가 직접 실행될 때만 Flask 애플리케이션을 실행  # 기본 포트 : 5000번
    app.run(debug=True)  # 애플리케이션 실행  # debug=True : 디버그 모드 활성화; 코드 변경시 자동으로 서버가 재시작 & 오류 발생시 디버그 정보 표시
# [7-1. 템플릿 파일(templates/home.html) 만들기]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <h1>Welcome to the Home Page</h1>
    <form action="/greet" method="post">
        <!-- 사용자로부터 이름을 입력받는 폼 -->
        <label for="name">Enter your name:</label>
        <input type="text" id="name" name="name" required>
        <button type="submit">Submit</button>
    </form>
</body>
</html>

# [7-2. 템플릿 파일(templates/greet.html) 만들기]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Greeting</title>
</head>
<body>
    <!-- 사용자 이름을 표시하는 인사말 페이지 -->
    <h1>Hello, {{ name }}!</h1>
    <a href="/">Go back to Home</a>
</body>
</html>
  • 용어 설명
용어 설명 사용 예
app = Flask(__name__) - 현재 스크립트를 기반으로 Flask 애플리케이션 인스턴스 생성 → 이 인스턴스를 app이라는 변수에 할당
- 추후 이 app 변수를 사용하여 웹 애플리케이션의 다양한 기능 정의•실행
 
Flask - Flask 프레임워크의 핵심 클래스
- 추후 이 클래스를 통해 Flask 애플리케이션 인스턴스 생성
 
인스턴스 - 웹 애플리케이션 그 자체  
app - Flask 애플리케이션 인스턴스를 저장하는 변수
- 추후 이 app 변수를 통해 route 설정 & 서버 실행
 
__name__ - 파이썬의 내장 변수; 모듈(스크립트)의 이름을 나타냄
- Flask는 '__name__' 값을 통해 애플리케이션의 위치를 결정
- 템플릿파일/정적파일의 위치를 찾을 때 '__name__'을 기반으로 기본 경로 설정

- 스크립트를 직접 실행하고 있다면; '__name__' → '__main__' 으로 받음
- 다른 스크립트에서 해당 스크립트를 import 했다면; '__name__' → '그 모듈의 이름(파일명)' 으로 받음
템플릿(template) 파일 - 동적으로 내용을 생성하기 위한 HTML 파일
- 보통 Jinja2라는 템플릿 엔진을 사용하여 Flask 에서 동적 웹페이지를 생성할 때 사용됨
- templates 폴더 안에 위치
- 클라이언트가 http://example.com/ 라는 URL 에 접근했을 때, 어떤 HTML 페이지를 보여줄 지 • 데이터를 처리할지 결정
정적(static) 파일 - 웹페이지 동작에 필요한 이미지/CSS/Javascript 같은 변하지 않는 파일
- static 폴더 안에 위치
 
라우트(route) - 특정 URL에 대한 요청이 들어왔을 때, 실행할 함수를 연결하는 것
- 'URL - 그 URL로 요청이 들어왔을 때 실행될 함수' 를 연결해줌
 
@app.route() 데코레이터 - 'URL 경로(route) - 데코레이터 아래에 있는 함수' 연결
- 그 함수가 해당 URL로 들어오는 요청을 처리
 
동적 라우팅  - URL의 일부를 변수로 처리; 다양한 입력에 대응  
HTTP 메서드 - GET, POST
- 클라이언트(웹 브라우저)가 서버와 통신할 때, 요청의 성격을 지정
 
GET - 데이터 조회
- 클라이언트가 서버로부터 데이터를 요청할 때 사용
- 웹페이지를 요청 • 서버에서 특정 정보를 받아옴
 
POST - 데이터 제출 / 서버 상태 변경
- 클라이언트가 서버에 데이터를 전송할 때 사용
- 폼 데이터를 서버로 제출
- 서버의 상태 • 데이터를 변경

 
 
 
 
 
 

📘 트러블 슈팅

[문제]

  • 문제 내용
출력 과정에서 오류 발생
name = "홍길동"
age = 20
print("안녕하세요," + name "님, 당신의 나이는 " + age + "세입니다.")
{
	"name": "TypeError",
	"message": "can only concatenate str (not \"int\") to str",
	"stack": "---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 3
      1 name = \"홍길동\"
      2 age = 20
----> 3 print(\"안녕하세요,\" + name + \"님, 당신의 나이는 \" + age + \"세입니다.\")

TypeError: can only concatenate str (not \"int\") to str"
}
  • 문제 원인
1종류 이상의 자료형을 한 문장으로 출력하려면; 산술연산자(+)가 아닌 쉼표(,)로 연결

 
[해결]

  • 해결 방법
print("문자열", 변수, "문자열", 변수, "문자열") 의 형태로 출력
  • 해결 결과
name = "홍길동"
age = 20
print("안녕하세요, ", name, "님, 당신의 나이는 ", age, "세입니다.")
안녕하세요,  홍길동 님, 당신의 나이는  20 세입니다.

 

📙 내일 일정

  • 파이썬 프로그래밍(컨테이너 자료형, 조건문, ...) 학습

 
 

 

 

 

 

'TIL _Today I Learned > 2024.08' 카테고리의 다른 글

[DAY 23] Django 웹 애플리케이션 개발  (0) 2024.08.12
[DAY 22] Flask  (0) 2024.08.09
[DAY 20] SQL  (0) 2024.08.07
[DAY 19] API, DB, SQL  (0) 2024.08.06
[DAY 18] HTML, CSS, Javascript  (0) 2024.08.05