Lina's Toolbox

파이썬 심화 강의 복습2 / 정규표현식(regex), glob, itertools, requests, json, csv, 데코레이터(decorator) 본문

스파르타 내일 배움 캠프 AI 웹개발 과정/python

파이썬 심화 강의 복습2 / 정규표현식(regex), glob, itertools, requests, json, csv, 데코레이터(decorator)

Woolina 2024. 7. 9. 11:08

 

 


정규표현식(regex)

 

정규표현식은 regular expression의 약자인 regex라고도 하며 문자열이 특정 패턴과 일치하는지 판단하는 형식 언어입니다. 

 

예를 들어 사용자가 입력한 이메일이 유효한 이메일인지, 유효한 핸드폰 번호를 입력했는지, 대문자로 시작하고 숫자로 끝나는 패턴의 단어가 몇번 반복되는지 등 알파벳, 숫자, 특수문자의 범휘를 지정하는, 다양한 패턴을 지정하고 검증할 수 있습니다.

 

🚨 단, 언어마다 정규식 표현은 다를 수 있음을 주의하세요!

 

 

  • 정규표현식 예제

이메일 형식을 검증할 때 정규표현식을 사용하지 않은 코드와 정규표현식을 사용한 코드를 비교해 보겠습니다.

유효한 이메일인지 판단하는 최소한의 패턴은 아래와 같습니다.

  1. 숫자, 알파벳 대/소문자, 일부 특수문자( - _ . )를 조합한 문자로 시작합니다.
  2. 문자열 중간에는 @가 반드시 1개 포함되어 있어야 합니다.
  3. @ 이후에는 숫자, 알파벳 대/소문자, 일부 특수문자( - _ . )를 조합한 문자가 들어갑니다.
  4. 3번 문자 이후에는 .이 한 개 이상 포함되어 있어야 합니다.
  5. 마지막 . 이후에는 2 ~ 4글자의 숫자, 알파벳 대/소문자, 일부 특수문자( - _ )를 조합한 문자 포함되어 있어야 합니다.

만약 정규표현식 없이 위 조건들을 만족하기 위해서는 아래와 같이 코드를 작성해야 합니다.

# 정규표현식 없이 이메일 검증하기

from pprint import pprint

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
number = "0123456789"
special_char = "-_."

def verify_email(email):
	#.count() : 특정 문자가 몇개 들어있는 지 알려주는 함수
    # 이메일에 @가 한개 포함되어 있는지 확인
    if email.count("@") != 1:
        return False
    
    # @를 기준으로 사용자명과 도메인을 분리
    username, domain = email.split("@")
    
    # username이 1자 이상인지 확인
    if len(username) < 1:
        return False
    
    # 도메인에 한개 이상의 .이 포함되어 있는지 확인
    if domain.count(".") < 1:
        return False
    
    # username에 알파벳, 숫자, 허용된 특수문자 이외의 문자가 포함되어 있는지 확인
    if not all([x in alphabet + number + special_char for x in username]):
        return False
    
    # domain에 알파벳, 숫자, 허용된 특수문자 이외의 문자가 포함되어 있는지 확인
    if not all([x in alphabet + number + special_char for x in domain]):
        return False
    
    # 마지막 .을 기준으로 도메인을 분리
    _, last_level_domain = domain.rsplit(".", 1)
    
    # 마지막 레벨의 도메인의 길이가 2~4글자인지 확인
    if not 2 <= len(last_level_domain) <= 4:
        return False
    
    # 모든 검증이 완료되면 True를 리턴
    return True

test_case = [
    "apple",              # False
    "sparta@regex",       # False
    "$parta@regex.com",   # False
    "sparta@re&ex.com",   # False
    "sparta@regex.com",   # True
    "sparta@regex.co.kr", # True
    "sparta@regex.c",     # False
    "sparta@regex.cooom", # False
    "@regex.com",         # False
]

result = [{x: verify_email(x)} for x in test_case]

pprint(result)

 

 

하지만 정규표현식을 사용할 경우 코드를 매우 간소화 시킬 수 있습니다.

# 정규표현식을 사용해  이메일 검증하기

from pprint import pprint
import re

# rstring : backslash(\)를 문자 그대로 표현
# ^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$ : 이메일 검증을 위한 정규표현식 코드
email_regex = re.compile(r"^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$")

