FastAPI는 Python 3.6이상의 API를 빌드하기 위한 빠르고 현대적인 웹 프레임워크이다. 웹 부분을 위한 Starlette와 데이터 부분을 위한 Pydantic 덕분에 NodeJS와 Go에 대등할 정도로 높은 성능을 가지고 있으며, 빠른 코드 작성이 가능하다. 직관적이고 쉬운 코드로 인해 휴먼 에러가 약 40%(내부 개발팀 테스트 기준) 감소했다고 한다. 또한 API에 완전히 호환되는 개방형 표준을 기반으로 하여 Swagger(OpenAPI)와 json Schema를 지원한다.
개인적으로는 Flask와 문법이 비슷하지만 기본적으로 추가된 기능이 많고 Django보다는 자동화(?)는 덜 되었지만 훨씬 가볍고 빠르다는 느낌을 받았다.
공식 문서에서는 위 명령어로 방법을 설명하지만, pip로 "uvicorn[standard]"을 install 하면 에러가 발생하고 명령어로 쳐봐도 당연히 실행되지 않는다. 그래서 아래처럼 python 코드 상에서 실행하는 방법을 찾았다. 실행에 문제가 없고 디버깅 측면에서도 더 좋다고 생각한다.
import os
workspace = "C:\\Users\\Hwan\\Desktop\\TestDir"
keywords = ["pass"]
list_result = []
for file in os.walk(workspace):
if any([True if keyword in file[0] else False for keyword in keywords]): continue
for x in file[2]:
list_result.append(file[0] + "\\" + x)
print(list_result)
코드를 실행하면 입력받은 경로 밑의 (경로나 파일 명에 pass가 포함되지 않은) 모든 파일을 리스트에 담아준다.
이제 입력한 경로 내의 모든 동일한 파일을 찾도록 아래의 코드를 추가했다.
dict_hash = {}
for file in list_result:
try:
dict_hash[my_hash(file)].append(file)
except:
dict_hash[my_hash(file)]= [file]
딕셔너리의 키로 파일 내용을 해싱한 값을 줬고, 값으로는 해당 해쉬값을 갖는 파일명 리스트를 담았다.
아래는 전체 코드이다.
import os
import hashlib
def my_hash(file):
with open(file, 'rb') as f:
read_data = f.read()
hash = hashlib.md5()
hash.update(read_data)
hexSHA512 = hash.hexdigest()
hashValue = hexSHA512.upper()
return hashValue
workspace = "C:\\Users\\hwan\\Desktop"
keywords = ["pass"]
list_result = []
for file in os.walk(workspace):
if any([True if keyword in file[0] else False for keyword in keywords]): continue
for x in file[2]:
list_result.append(file[0] + "\\" + x)
dict_hash = {}
for file in list_result:
try:
dict_hash[my_hash(file)].append(file)
except:
dict_hash[my_hash(file)]= [file]
for x in dict_hash:
if len(dict_hash[x]) > 1:
print(x, dict_hash[x])
파이썬은 자료형이 명시되지 않기 때문에(언어의 동적 특성) 파이썬에서의 문서화는 매우 중요하다.
문서화를 위해서 파이썬은 docstring이라는 문서화 문자열 기능을 제공하고 """ 문서화 문자열입니다. """ 처럼 표현할 수 있다. docstring은 모듈, 클래스, 함수에 붙일 수 있고 각 객체의 __doc__ 속성에 접근하여 문자열을 가져올 수 있다. 어떤 대상에 docstring을 작성할 지에 따라 적어야하는 내용들도 달라진다.
모든 하위 디렉토리 내부 파일까지 포함된 전체 파일의 목록을 가져오기 위해 파이썬으로 코드를 작성하려고 한다.
그런데 디렉토리(또는 폴더) 내부에 하위 디렉토리가 있다면?
그리고 그 디렉토리 내부에 하위 디렉토리가 있는지 없는지 모른다면?
코드를 어떻게 작성해야 될까?
먼저 파이썬에서 경로를 다루기위해 os 패키지를 import 했다.
그리고 아래와 같은 디렉토리 구조(주석)를 만들어 둔 뒤 하위 디렉토리 어딘가에 FindMe.txt 파일을 숨겨두었다!
#Find_TMP
#┣━1234
#┗━TEST
# ┗━TEST1
import os
os 모듈 내부의 메소드들을 사용해서 FindMe.txt 파일이 어디에 있는지 찾아보자.
os.listdir() 메소드를 사용하면 입력한 폴더 내부에 존재하는 파일과 디렉토리를 모두 가져올 수 있다.
def findFiles(root):
files = os.listdir(root)
for file in files:
path = os.path.join(root, file)
if os.path.isdir(path):
print("Directory :", path)
else:
print("File :", path)
findFiles("C:/Users/Hwan/Desktop/Find_TMP")
Find_dir의 하위 디렉토리인 1234와 TEST는 잘 찾았지만 우리가 원하는 FindMe.txt 파일은 찾지 못했다.
1234와 TEST 내부까지 확인하려면 그리고 내부에 우리가 알지 못하는 디렉토리가 있다면 어떻게 해야될까?
재귀를 이용한 디렉토리 탐색
디렉토리 내부에 디렉토리, 그리고 그 내부에 디렉토리 그리고 또 하위 디렉토리.. 만들어둔 구조를 보고 있으면 뭔가 떠오르는 것 같다..!
재귀를 사용해서 모든 경로를 확인해보자.
def findFiles_recursion(path):
for x in os.listdir(path):
subdirectory_path = f"{path}/{x}"
print(subdirectory_path)
if os.path.isdir(subdirectory_path):
findFiles_recursion(subdirectory_path)
findFiles_recursion("C:/Users/Hwan/Desktop/Find_TMP")
우리가 원하던 FindMe.txt 파일을 드디어 찾았다!
위 구조에선 숨겨져있던 Secret 디렉토리 내부까지 확인이 되었다.
하지만 만약 폴더의 구조가 매우 깊다면 재귀를 사용한 함수는 Runtime Error를 뱉는다.
import sys
sys.setrecursionlimit(10000)
물론 이런 코드를 추가하면 좀 더 깊게 탐색할 수는 있지만 스택을 사용하면 더 좋을 것 같다.
코드로 작성해보자.
def findFiles_stack(path):
list_stack = [path]
while list_stack.__len__():
cur_path = list_stack.pop()
for x in os.listdir(cur_path):
_path = os.path.join(cur_path, x)
if os.path.isdir(_path):
list_stack.append(_path)
print(_path)
findFiles_stack("C:/Users/Hwan/Desktop/Find_TMP")
탐색 순서는 조금 다르지만 이제 깊이에 상관없이 FindMe.txt를 찾을 수 있게 되었다!
os.walk
그런데 사실 파이썬의 os 모듈에서는 위에서 고민했던 내용들을 한번에 해결해줄수 있는 메소드를 제공한다.
for x in os.walk("C:/Users/Hwan/Desktop/Find_TMP"):
print(x)
JWT는 웹 표준(RFC 7519) 으로 두 개체 사이에서 JSON을 사용하여 정보를 안전성 있게 전달해준다.
웹에서 로그인을 하거나 인증을 받게되면 보통 세션을 사용하여 인증 정보를 기록하는데, JWT는 토큰 내부의 Signature에 해당 정보를 기록한다. JWT를 사용할 경우 인증을 위해 웹 브라우저의 세션 공간을 사용하지 않고 인증 여부를 알 수 있기 때문에 확장성이 좋다. 또한 생성 시 권한을 지정할 수 있어 각 토큰별로 기능을 제어할 수 있고 플랫폼에 종속적이지 않다.
JWT의 구조는 Header.Payload.Signature로 나뉘어져 있다. Header는 토큰의 typ(해당 토큰의 타입)과 alg(해싱 알고리즘)을 Payload는 토큰에 담을 정보를 그리고 마지막 Signature는 Header와 Paylaod의 Base64 인코딩 값을 시크릿 키와 함께 다시 한번 해싱한 후 인코딩한 값을 가진다.
파이썬의 PyJWT 패키지를 사용해서 직접 토큰을 만들고 검증해보자.
구현
파이썬에서의 jwt 사용은 아래처럼 PyJWT를 설치하거나 requirements.txt에 작성해두고 사용할 수 있다.
# requirements.txt : requests_html, yahoo_fin 추가
import sys
import subprocess
try:
from yahoo_fin.stock_info import *
except:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])
from yahoo_fin.stock_info import *
if __name__ == '__main__':
ticker = "JEPI"
if ticker in tickers_dow():
print("dow")
if ticker in tickers_other():
print("other")
if ticker in tickers_sp500():
print("sp500")
if ticker in tickers_ftse250():
print("ftse250")
if ticker in tickers_ftse100():
print("ftse100")
if ticker in tickers_ibovespa():
print("ibovespa")
if ticker in tickers_nasdaq():
print("nasdaq")
print(get_data(ticker))
후기
yfinance, FinanceDataReader 등을 사용봤지만 전체 티커의 목록을 얻어오거나 실시간 데이터를 얻기엔 불편한 점이 있었다. yahoo_fin에선 여러 소스에서 스크랩과 api를 활용하여 데이터를 받아오기 때문에 실시간 데이터와 전체 목록을 얻어오는 기능이 필요하다면 유용하게 사용할 수 있다. 하지만 내부 코드를 보면 위키피디아 등에서도 데이터를 스크랩해오는데.. 누구나 수정할 수 있는 위키피디아의 특성 상 항상 신뢰하긴 어려울 수도 있을 것 같다.
# Case 1. lambda 함수 정의 후 매개변수 전달
function_lambda = lambda x : x + 1
print("result : ", function_lambda(1))
# result : 2
# Case 2. 한번에 매개변수 전달
print("result : ", (lambda x : x + 1)(1))
# result : 2
# Case 3. 외부 변수 활용
y = 1
print("result : ", (lambda x : x + y)(1))
# result : 2
# Case 4. 여러개의 매개변수 전달
print("result : ", (lambda x, y : x + y)(1, 1))
# result : 2
# Case 5. max 함수의 매개 변수로 사용
print(max((lambda x : [i for i in range(1, x+1)])(10)))
# 10
from pykrx import stock
# 원하는 조건의 티커 목록 얻어오기, market 설정 안해줄 경우 기본은 KOSPI
# 아래 조건은 2021년 6월 1일 기준의 KOSDAQ 상장사들의 티커를 받아옴
tickers = stock.get_market_ticker_list("2021-06-01", market="KOSDAQ") #yyyy-MM-dd
# 각 티커들의 종목이름을 확인
for ticker in tickers:
str_종목이름 = stock.get_market_ticker_name(ticker)
# 시작일~종료일 사이 특정 티커의 OHLCV 정보를 한달 단위로 받아옴 (DateFrame)
df = stock.get_market_ohlcv_by_date("20210101", "20210601", ticker, "m")
print(df.head(6))
# -*- coding: utf-8 -*-
import sys
import pygame
import math
from pygame.locals import *
PI = 3.14159265359
R = 200
screenX = 410
screenY = 410
Ox = screenX / 2
Oy = screenY / 2
# 초당 프레임수를 정의
TARGET_FPS = 30
clock = pygame.time.Clock()
# 색 정의
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
# 실수를 더하기 위해서 만들어줌
def myrange(start, end, step):
r = start
while(r<end):
yield r
r += step
# 인원 수 를 입력받아서 같은 각도로 나눠줌
def auto_line(size):
a = 360.0 / size # 1명 각도
# cnt = 0
tmp = 0 # 각도 누적
x = 0.0
y = 0.0
for tmp in myrange(0, 360, a):
# cnt = cnt + 1
# 간단한 수학 공식으로 좌표 Get
x = R * math.cos(math.radians(tmp))
y = R * math.sin(math.radians(tmp))
#print "[%d] tmp : %.2lf, x : %lf, y : %lf" %(cnt, tmp, x, y)
pygame.draw.line(screen, BLACK, (Ox, Oy), (Ox+x, Oy+y), 2)
# 라이브러리 및 디스플레이 초기화
pygame.init()
num = raw_input("num : ")
screen = pygame.display.set_mode((screenX, screenY), DOUBLEBUF)
pygame.display.set_caption('Hello World!') # 타이틀바의 텍스트를 설정
screen.fill(WHITE)
#pygame.draw.line(screen, RED, (Ox, Oy-R*10), (Ox, Oy+R*10), 1) # y
#pygame.draw.line(screen, RED, (Ox-R*10, Oy), (Ox+R*10, Oy), 1) # x
# 메인 루프
while True:
for event in pygame.event.get():
# 이벤트를 처리하는 부분
if event.type == QUIT:
pygame.quit()
sys.exit()
auto_line(int(num)) # 입력받은 인원 수로 원을 나눠줌
pygame.draw.circle(screen, BLACK, (Ox, Oy), R, 2) # 외부 원
pygame.draw.circle(screen, BLACK, (Ox, Oy), 20) # 중심 원
pygame.display.flip() # 화면 전체를 업데이트
clock.tick(TARGET_FPS) # 프레임 수 맞추기
#-*- coding: utf-8 -*-
import sys
import pygame
from pygame.locals import *
import time
# 초당 프레임수를 정의
TARGET_FPS = 30
clock = pygame.time.Clock()
# 색 정의
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
# 라이브러리 및 디스플레이 초기화
pygame.init()
screen = pygame.display.set_mode((600, 400), DOUBLEBUF) # 윈도우 크기 및 속성 설정
pygame.display.set_caption('돌림판') # 타이틀바의 텍스트를 설정
# 이미지 파일을 로딩
img = pygame.image.load('images.png') # 돌림판 이미지
img2 = pygame.image.load('images2.jpg') # 화살표
degree = 0
flag = True
rad = 100
stop_time = 3 # 돌림판이 멈출 때까지의 시간 (클수록 빨리 멈춤)
# 메인 루프
while True:
for event in pygame.event.get():
# 이벤트를 처리하는 부분
if event.type == QUIT:
pygame.quit()
sys.exit()
# 키보드 이벤트 처리
if event.type == KEYDOWN:
# 스페이스 -> 토글
if event.key == 32:
if flag == True:
flag = False
elif flag == False:
flag = True
rad = 100
# 게임의 상태를 화면에 그려주는 부분
screen.fill(WHITE)
# 이미지 파일 회전하여 그리기
x = 350
y = 200
rotated = pygame.transform.rotate(img, degree) # degree 만큼 회전
rect = rotated.get_rect()
rect.center = (x, y)
screen.blit(rotated, rect)
# 플래그의 상태가 True면 회전, False면 천천히 정지
if flag == True:
degree += rad
elif flag == False:
if rad > 0:
rad -= stop_time
degree += rad
screen.blit(img2, (70, 180)) # 화살표 그리기
pygame.display.flip() # 화면 전체를 업데이트
clock.tick(TARGET_FPS) # 프레임 수 맞추기