def verify_email(email):
    return bool(email_regex.fullmatch(email))
    
test_case = [
    "apple",              # False
    "sparta@regex",       # False
    "$parta@regex.com",   # False
    "sparta@re&ex.com",   # False
    "spar_-ta@regex.com", # True
    "sparta@regex.co.kr", # True
    "sparta@regex.c",     # False
    "sparta@regex.cooom", # False
    "@regex.com",         # False
]

result = [{x: verify_email(x)} for x in test_case]

pprint(result)
더보기

^ : 시작을 의미

\w : 알파벳 대문자, 소문자, 숫자, 언더바

\. : .

- : -

@ : @가 무조건 하나 있어야함

 

(함께 쓰면 다음과 같은 조합들로 이루어져있어야 한다는 뜻)

 

{2,4} : 2~4회 반복해야함

 

 

 

  • 정규표현식 코드를 짜는 방법?

정규표현식으로 내가 원하는 패턴의 코드를 짜는 것은 직접 짜는 것은 매우 어려운 일입니다. 외울 필요 전혀 ❌

때문에 이미 만들어져 있고, 검증 된 정규표현식을 가져다가 사용하는 것을 권장드리며

위 예제와 같이 이메일 검증, 패스워드 안정성 검증, 핸드폰번호 검증과 같이 대중적으로 많이 사용되는 정규표현식 코드들은 구글에서 검색 해 보면 쉽게 찾아볼 수 있습니다.

혹은 정규표현식의 문법에 대해 설명해주고 많은 예제들을 보여주는 사이트들을 참고하는 것도 좋은 방법입니다.

https://regexr.com/

 

RegExr: Learn, Build, & Test RegEx

RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr.com

 


 

r-string (원시 문자열)

백슬래시(\)가 특별한 의미를 갖지 않고 문자 그대로 해석된다.

# \n : 개행 의미
# \t : 탭 의미 

test = r"\n\ttest"
print(test)

" 출력

\n\ttest

"

파일과 디렉토리 다루기

 

glob 함수는 사용자가 제시한 조건에 맞는 파일명을 리스트 형식으로 반환한다.

💡 glob.glob() : glob 모듈 내에서 정의된 glob 함수 

(glob 모듈은 파이썬 표준 라이브러리에 포함된 모듈 중 하나)

 

  • glob을 활용한 파일 및 디렉토리 목록 확인
from pprint import pprint
import glob

# ./는 현재 python 파일이 위치한 경로를 의미합니다.
# *은 "모든 문자가 일치한다" 라는 의미를 가지고 있습니다.
# ./venv/*은 venv 폴더 내 모든 파일들을 의미합니다.
path = glob.glob("./venv/*")
pprint(path)

# result output
"""
['./venv\\Include', './venv\\Lib', './venv\\pyvenv.cfg', './venv\\Scripts']
"""

# **은 해당 경로 하위 모든 파일을 의미하며, recursive 플래그와 같이 사용합니다.
# *이 하나라면 recursive=True 라도 재귀적으로 탐색하지 않는다. 모든 하위 폴더 탐색하고 싶다면 ** 이렇게 별두개 사용해야함
# recursive를 True로 설정하면 디렉토리 내부의 파일들을 재귀적으로 탐색합니다.
path = glob.glob("./venv/**", recursive=True)
pprint(path)

# result output
"""
['./venv\\',
 './venv\\Include',
 './venv\\Lib',
 './venv\\Lib\\site-packages',
 './venv\\Lib\\site-packages\\autopep8-2.0.1.dist-info',
 ...
]
"""

# *.py와 같이 작성 시 특정 확장자를 가진 파일들만 볼 수 있습니다.
# ./venv/**/*.py는 venv 하위 모든 폴더들을 재귀적으로 탐색하며 .py 확장자 파일을 탐색합니다.
path = glob.glob("./venv/**/*.py", recursive=True)
pprint(path)


# recursive 인수를 명시적으로 설정하지 않으면 기본값은 recursive=False 
# recursive=False=> 따라서, ./venv/**는 ./venv/ 디렉토리와 그 바로 하위 디렉토리만 검색. 
# 하위 디렉토리의 더 깊은 레벨은 검색되지 않습니다.

# result output
"""
['./venv\\Lib\\site-packages\\autopep8.py',
 './venv\\Lib\\site-packages\\pycodestyle.py',
 './venv\\Lib\\site-packages\\pip\\__init__.py',
 './venv\\Lib\\site-packages\\pip\\__main__.py',
 './venv\\Lib\\site-packages\\pip\\__pip-runner__.py',
 ...
]
"""

 

 

 

  • open을 활용한 파일 다루기
# python에서는 파일을 편집하거나 생성할 때, with open 문법을 사용할 수 있습니다.

# "file.txt" : 파이썬에서 사용할 파일을 지정합니다.
# "w" : 파일을 쓰기 모드로 엽니다. 만약 파일이 없다면 새로 생성합니다.
# r, a, 등 다양한 mode가 존재하며, 
# 더 많은 mode의 종류는 (https://docs.python.org/ko/3/library/functions.html#open)
# 서 확인할 수 있습니다.
# encoding : 파일의 encoding 형식을 지정합니다.

# case 1. open 함수를 사용해 파일 열기
# 이렇게 파일명만 적어줄 경우 실행하는 파이썬 파일과 똑같은 위치에서 열겠다는 뜻
# 만약 이 때 해당 파일이 없으면 해당 파일명으로 파일을 생성한다.
f = open("file.txt", "w", encoding="utf-8")
f.write("파이썬 파일 쓰기 테스트!\n")

# open 함수를 실행하면 python 스크립트가 끝날때 까지 파일이 열려있게 됩니다.
# 때문에 파일에 대한 작업이 끝나면 close()를 사용해 파일을 닫아줘야 합니다.
f.close()

# 이때 파일은 닫혀있는 상태이므로 여기서 다시 f.write()를 하면 에러가 발생한다.

# open을 with와 같이 사용하면 with 구문이 끝날 때 자동으로 파일이 close 됩니다.
# 때문에 with를 사용할 떄는 별도로 close 해주지 않아도 됩니다.
# a 모드는 기존 내용을 유지한 상태로 추가합니다. (append)
# w 모드는 기존 파일 내용 상관 없이 새로 덮어쓴다.
# as -> open한 파일이 as 뒤의 변수에 담긴다.
with open("file.txt", "a", encoding="utf-8") as w:
    w.write("파이썬 내용 추가 테스트!")

# r 모드는 파일을 읽기 모드로 엽니다. (read)
# r 모드는 따로 close 해줄 필요가 없습니다. read 문법을 빠져나가는 순간 자동으로 close 됩니다.
with open("file.txt", "r", encoding="utf-8") as r:
    # readlines는 파일의 모든 내용을 list 자료형으로 한번에 읽어들입니다.
    print(r.readlines())


# 파일을 자주 사용할 거라면 f = open ~ 형태로 변수에 담아주어 사용하고,
# 잠깐 사용할 거라면 with 문법을 사용하는게 더 깔끔하며 close를 안해줘서 생기는 문제도 예방할 수 있습니다.


# result output
"""
['파이썬 파일 쓰기 테스트!파이썬 내용 추가 테스트!']
"""

with open("file.txt", "r", encoding="utf-8") as r:
    while True:
        # readline은 파일을 한 줄 씩 읽어들입니다.
        line = r.readline()

        # 파일 끝까지 텍스트를 읽어들였다면 반복문을 중지합니다.
        if not line:
            break

        # 텍스트의 줄바꿈 문자 제거
        line = line.strip()
        print(line)

# result output
"""
파이썬 파일 쓰기 테스트!
파이썬 내용 추가 테스트!
"""

 

더보기

strip() : 문자열에서 불필요한 공백 문자나 특정 문자를 제거

 

strip() 메서드는 문자열의 양 끝에서 공백 문자(스페이스, 탭, 개행 등)를 제거하고,

s.strip()은 문자열 s의 시작과 끝에 있는 공백을 제거한 문자열을 반환 합니다.

s = "   Hello, World!   "
cleaned_s = s.strip()
print(cleaned_s)  # 출력: "Hello, World!"

 

인수와 함께 사용 - 특정 문자 제거

s = "!!!Hello, World!!!"
cleaned_s = s.strip("!")
print(cleaned_s)  # 출력: "Hello, World"

 

여러 문자 제거

s = "xyxHello, World!yx"
cleaned_s = s.strip("xy")
print(cleaned_s)  # 출력: "Hello, World!"

 


 

itertools

 

itertools는 효율적인 루핑을 위한 이터레이터를 만드는 함수입니다.

 

특정 패턴이 무한하게 반복되는 배열을 만들거나 배열의 값을 일괄적으로 계산하는 등의 작업을 할 수 있으며, 이 게시글에서는 조합형 이터레이터에 대해서 다룰 예정입니다.

 

더 많은 이터레이터의  기능들이 궁금하다면 참조 : https://docs.python.org/ko/3/library/itertools.html

 

itertools — Functions creating iterators for efficient looping

This module implements a number of iterator building blocks inspired by constructs from APL, Haskell, and SML. Each has been recast in a form suitable for Python. The module standardizes a core set...

docs.python.org

 

더보기

데카르트 곱

 

  • 데카르트곱 구하기
from itertools import product

sample1 = ["A", "B", "C", "D", "E"]
sample2 = [1, 2, 3, 4]

# 행 / 열을 구분하여 프린트 하기 위해 enumerate 사용
for i, v in enumerate(product(sample1, sample2), 1):
    print(v, end=" ")
    if i % len(sample2) == 0:
        print("")

# result output
"""
('A', 1) ('A', 2) ('A', 3) ('A', 4) 
('B', 1) ('B', 2) ('B', 3) ('B', 4) 
('C', 1) ('C', 2) ('C', 3) ('C', 4) 
('D', 1) ('D', 2) ('D', 3) ('D', 4) 
('E', 1) ('E', 2) ('E', 3) ('E', 4) 
"""

 

더보기

itertools.product() : product(sample1, sample2)는 sample1과 sample2의 모든 가능한 순서쌍(즉, 데카르트 곱)을 생성

[('A', 1), ('A', 2), ('A', 3), ('A', 4), ('B', 1), ('B', 2), ('B', 3), ('B', 4), ('C', 1), ('C', 2), ('C', 3), ('C', 4), ('D', 1), ('D', 2), ('D', 3), ('D', 4), ('E', 1), ('E', 2), ('E', 3), ('E', 4)]

사실 단순히 데카르트 곱을 구하는 코드는 product(sample1, sample2)가 끝이다.

나머지는 표 형태로 출력하기 위한 코드임.

 

enumerate()

인덱스와 값의 튜플을 생성합니다. 

 

enumerate(product(sample1, sample2), 1)

enumerate()는 iterable(여기서는 product(sample1, sample2))의 각 원소에 대해 인덱스와 원소를 튜플로 반환합니다. 여기서 인덱스는 1부터 시작합니다.

 

 

for i, v in enumerate(product(sample1, sample2), 1) :

i(이름은 상관❌, 첫번째 자리)는 인덱스, value(이름은 상관❌, 두번째 자리)는 값을 의미합니다.

 

https://www.geeksforgeeks.org/enumerate-in-python/

 

Enumerate() in Python - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

 

  • 원소의 개수가 n개인 순열
from itertools import permutations

sample = ["A", "B", "C"]

# 원소의 개수가 3개인 순열 출력
for i in permutations(sample, 3):
    print(i)

# result output
"""
('A', 'B', 'C')
('A', 'C', 'B')
('B', 'A', 'C')
('B', 'C', 'A')
('C', 'A', 'B')
('C', 'B', 'A')
"""

itertools.permutations() 함수 : 파이썬에서 순열을 생성하는 데 사용

 

📌 순열(permutation) :  주어진 집합의 원소들을 순서에 따라 배열하는 모든 가능한 경우의 수 (원소 순서 중요)

 

 

 

  • 원소의 개수가 n개인 조합 구하기
from itertools import combinations

sample = ["A", "B", "C"]

# 원소의 개수가 2개인 조합 출력
for i in combinations(sample, 2):
    print(i)

# result output
"""
('A', 'B')
('A', 'C')
('B', 'C')
"""

itertools.combinations() : 주어진 iterable의 원소들 중에서 순서에 관계없이 모든 가능한 조합을 생성 

 

 

  • 원소의 개수가 n개인 조합 구하기(중복 허용)
from itertools import combinations_with_replacement

sample = ["A", "B", "C"]

# 중복을 포함한 원소의 개수가 3개인 조합 출력
for i in combinations_with_replacement(sample, 3):
    print(i)

# result output
"""
('A', 'A', 'A')
('A', 'A', 'B')
('A', 'A', 'C')
('A', 'B', 'B')
('A', 'B', 'C')
('A', 'C', 'C')
('B', 'B', 'B')
('B', 'B', 'C')
('B', 'C', 'C')
('C', 'C', 'C')
"""

 

 

더보기

차이점

  1. 순서의 중요성:
    • permutations: 순서가 중요합니다. 같은 원소라도 순서가 다르면 다른 순열로 간주됩니다.
    • product: 순서가 중요합니다. 각 iterable의 원소를 조합하여 순서쌍을 생성합니다.
    • combinations: 순서가 중요하지 않습니다. 원소의 조합만 고려하며, 순서는 무시됩니다.
  2. 중복:
    • permutations: 원소가 중복되지 않는 경우와 중복되는 경우 모두 처리할 수 있습니다.
    • product: 원소가 중복되어도 모든 조합을 생성합니다.
    • combinations: 원소의 중복이 없다고 가정합니다. 중복 원소를 포함하려면 itertools.combinations_with_replacement()를 사용합니다.

 


 

 

Requests

 

requests란, 파이썬에서 http 통신을 가능하게 해주는 모듈로,

beautifulsoup과 함께 웹 크롤링을 하거나 api 통신이 필요할 때 사용됩니다.

 

더보기

beautifulsoup 라이브러리

HTML과 XML 파일을 파싱(parsing)하고 데이터를 추출하는 라이브러리.

 

웹 스크래핑을 위해 매우 유용한 라이브러리로, HTML과 XML 문서를 쉽게 파싱하고 탐색할 수 있는 강력한 기능을 제공합니다. 다양한 파서를 지원하며, 직관적인 API로 복잡한 문서도 간단하게 처리할 수 있습니다.

 

BeautifulSoup은 bs4라는 패키지로 제공되며, pip 명령어를 통해 쉽게 설치 가능

pip install beautifulsoup4

 

 

따라서 예를 들어, 특정 사이트에서 정보를 가져와서, 내 DB에 저장하고 싶다면

➡️ request 로 데이터 가져오고, beautifulsoup 으로 데이터를 가공하여 저장한다.

 

소셜 로그인 연동, 결제 연동에도 request 사용하여 서버(카카오, 토스 쪽)에 인증정보를 저장한다.

 

즉, 사용자가 https://www.naver.com 이라는 페이지에 접속했을 때 나오는 페이지를

python에서 requests 모듈을 사용하면 해당 데이터를 웹브라우저 없이 코드로 받아올 수 있다는 것을 의미합니다.

 

requests 요청에는 크게 네가지 종류의 method가 존재합니다.

# 이것들은 파이썬의 특징이 ❌, 웹 브라우저에서 서버와 통신할 때 사용되는 방식을 파이썬에서 코드로 구현하는 것 뿐임

여기서는 가장 많이 사용되는 GET 요청과 POST 요청을 다룰 예정입니다.

  • GET : 데이터 정보 요청 (주로 검색에 많이 사용)
  • POST : 데이터 생성 요청
  • PUT : 데이터 수정 요청
  • DELETE : 데이터 삭제 요청

requests를 요청하면 서버에서는 응답(response)을 내려주며, 응답은 내용(content)와 상태 코드(status code)를 받아오게 됩니다.

 

content는 서버에서 사용자에게 주는 응답 본문이며,

status는 통신 과정에서 문제가 있었는지, 정상적으로 작동했는지와 같은, 서버가 어떤 상태인지를 표현해줍니다.

상태 코드는 아래와 같이 이루어져 있으며, 더 많은 상태 코드 정보는 https://developer.mozilla.org/ko/docs/Web/HTTP/Status 서 확인할 수 있습니다.

 

< 자주 사용되는 상태 코드 정보 >

  • 2xx - 성공
    • 200 : 정상 통신 완료
    • 201 : 정상 생성 완료
  • 3xx : 페이지 리다이렉션
    • 301 : url 변경
  • 4xx : 클라이언트 오류
    • 400 : 클라이언트가 잘못 된 요청을 보냄
    • 401 : 인증되지 않은 사용자
    • 403 : 액세스 권한이 없음
  • 5xx : 서버 오류
    • 500 : 서버에서 처리할 수 없음
    • 502 : 게이트웨이에서 잘못된 응답을 받음

사이트에 접속하다 보면 한번씩 보이는 에러에서 502가 status code를 의미합니다.

 

 

 

 

  • requests 모듈로 request 보내보기

requests 모듈을 사용하기 위해서는 먼저 pip install requests 명령어를 사용해 패키지를 설치해야 합니다.

이번에 http 통신 요청을 보내게 될 https://jsonplaceholder.typicode.com/라는 사이트는 다양한 http 요청을 간편하게 테스트 할 수 있는 사이트입니다.

 

get 요청 테스트 코드

import requests
from pprint import pprint

# 통신 할 base url 지정
url = "https://jsonplaceholder.typicode.com/"

# 1번 사용자 정보를 받아오기 위해 users/1 경로에 get 요청
r = requests.get(f"{url}users/1")

pprint({
    "contents": r.text,
    "status_code": r.status_code,
})

# result output
"""
{'contents': '{\n'
             '  "id": 1,\n'
             '  "name": "Leanne Graham",\n'
             '  "username": "Bret",\n'
             '  "email": "Sincere@april.biz",\n'
             '  "address": {\n'
             '    "street": "Kulas Light",\n'
             '    "suite": "Apt. 556",\n'
             '    "city": "Gwenborough",\n'
             '    "zipcode": "92998-3874",\n'
             '    "geo": {\n'
             '      "lat": "-37.3159",\n'
             '      "lng": "81.1496"\n'
             '    }\n'
             '  },\n'
             '  "phone": "1-770-736-8031 x56442",\n'
             '  "website": "hildegard.org",\n'
             '  "company": {\n'
             '    "name": "Romaguera-Crona",\n'
             '    "catchPhrase": "Multi-layered client-server neural-net",\n'
             '    "bs": "harness real-time e-markets"\n'
             '  }\n'
             '}',
 'status_code': 200}
"""

 

 

post 요청 테스트 코드

import requests
from pprint import pprint

# 통신 할 base url 지정
url = "https://jsonplaceholder.typicode.com/"

# 데이터 생성에 사용될 값 지정
data = {
    "name": "sparta",
    "email": "sparta@test.com",
    "phone": "010-0000-0000",
}


# 사용자를 생성하기 위해 users 경로에 data를 담아 post 요청
r = requests.post(f"{url}users", data=data)

pprint({
    "contents": r.text,
    "status_code": r.status_code,
})

# result output
"""
{'contents': '{\n'
             '  "name": "sparta",\n'
             '  "email": "sparta@test.com",\n'
             '  "phone": "010-0000-0000",\n'
             '  "id": 11\n'
             '}',
 'status_code': 201}
"""

 


서버에서 받아온 데이터는 위와 같이 key=value 형태로 되어있는, 딕셔너리와 비슷합니다.

그래서 이것은 딕셔너리 일까요? 아닙니다. 이것들은 "json 스트링"입니다.

 

json 다루기

 

json 이란,  javascript Object Notation의 약자로 데이터를 저장하거나 데이터 통신을 할 때 주로 사용됩니다.

json을 파일로 다룰 때는 .json 확장자를 사용합니다.

json의 형태는 key: value 쌍으로 이루어져 있으며, 파이썬의 dictionary 형태와 매우 유사합니다. 이러한 특성으로 인해 파이썬에서는 json 데이터를 dictionary 데이터로 변경하고, 반대로 dictionary 데이터를 json으로 변경할 수 있습니다.

 

 

  • python에서 json 형태 다뤄보기
# json 모듈을 사용하기 위해 import 합니다.
import json
import requests

# 해당 사이트는 요청에 대한 응답을 json 형태의 문자열로 내려줍니다.
url = "https://jsonplaceholder.typicode.com/"

r = requests.get(f"{url}users/1")
print(type(r.text))  # <class 'str'>

# json.loads()를 사용하여 문자열 형태의 json을 dictionary 자료형으로 형변환
response_content = json.loads(r.text)
print(type(response_content))  # <class 'dict'>

# dictionary 자료형이기 때문에 key를 사용해 value를 확인할 수 있습니다.
print(f"사용자 이름은 {response_content['name']} 입니다.")

# result output
"""
사용자 이름은 Leanne Graham 입니다.
"""
더보기

json.loads() 함수는 파이썬 표준 라이브러리인 json 모듈의 함수로,

JSON 문자열을 파이썬의 기본 데이터 타입(딕셔너리, 리스트 등)으로 변환하는 역할을 합니다.

 

loads는 "load string"의 약자로, JSON 형식의 문자열을 파싱하여 파이썬 객체로 변환합니다.

 

import json

# JSON 형식의 문자열
json_string = '{"name": "Alice", "age": 30, "city": "Wonderland"}'

# JSON 문자열을 파이썬 딕셔너리로 변환
python_dict = json.loads(json_string)

# 결과 출력
print(python_dict)
print(type(python_dict))


"
{'name': 'Alice', 'age': 30, 'city': 'Wonderland'}
<class 'dict'>
"

 

 

데이터 타입 매핑: JSON 형식과 파이썬 데이터 타입 간의 매핑이 자동으로 이루어집니다.

  • JSON 객체 (object) -> 파이썬 딕셔너리 (dict)
  • JSON 배열 (array) -> 파이썬 리스트 (list)
  • JSON 문자열 (string) -> 파이썬 문자열 (str)
  • JSON 숫자 (number) -> 파이썬 정수 (int) 또는 부동 소수점 (float)
  • JSON 참/거짓 (true/false) -> 파이썬 True/False
  • JSON null -> 파이썬 None

⛔️ 단, 이 방법은 서버에서 응답을 json형태로 받았을 때만 사용 가능한 방법으로,

제이슨 형태의 응답이 아닌 경우는 에러가 난다.

json 형태의 response는 보통 다른 서버와 API 연동할 때 주로 사용한다.

 

 


csv

 

csv란, comma-separated values의 약자로 텍스트에 쉼표( , )를 사용해 필드를 구분하며 .csv 확장자를 사용합니다.

쉼표를 사용해 데이터를 구분한다는 특성 덕분에 텍스트 편집기를 사용해 간단한 csv 파일을 만드는 것도 가능합니다.

csv 파일 예시

이렇게 텍스트 편집기(메모장) 뿐만이 아닌, 엑셀 파일로 열어서 보면, 쉼표 기준으로 셀이 나눠져서 잘 보이기는 하지만, 

엑셀 파일과는 다르게 단순 텍스트이다. => 읽고 쓰는 속도가 빠름.

 

 

  • csv 파일 읽기
# 파이썬에서 csv 파일을 다루기 위해 모듈 import
import csv

# 파일명 앞에 경로 지정 안해줄 경우 해당 파이썬 파일과 동일 위치에 있는 파일을 찾는다.
csv_path = "sample.csv"

# csv.reader는 csv를 list 자료형으로 읽는다.
csv_file = open(csv_path, "r", encoding="utf-8")
csv_data = csv.reader(csv_file)
for i in csv_data:
    print(i)

# 작업이 끝난 csv 파일을 꼭 닫아줍니다.
csv_file.close()

# result output
"""
['email', 'birthyear', 'name', 'Location']
['laura@example.com', '1996', 'Laura Grey', 'Manchester']
['craig@example.com', '1989', 'Craig Johnson', 'London']
['mary@example.com', '1997', 'Mary Jenkins', 'London']
['jamie@example.com', '1987', 'Jamie Smith', 'Manchester']
['john@example.com', '1998', 'John', 'Manchester']
"""

# csv를 dict 자료형으로 읽기
csv_file = open(csv_path, "r", encoding="utf-8")
csv_data = csv.DictReader(csv_file)

for i in csv_data:
    print(i)

csv_file.close()

# result output
"""
{'email': 'laura@example.com', 'birthyear': '1996', 'name': 'Laura Grey', 'Location': 'Manchester'}
{'email': 'craig@example.com', 'birthyear': '1989', 'name': 'Craig Johnson', 'Location': 'London'}
{'email': 'mary@example.com', 'birthyear': '1997', 'name': 'Mary Jenkins', 'Location': 'London'}
{'email': 'jamie@example.com', 'birthyear': '1987', 'name': 'Jamie Smith', 'Location': 'Manchester'}
{'email': 'john@example.com', 'birthyear': '1998', 'name': 'John', 'Location': 'Manchester'}
"""

 

 

  • csv 파일 쓰기
# 파이썬에서 csv 파일을 다루기 위해 모듈 import
import csv

csv_path = "sample.csv"

# csv 파일을 쓸 때는 newline='' 옵션을 줘서 중간에 공백 라인이 생기는 것을 방지합니다.
csv_file = open(csv_path, "a", encoding="utf-8", newline='')
csv_writer = csv.writer(csv_file)

# csv에 데이터를 추가합니다.
csv_writer.writerow(["lee@sparta.com", '1989', "lee", "Seoul"])

csv_file.close()

csv_file = open(csv_path, "r", encoding="utf-8")
csv_data = csv.reader(csv_file)
for i in csv_data:
    print(i)

csv_file.close()

# result output
"""
...
['lee@sparta.com', '1989', 'lee', 'Seoul'] # 추가 된 행
"""

 

데코레이터(decorator)

 

데코레이터란 이름 그대로 파이썬의 함수를 장식해주는 역할을 합니다.

데코레이터는 선언되는 함수 위에 골벵이를 사용해 @decorator 형태로 작성하며 해당 함수가 실행될 때 데코레이터에서 선언 된 코드가 같이 실행됩니다.

어떤 함수든 데코레이터를 사용할 수 있습니다!

 

ex) 파이썬 웹서버에서 웹사이트를 인증된 사용자만 실행시키게 하고 싶을 때, 사용자 권한을 체크하기 위해 사용됩니다.

 

  • 데코레이터 코드 구조

데코레이터는 일반 함수와는 다른 특별한 구조를 하고 있습니다.

# 데코레이터는 호출 할 함수를 인자로 받도록 선언합니다.
def decorator(func):
    # 호출 할 함수를 감싸는 wrapper 함수를 선언합니다.
    def wrapper():
        # func.__name__에는 데코레이터를 호출 한 함수의 이름이 들어갑니다.
        print(f"{func.__name__} 함수에서 데코레이터 호출") # 함수 실행 전 실행
        func()
        print(f"{func.__name__} 함수에서 데코레이터 끝") # 함수 실행 후 실행

    # wrapper 함수를 리턴합니다.
    return wrapper

 

 

선언되는 함수 위에 @decorator를 추가해 데코레이터를 사용할 수 있습니다.

@decorator
def decorator_func():
    print("decorator_func 함수 호출")

decorator_func()

# result output
"""
decorator_func 함수에서 데코레이터 호출
decorator_func 함수 호출
decorator_func 함수에서 데코레이터 끝
"""

 

 

  • 데코레이터 예제
# 특정 함수의 실행 시간 구하기
import time
import random

def time_checker(func):
    def wrapper():
        # 함수가 실행될 때 시간을 저장합니다.
        start_time = time.time()

        # 함수를 실행합니다.
        func()

        # 함수가 종료된 후 시간에 실행될 때 시간을 빼 실행 시간을 구합니다.
        executed_time = time.time() - start_time

        # 실행 시간을 소수점 5자리까지만 출력합니다.
        print(f"{func.__name__} 함수의 실행시간 : {executed_time:.05f}s")

    return wrapper

@time_checker
def main():
    # 함수의 실행 시간을 테스트하기 위해 0.1초 ~ 1초간 sleep 합니다.
    time.sleep(random.randint(1, 10) / 10)

for i in range(10):
    main()

# result output
"""
main 함수의 실행시간 : 0.80095s
main 함수의 실행시간 : 0.90009s
main 함수의 실행시간 : 1.00027s
main 함수의 실행시간 : 0.20020s
main 함수의 실행시간 : 0.90011s
main 함수의 실행시간 : 0.60041s
main 함수의 실행시간 : 0.30027s
main 함수의 실행시간 : 0.40024s
main 함수의 실행시간 : 0.10026s
main 함수의 실행시간 : 0.50032s
"""

 

 

 

  • 인자가 있는 함수의 데코레이터 예제
# 입력받은 인자에 2를 곱해주기
def double_number(func):
    def wrapper(a, b):
        # 함수에서 받은 인자에 2를 곱해줍니다.
        double_a = a * 2
        double_b = b * 2

        return func(double_a, double_b)

    return wrapper

# 데코레이터 사용
@double_number
def double_number_add(a, b):
    return a + b

# 데코레이터 사용 안함
def add(a, b):
    return a + b

print(double_number_add(5, 10))
print(add(5, 10))

# result output
"""
30
15
"""