2주차 필기록 통합본

김다피·2026년 1월 27일

SKN-25 필기본

목록 보기
2/14

Day1

🟢클래스,pydantic 외

🔵클래스

자동차 제조사가 같은 이치

스마트폰 부팅 때 로고 뒤에 나오는 것 → 주로 우분투 부팅 코드

  • method : 클래스 안에서 생성된 함수
  • 안에서 돌아가는 로직이라는 뜻 definit

class Student: # 안에서 돌아가는 로직이라는 뜻 def__init__
    def __init__(self, name, korean, math, english, science):
        self.name = name 
        self.korean = korean
        self.math = math
        self.english = english 
        self.science = science 

    def get_data(self):
        return self.name
  • 인스턴스는 서로 독립적이다
data = Student('원빈',100,90,80,70)
data2 = Student('장동건',100,90,80,70)

data2.name ##장동건
data2.get_data() ## 장동건
  • 위에 있던 Student 클래스 그냥 불러와서 자식 클래스 생성
class sk25(Student):
    pass
std1=sk25("서찬웅",100,100,100,100)
std1.name #서찬웅
class sk25(Student):
    def __init__(self, name, korean, math, english, science,phone):
        super().__init__(name,korean,math,english,science)
        self.phone=phone

    def get_math(self):
        return self.math
std1=sk25("서찬웅",100,100,100,100,'01000000000')
std1.name #서찬웅

std1.get_math() #100
std1.phone
dir(sk25)
  • output
a =[1,2,3]
a.__len__() #3
  • 리스트 내부에 내장된 함수 호출해보기
a =[1,2,3]
a.__getitem__(1) #2
class Student:
    def __init__(self,name):
        self._name=name
  • _ 하나 → 속성값들.
a = Student("원빈")
a._name #원빈
a._name = '장동건'
a._name # 장동건

🔵property를 통한 getter setter 등록

class Student:
    def __init__(self,name):
        self._name=name

    @property
    def name(self):
        return self.name
    
    @name.setter
    def name(self,value):
        self._name= value
    
    @name.getter
    def name(self):
        return self.name
  • setter ⇒ 변경
  • getter ⇒ 출력
class Student:
    def __init__(self,name):
        self._name=name

    @property
    def math(self):
        return self.name
    
    @math.setter
    def math(self,value):
        print("setter")
        if 0<=value <=100:
            self._name= value
        else:
            raise ValueError("retry")
    
    @math.getter
    def name(self):
        print("getter")
        return self.name

    def __str__(self): #print 출력을 위한 내장함수
        return self._name
    
b = Student('엔코아')
b.math= 101
  • math가 100 이상이므로 오류 발생
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[44], line 1
----> 1 b.math= 101

Cell In[43], line 15
     13     self._name= value
     14 else:
---> 15     raise ValueError("retry")

ValueError: retry
try:
    b.math= 101
except Exception as e :
    print(e)
    
#setter
#retry

🔵pydantic

  • 일반 파이썬이랑 문법이 좀 다름
  • agent 설계에 주로 사용
  • LLM이 특정 포맷을 내보내도록 하는 기능

🟢가상환경 생성

conda create --name pandas_1 python=3.10
conda activate pandas_1

(pandas_1) C:\Users\rosie>

conda deactivate
  • 가상환경 vscode랑 연결하기
pip install ipykernel
  • 의존성 패키지
    • pip list로 확인
(pandas_1) C:\Users\rosie>python -m ipykernel install --user --name pandas_1 --display-name pandas_1

  • 망이 분리된 상태일 때는 의존성을 pip install 없이 따로 설치해야됨

🔵pypi.org

https://pypi.org/

  • pip install pandas==1.5.3
  • pip list | findstr numpy
  • pip uninstall numpy
  • pip install numpy==1.26.4
import pandas as pd
pd.__version__ #'1.5.3'
  • conda는 버전 변경이 쉽고, 언어 버전 변경이 특히 쉬움
  • virtualenv도 가상환경 구축에 필요하나 파이썬 버전 변경이 어려움

🟢pandas

pd.DataFrame(r.json())
  • json을 함수로 감싸면 dataframe이 됨
from datetime import datetime, date , timedelta
import requests

url = "https://api.stock.naver.com/chart/domestic/item/{}/day?startDateTime={}&endDateTime={}"
url.format('005930', datetime.now().strftime("%Y%m%d") + "0000", datetime.now().strftime("%Y%m%d") + "0000")

r= requests.get(url.format('005930', "202512010000", datetime.now().strftime("%Y%m%d") + "0000")
)

pd.DataFrame(r.json())
  • 1차원 → vector
  • 2차원 → matrix
  • 3차원 → tensor

🔵통계

  • 설명변수 (열)
  • 관측치, 관측데이터(행)

🔵필요 역량

  • 회사가면 1억건, 10억건도 자주 봄
  • 우분투 많이 씀
  • 가상 머신 사용 능력 → container
  • 운영체제 능력
  • sql pandas

🔵numpy

  • 벡터 연산은 한 번에 가능함 → broadcasting 연산
np.array([1,2,3])/10
# array([0.1, 0.2, 0.3])
  • 처리를 편하게 하기 위해서.

🟢코테를 했어요 ^~^

test={1,2,3}
test | {3,4,5}
test &{3,4,5}

test - {3,4,5}

list(set([1,1,2,2,234,5,6,6,7,77,7,89,9,9,9,9,9,0]))
#[0, 1, 2, 5, 6, 7, 9, 234, 77, 89]
  • 집합으로 활용

boj_1302.py

n = int(input())
book_list=[]
for _ in range(n):
    book_list.append(input())

book_counts={}

for book in book_list:
    if book in book_counts:
        book_counts[book]+=1
    else:
        book_counts[book]=1

book_counts=sorted(book_counts.items())

answer_book=''
answer_count=0
for book, count in book_counts:
    if count > answer_count:
        answer_count=count
        answer_book=book

print(answer_book)

"""
강사님 코드. 너무 간단하다...

books = {}
number = int(input())

for _ in range(number):
    name = input()
    if name in books:
        books[name] += 1
    else:
        books[name] = 1
print(sorted(books.items(), key= lambda x : (-x[1], x[0]))[0][0])

"""

🔵큐 생성

  • pandas에도 있는 pop()
from collections import deque
dq =deque()
dq.append(10)
dq.appendleft(20)
print("1.",dq)
dq.append(30)
print("2.",dq)
dq.pop()
print("3.",dq)
dq.popleft()
print("4.",dq)
  1. deque([20, 10])
  2. deque([20, 10, 30])
  3. deque([20, 10])
  4. deque([10])

🟢ip 공부

모델 서빙을 위해 가르치는 것이었음.

  • kt 단말기 → public ip
  • 각자의 컴퓨터 → private ip

ipv4 → 32비트

255 → ff

IPv4 주소 . . . . . . . . . : 192.168.0.8(기본 설정) ⇒ 공유기 따라 다름
서브넷 마스크 . . . . . . . : 255.255.255.0

링크-로컬 IPv6 주소 . . . . : fe80::b451:bca5:61fd:42bd%8(기본 설정)

→ 완전 로컬.

private ip ⇒ 공유기 ⇒ kt 단말기 ⇒ 네이버 서버

pricate ip ⇒ 172~, 192.~

🔵알아야하는 분포

  • 카이제곱분포
  • t분포 ⇒ 기초통계에서 많이 사용
  • 유니폼 분포(연속 균등 분포)

모수적 통계 기법 ⇒ 분포를 알고 분석

비모수적 통계 기법 ⇒ 분포 모르는 상태로 분석

API(Application Programming Interface)

  • 인터페이스는 약속. 다르면 통신이 안됨

REST(ful) API

  • 두 컴퓨터 시스템이 인터넷 통해 정보 교환

🔵크롤링 안잡히는 방법

    time.sleep(abs(random.gauss(0,1)))
  • 가우시안분포로 sleep 걸기
import os 
import requests 
import time, random
from tqdm import tqdm
if not os.path.isdir("./stock"):
    os.mkdir("./stock")
    
past_day = str(date.today() - timedelta(days=30)).replace("-", "") + '0000'
today = str(date.today()).replace("-", "") + '0000'
for x in tqdm(data.split("\n")[1:]):
    # print(i)
    # if i == 10:
    #     break
    y  = x.replace('"', '').split(",")
    if y[2] == 'KOSPI':
        # print(y[0], y[1])
        url = f"https://api.stock.naver.com/chart/domestic/item/{y[0]}/day?startDateTime={past_day}&endDateTime={today}"
        # print(url)
        with open(f"./stock/{y[1]}.csv", "a", encoding='utf-8') as f:
            for x in requests.get(url).json():
                f.write(','.join(map(str,x.values())) + "\n")
    time.sleep(abs(random.gauss(0,1)))

🔵streamlit으로 웹 연결하기

  • localhost:8501
  • 여기서 8501은 port ⇒ 데이터가 왔다갔다 하는 곳
  • port는 2의 16승
streamlit run stock_app.py ip =0.0.0.0

Day2

🟢게임을 만들어볼거라네요…

pip install virtualenv
virtualenv venv
  • virtualenv는 파이썬 환경을 변경할 수 없음
cd venv
cd Scripts
cd activate

(venv) C:\Users\rosie\venv\Scripts>

  • 추후 mcp 배울 예정

🔵MS

  • .net 프레임워크(비쌈.)

    • 스마트팩토리로 가면 만날 수도 있음.
  • 클라우드 azure

  • 구글은 gcp

  • 1등 클라우드는 aws

  • DOS ⇒ powershell

  • red hat

import pygame

pygame.init()

screen = pygame.display.set_mode((800,600))

##============================== 색상 코드 ==============================##
BLUE=(0,0,255)
WHITE=(255,255,255)
RED=(255,0,0)
SKYBLUE=(136,221,221)
BLACK=(0,0,0)
##============================== 색상 코드 ==============================##

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill(SKYBLUE)

##============================== 눈사람 ==============================##

    pygame.draw.circle(screen,WHITE,[400,200],80) #좌표, 지름
    pygame.draw.circle(screen,WHITE,[400,350],100) #좌표, 지름
    pygame.draw.rect(screen, RED, [340,249,130,30], 50)
    pygame.draw.circle(screen, BLACK, [362, 180],5)
    pygame.draw.circle(screen, BLACK, [432, 180],5)
    pygame.draw.circle(screen, BLACK, [400, 200],5)
##============================== 눈사람 ==============================##

    x,y= pygame.mouse.get_pos()

    print(f"{x} {y}")
    pygame.display.flip()

pygame.quit()
  • 이벤트 처리 → 큐

🔵변수명 한 번에 교체 → Ctrl + Shift + L

🔵OOP

  1. overriding

  2. overloading

    1. 매개변수가 다름

🔵random

import random
random.randrange(0,7)

🔵공개키 개인키, RSA

  • 서버 구축할 때 알아야 하는 지식

🔵pyinstaller

  • exe 파일로 묶어내기
pip install pyinstaller
pyinstaller --onefile --windowed ./dino/main.py
  • 실행 시 이미지 파일은 동일 디렉토리에 배치
  • 즉 파이썬과 라이브러리를 묶을 뿐, 외부 디렉토리는 그대로이다

Day3

🟢파라미터 전달(arguments)

import sys
print('출력1',sys.argv[0])
print('출력2',sys.argv[1])
print('출력3',sys.argv[2])

(base) C:\skn-25\wk2>python ./20260107.py 안녕 hi
출력1 ./20260107.py
출력2 안녕
출력3 hi

  • 에러의 대부분 → 권한과 경로….
(base) C:\skn-25\wk2>dir
 C 드라이브의 볼륨에는 이름이 없습니다.
 볼륨 일련 번호: 92F2-D5EF

 C:\skn-25\wk2 디렉터리

ipynb
2026-01-05  오전 11:29               237 requirements.txt        
2026-01-05  오후 04:31    <DIR>          stock
2025-12-31  오후 01:27             1,896 stock.py
2026-01-05  오후 05:53               859 stock_app.py
2026-01-05  오후 04:15    <DIR>          __pycache__
2026-01-05  오후 05:22               114 삼성전자.csv
              10개 파일             440,752 바이트
               4개 디렉터리  68,251,316,224 바이트 남음
  • 파싱 : 원하는 정보만을 가져옴
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name', help='사용자의 이름')
args = parser.parse_args()
print(args.name)

(base) C:\skn-25\wk2>python ./20260107.py nayeon
nayeon

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--name', help='사용자의 이름')
parser.add_argument('--age', help='사용자의 나이')

args = parser.parse_args()
print(args.name, args.age)

(base) C:\skn-25\wk2>python ./20260107.py --name nayeon --age 25
nayeon 25

import argparse

parser= argparse.ArgumentParser()

parser.add_argument('--code',help="종목코드 입력")
parser.add_argument('--sdate',help='시작 날짜')
parser.add_argument('--edate',help='끝 날짜')
parser.add_argument('--type',help='일,주,월 선택')

args = parser.parse_args()
print(args.code, args.sdate, args.edate, args.type)

(base) C:\skn-25\wk2>python get_stock.py --code 005930 --sdate 20260101 --edate 20260106 --type day
005930 20260101 20260106 day

  • third party → 사용자가 까는
import argparse
import requests
## 윗단의 코드들은 다른 코드에서 모듈로 불러올 수 있음
def stock(code, sdate, edate, type_):
    return f"https://api.stock.naver.com/chart/domestic/item/{code}/{type_}?startDateTime={sdate}&endDateTime={edate}"

if __name__=="__main__":
    ## 이 코드를 독단적으로 돌리기 위함. __name__ 이 main인 것임
    ## 터미널에서 실행 시 돌아갈 수 있음
    parser = argparse.ArgumentParser()

    parser.add_argument('--code', help="종목 코드를 입력")
    parser.add_argument('--sdate', help="시작 날짜")
    parser.add_argument('--edate', help="끝 날짜")
    parser.add_argument('--type', help="일, 주, 월 선택")

    args = parser.parse_args()

    # print(args.code, args.sdate, args.edate, args.type)
    print(stock(args.code, args.sdate, args.edate, args.type))

(base) C:\skn-25\wk2>python get_stock.py --code 005930 --sdate 20260101 --edate 20260106 --type day
https://api.stock.naver.com/chart/domestic/item/005930/day?startDateTime=20260101&endDateTime=20260106

  • 터미널에서 실행할 것인지 외부에서 모듈로 사용할 것인지에 따라 name에 넘어가는 인자가 변경됨

  • import 때 다른 python 파일에 같은 함수를 만들 수 있으므로, import 때 * 사용 지양

  • CS 기준 namespaces 문제

from module_b import add
from module_a import add
import folium
import pickle #데이터의 직렬화, 인코딩 깨짐 신경 안써도 됨

with open("./star.pkl","rb") as f:
    data=pickle.load(f)

pickle : 데이터 binary로 저장

  • 운영팀에 모델 넘길 때 (코드도 넘어감)
  • 껐다켰다 할 때 pkl로 저장해서 다음 날 다시 읽어도 됨
    • 오 유용하다~
seoul_map = folium.Map(location=[37.55, 126.88],  tiles="Cartodb Positron", zoom_start=12)

for i in range(len(data['list'])):
    folium.Marker(location=[data['list'][i]['lat'], data['list'][i]['lot']],
                popup=data['list'][i]['s_name']).add_to(seoul_map)

seoul_map.save("./star.html")
  • 저장~

🟢pandas

  • 데이터 손질, 요리에서의 칼질
import pandas as pd

df = pd.DataFrame(data['list'])
df.shape
df.head()
df.tail()
df.isnull().sum() #결측치 체크
df['s_name'] #pandas.core.series.Series
type(df['s_name'].values)  #numpy.ndarray
  • numpy 한 줄 ⇒ series

  • series 묶으면 ⇒ dataframes

  • 결측치 채울 때 지식 중요

    • ex) 탑골공원, 홍대
import numpy as np
np.array(range(0,11)) #벡터로 보면 됨

array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

  • 10을 곱하면 한 번에 다 곱해짐(벡터 연산, 브로드캐스팅)
np.array(range(0,11)) >5

array([False, False, False, False, False, False, True, True, True,
True, True])

mask = np.array(range(0,11)) >5 #로직 설계
np.array(range(0,11))[mask]

array([ 6, 7, 8, 9, 10]법

  • 마스킹 기법
df.isnull().sum()[df.isnull().sum() ==0] #마스크 적용, 얘는 결측치 없음
df2=df[df.isnull().sum()[df.isnull().sum() ==0].index].copy()

df2.shape
df2[['s_name','gugun_name','addr','lot','lat']].head(2)
s_namegugun_nameaddrlotlat
0역삼아레나빌딩강남구서울특별시 강남구 역삼동 721-13 아레나빌딩127.043069
1논현역사거리강남구서울특별시 강남구 논현동 142-2 정일빌딩127.022223
df3.set_index("s_name",inplace=True)
df3.index

Index(['역삼아레나빌딩', '논현역사거리', '신사역성일빌딩', '국기원사거리', '대치재경빌딩', '봉은사역', '압구정윤성빌딩',
'코엑스별마당', '삼성역섬유센터R', '압구정R',
...
'상봉', '중랑역', '중랑구청', '사가정역', '상봉역', '면목역', '묵동', '망우동', '양원역', '중화역'],
dtype='object', name='s_name', length=671)

🔵데이터 접근

  • iloc[열, 행], row, columns
  • loc
df3.iloc[0:2,[3,1]]

df3.loc["역삼아레나빌딩":"신사역성일빌딩",'addr':'lat']

starbucks_agg = df3.gugun_name.value_counts()

gugun_name
강남구 99
서초구 57
중구 54
종로구 43
영등포구 43
송파구 39

import requests

requests.get("https://t1.daumcdn.net/cfile/tistory/272C224C58B4BD540B").json()
  • 서울좌표값

  • 이거 못구했으면 국토부 사이트에서 구해와야함.

  • 시각화가 업무로 넘어간다면 BI

  • Salesforce는 crm 하는 , 슬랙 만든 회사

  • tableau

import folium
import pickle #데이터의 직렬화
import requests
import pandas as pd

with open("./star.pkl","rb") as f:
    data=pickle.load(f)

df = pd.DataFrame(data['list'])
df2=df[df.isnull().sum()[df.isnull().sum() ==0].index].copy()
df3= df2[['s_name','gugun_name','addr','lot','lat']].copy()

starbucks_agg= df3.gugun_name.value_counts()

seoul_sb = folium.Map(location=[37.55, 126.88], tiles="OpenStreetMap", zoom_start=12)
location = requests.get("https://t1.daumcdn.net/cfile/tistory/272C224C58B4BD540B").json()

agg_df = pd.DataFrame(starbucks_agg).reset_index()
folium.Choropleth(location, data=agg_df,columns=['gugun_name', 'count'], fill_color="PuRd",
                 key_on='feature.id').add_to(seoul_sb)

코테 푸는 중인데, 내가 2차원 배열에 아주 약하다는 사실을 깨달았다. 2차원 배열 순환하면서 다 출력하는거 어떻게 하는거더라.

pip list --format=freeze > requirements.txt #덮어쓰기
pip list --format=freeze >> requirements.txt #추가
echo # 터미널에 출력
'201107' > '20260101' #False , 날짜 다루기 조심
hex(ord('a'))
  • C 메모리도 16진수
  • 날짜 다루기 조심하기
  • 너무 많은 데이터는 못읽음
  • 그래서 데이터레이크가 필요함.
  • 뒤에 e-2 : 과학적 표기법

🔵KBO 데이터로 pandas 공부

  • 데이터 전처리(preprocessing)
  • 다 돈 벌려고 하는 짓
  • 수요 예측.
  • 벡터 데이터일 경우 군집도, 코사인 유사도 확인 가능
import pandas as pd
kbo_df= pd.read_csv('./kbo.csv',encoding="utf-8")

kbo_df.head()
kbo_df.loc[1,'경력']
kbo_df.iloc[1,5] #'태전초(경기광주시리틀)-모가중-야로고BC-동원대'

height= int("188cm/88kg	".split('/')[0].replace("cm",""))
weight= int("188cm/88kg	".split('/')[1].replace("kg",""))

round(weight/(height/100)**2,2) #24.9

 
kbo_df['신장']=kbo_df['신장/체중'].apply(lambda x : x.split('/')[0].replace("cm",""))
  • 파생 변수 만들기
kbo_df['신장'] = kbo_df['신장/체중'].apply(lambda x : x.split('/')[0].replace("cm", ""))
kbo_df['체중'] = kbo_df['신장/체중'].apply(lambda x : x.split('/')[1].replace("kg", ""))

kbo_df=kbo_df[kbo_df['신장']!=''].copy()

kbo_df['신장']=kbo_df['신장'].astype(int)
kbo_df['체중']=kbo_df['체중'].astype(int)

kbo_df['bmi']=(kbo_df['체중']/(kbo_df['신장']/100)**2)
kbo_df.sort_values(by=['bmi'],ascending=False).tail()

좀 더 똑똑하게 만들기.

🟢백준 7785 강사쌤 풀이

n = int(input())
list_check = dict()
for _ in range(n):
    name, check = input().split()
    if check == 'enter':
        list_check[name] = 1
    else:
        del list_check[name]

for name, _ in sorted(list_check.items(), key=lambda x : x[0], reverse=True):
    print(name)

🔵POC (proof of concept)

  • IT 용어, 플젝이 이게 되는지 검증하는 것.

Reuters → 유명한 언론 기사, 데이터 비쌈

기업에서 사업하기 전 중요한 task

🔵플젝 흐름도

  • 목적 ⇒ 데이터 수집(DB, 외부 사이트) ⇒ 전처리 ⇒ 모델 학습(분류, 예측)

🔵하둡, 스파크

  • 데이터 레이크(부서별로 사용하는 DB를 한 곳에서 관리하기 위함)

🔵BigQuery

  • LG가 좋아함
  • DB를 클라우드에 올린다.

🔵SCM(공급망 관리)

  • supply chain management.
  • 삼성 → 스마트폰 잘 확인해보면 중국건지 한국건지 구분됨
  • scm 분석가 포지션도 채용함

Day4

  • parquet ⇒ 컬럼 기준의 데이터, 데이터 분석 때 사용
  • 고도화 작업 ⇒ 소프트웨어 업데이트 및 기능 추가

🔵데이터를 나누면

  • 정형 (structured)
    • 엑셀, csv
  • 비정형(unstructured)
    • text, 영상, 음성, 이미지
  • 반정형
    • 사람이 작업하면 정형으로 변경 가능
    • json, xml

리스트 안에 딕셔너리 있는 구조 → 데이터프레임

🟢pandas

kbo_df['생년월일'].isnull().sum()
kbo_df['생년월일'].apply(lambda x : len(x) !=13).sum()
  • 따로 결측치가 없으므로 그대로 날짜로 데이터 가공 진행
from datetime import datetime

kbo_df['days'] = kbo_df['생년월일'].apply(lambda x :  \
            (datetime.now() - datetime.strptime(x, "%Y년 %m월 %d일")).days)
kbo_df.sort_values(by=['days'])
  • 강사님 코드
kbo_df.sort_values(by=['Team','days'],ascending=[True,False])
  • 정렬 기준 컬럼이 2개면, ascending도 선택할 수 있다.
kbo_df[kbo_df['Team']=='고양 히어로즈']
kbo_df.loc[kbo_df['Team']=='고양 히어로즈','Team'] = '키움 히어로즈'
kbo_df['Team'].unique()
  • 마스킹 기법 활용하여 컬럼 정리
kbo_df[(kbo_df['Team']=='LG 트윈스') & (kbo_df['포지션']=='투수(우투우타)')]
kbo_df[(kbo_df['Team']=='LG 트윈스') | (kbo_df['포지션']=='투수(우투우타)')]
  • & → and
    • 둘 다 참인 거만 출력
  • | → or
    • 둘 중 하나 참이면 출력
  • pandas는 내부 연산 때 비트 연산자 사용

🔵다시 초등학교 출력

kbo_df['출신초등학교']=kbo_df['경력'].apply(lambda x : x.split('-')[0])
kbo_df['출신초등학교']

🟢부가지식

🔵streamlit

  • side bar를 공부 중……
  • db 출력도 공부 중…….
  • 와 공부할 거 많은 것 축하한다 짜샤!

🔵정규표현식(regex)

  • 이산수학 베이스
  • gpt한테 맡겨도 괜찮은 부분
import re

p=re.compile("[가-힣a-zA-Z]+초")
kbo_df['출신초등학교'].value_counts()
  • 대괄호 ⇒ 집합

🟢logging

🔵로깅 기본 설정

import logging
import datetime # 예제용

# 로깅 기본 설정 (스크립트 시작 시 한 번만 호출)
log_format = '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
log_datefmt = '%Y-%m-%d %H:%M:%S' # 예: 2025-04-22 10:07:49

logging.basicConfig(level=logging.INFO, # INFO 레벨 이상만 기록
                    format=log_format,
                    datefmt=log_datefmt)

# 이제 로깅 함수 사용 가능
logging.debug("상세 디버깅 정보입니다. (INFO 레벨 설정 시 출력 안 됨)")
logging.info("프로그램이 시작되었습니다. (위치: Seoul)") # 위치 정보 활용
logging.warning("설정 파일 (~/config.ini)을 찾을 수 없어 기본값을 사용합니다.")
logging.error("데이터베이스 연결에 실패했습니다.")
logging.critical("시스템의 주요 구성 요소가 작동하지 않습니다!")

(base) C:\skn-25\wk2>python log.py
2026-01-08 11:23:38 - INFO - root - 프로그램이 시작되었습니다. (위치: Seoul)
2026-01-08 11:23:38 - WARNING - root - 설정 파일 (~/config.ini)을 찾을 수 없어 기본값을 사용합니다.
2026-01-08 11:23:38 - ERROR - root - 데이터베이스 연결에 실패했습니다.
2026-01-08 11:23:38 - CRITICAL - root - 시스템의 주요 구성 요소가 작동하지 않습니다!

root가 뭘 하고 다니는지 체크 가능

🔵로그를 저장해서 확인하다

  • print는 출력만 하고 사라지므로, log로 시스템을 남길 수 있다.
logging.basicConfig(level=logging.INFO, # INFO 레벨 이상만 기록
                    format=log_format,
                    datefmt=log_datefmt)
logging.FileHandler("./logs/mylog.txt",mode='a',encoding='utf-8')

로그파일 핸들러한테 이야기해서 추가하기.

🟢Linux 환경설정

appwiz.cpl

빨간 부분 클릭하고 재부팅

C:\Users\rosie>wsl

다운로드 중: Linux용 Windows 하위 시스템 2.6.3
설치 중: Linux용 Windows 하위 시스템 2.6.3
Linux용 Windows 하위 시스템 2.6.3이(가) 설치되었습니다.
Windows 선택적 구성 요소 설치 중: VirtualMachinePlatform

배포 이미지 서비스 및 관리 도구
버전: 10.0.26100.5074

이미지 버전: 10.0.26100.7462

기능을 사용하도록 설정하는 중
[==========================100.0%==========================]
작업을 완료했습니다.
요청한 작업이 잘 실행되었습니다. 시스템을 다시 시작하면 변경 사항이 적용됩니다.
Linux용 Windows 하위 시스템 설치된 배포가 없습니다.
아래 지침에 따라 배포를 설치하여 이 resolve 수 있습니다.

사용 가능한 배포를 나열하려면 'wsl.exe --list --online' 사용
설치하려면 'wsl.exe --install '를 선택하세요.

unix ⇒ linux ⇒ linux 배포판

🔵linux 배포판

배포판마다 조금씩 다름

  • Redhat
  • Ubuntu
  • Suse
  • 안드로이드

🔵윈도우 하위 리눅스 (wsl)

C:\Users\rosie>wsl --list --online

C:\Users\rosie>wsl --list --online
다음은 설치할 수 있는 유효한 배포 목록입니다.
'wsl.exe --install '을 사용하여 설치합니다.

NAME FRIENDLY NAME
Ubuntu Ubuntu
Ubuntu-24.04 Ubuntu 24.04 LTS
openSUSE-Tumbleweed openSUSE Tumbleweed

C:\Users\rosie>wsl --install Ubuntu-24.04
다운로드 중: Ubuntu 24.04 LTS
설치 중: Ubuntu 24.04 LTS


못생겼당

🔵Ubuntu

rosie@ming9:/mnt/c/Users/rosie$ cd  ## 아직 남의 집이라 제약 있음
rosie@ming9:~$ pwd
/home/rosie
rosie@ming9:~$
  • 딥러닝에서 활용

  • tensorflow는 작업시 wsl 사용하라고 가이드 존재.

  • 코랩도 리눅스 기반.(굳이 따지면 컨테이너 기반)

  • cd : change directory → 그냥 치면 home으로 감.

  • pwd : 현재 경로

  • mnt : docking, 연결이라는 뜻.

    • 즉 외부 장비를 연결했다는 뜻으로 볼 수 있따.
rosie@ming9:~$ whoami
rosie
rosie@ming9:~$ pwd
/home/rosie
  • 사용자, 위치 체크 (중요!!!)
rosie@ming9:~$ sudo su
[sudo] password for rosie:
root@ming9:/home/rosie# pwd
/home/rosie
root@ming9:/home/rosie# whoami
root
root@ming9:/home/rosie# exit
exit
  • root는 절대 권력자.
  • rooting 하면 맘대로 가능한데 제조사에서 가만히 보고 있지 않음.
vim ~/.bashrc
  • vim 접속
  • I로 insert 켜기
  • cd 입력
  • esc 입력
  • :wq 로 나가기
  • exit
  • wsl
rosie@ming9:~$ ls -al
total 32
drwxr-x--- 3 rosie rosie 4096 Jan  8 14:22 .
drwxr-xr-x 3 root  root  4096 Jan  8 12:43 ..
-rw------- 1 rosie rosie   49 Jan  8 14:22 .bash_history
-rw-r--r-- 1 rosie rosie  220 Jan  8 12:43 .bash_logout
-rw-r--r-- 1 rosie rosie 3774 Jan  8 14:22 .bashrc
drwx------ 2 rosie rosie 4096 Jan  8 12:43 .cache
-rw-rw-r-- 1 rosie rosie    0 Jan  8 12:43 .motd_shown
-rw-r--r-- 1 rosie rosie  807 Jan  8 12:43 .profile
-rw-r--r-- 1 rosie rosie    0 Jan  8 14:12 .sudo_as_admin_successful
-rw------- 1 rosie rosie 1475 Jan  8 14:22 .viminfo
rosie@ming9:~$

파일에서 . 찍혀있으면 숨겨진 파일

ls -al이면 숨겨진 것도 보이고, ls로만 하면 안보임

순서대로

파일인지 디렉토리인지 / 소유주/ 소유그룹 / 제 3자

  • 3자리 수 기준으로 2진수로 권한 대화함
  • rw- r— r —
    • 4 2 1 기준으로 연산하여 표기
    • ex) 권한을 700으로 걸어라
rosie@ming9:~$ echo 'hi' >encore.txt
rosie@ming9:~$ chmod 700 ./encore.txt # 권한 변경
-rwx------ 1 rosie rosie    3 Jan  8 14:30 encore.txt #변경됨
rosie@ming9:~$ mkdir workspace
rosie@ming9:~$ cd workspace/

rosie@ming9:~/workspace$ python3
Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
  • apt ⇒ 리눅스에서의 pip
  • sudo ⇒ 권한 빌림
rosie@ming9:~/workspace$ sudo apt update
  • 그냥 pip 다운로드 시 안되므로 update 진행시킴
  • 그 이후 명령어로 다운로드 하기
rosie@ming9:~/workspace$ sudo apt install python3-pip
rosie@ming9:~/workspace$ apt-get moo
                 (__)
                 (oo)
           /------\/
          / |    ||
         *  /\---/\
            ~~   ~~
..."Have you mooed today?"...
pip3 install virtualenv --break-system-packages
rosie@ming9:~/workspace$ ls
encore
rosie@ming9:~/workspace$ ls -al
total 12
drwxr-xr-x 3 rosie rosie 4096 Jan  8 14:42 .
drwxr-x--- 5 rosie rosie 4096 Jan  8 14:42 ..
drwxr-xr-x 4 rosie rosie 4096 Jan  8 14:42 encore
rosie@ming9:~/workspace$
rosie@ming9:~/workspace$ pip3 install virtualenv --break-system-packages-

  • 설치 후 crtrl shift p 해서 connect wsl 진행

vscode에 encore라는 가상환경 사용

🔵텍스트 암호화

import bcrypt
bcrypt.hashpw('123'.encode('utf-8'),bcrypt.gensalt())
http://172.19.196.11:8501
localhost:8501
  • 동일하게 작용

  • 리눅스, 도커 표준 확장자 yaml(야믈?야믈야믈…….)

credentials:
  usernames:
    play:
      name: rosie
      password: '$2b$12$AsEex2EsRr5DM/JJQJHuBOXMHCVYya/lO3jk6QieSQ2VOugoBYUHO'
import streamlit as st
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader

with open('config.yaml', 'r' , encoding='utf-8') as file:
    config = yaml.load(file, Loader=SafeLoader)

authenticator = stauth.Authenticate(
    config['credentials'])

authenticator.login() 

Day5

🟢DataBase Management System

DBMS 만드는 회사 ⇒ oracle

  • oracle이 소송을 많이 걸었다고?
    • 예전에 sunmicro system을 인수함, java 만든 회사

🔵상용

  • Oracle, DB-2, SQL-Server

🔵Opensource

  • mysql -그냥 많이 사용
  • mariadb - 카카오톡 초기 설계, mysql과 아주 비슷하다.
  • postgresql - 빅데이터 쪽에서 많이 사용

🔵SQL(Structed Query language)

  • 씨퀄이라고도 읽는 경우 존재

  • 포그라운드 vs 백그라운드

  • daemon → 백그라운드에서 실행되는 서비스

🔵환경 설정

sudo apt update
apt install mysql-server
sudo service mysql status

정상적이다.(active)

sudo mysql -uroot

보통 q누르면 나갈 수 있음

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

🔵HeidiSQL, DBeaver

  • db를 도와주는 프로그램. db가 아니다.

  • 비정형 데이터로는 mongodb, redis 사용
mysql> create user play@'%' identified by '123';
Query OK, 0 rows affected (0.03 sec)
  • ‘%’ : 모든 ip를 허용하겠다는 뜻
mysql> grant all privileges on *.* to play@'%';
Query OK, 0 rows affected (0.02 sec)
  • 명령어 다 기억이 안나냐….
mysql> quit
Bye
rosie@ming9:~$ pwd
/home/rosie
rosie@ming9:~$ cd /etc/mysql/mysql.conf.d
rosie@ming9:/etc/mysql/mysql.conf.d$
  • mysql 세팅환경이 있는 곳
rosie@ming9:/etc/mysql/mysql.conf.d$ ls -al
total 16
drwxr-xr-x 2 root root 4096 Jan  9 09:18 .
drwxr-xr-x 4 root root 4096 Jan  9 09:18 ..
-rw-r--r-- 1 root root  132 Nov 19 05:53 mysql.cnf
-rw-r--r-- 1 root root 2220 Nov 19 05:53 mysqld.cnf
rosie@ming9:/etc/mysql/mysql.conf.d$

-rw-r--r-- ⇒ 아직 읽을 수만 있음

127.0.0.1 ⇒ Loopback IP . localhost

bind-address ⇒ 0.0.0.0으로 변경 (모두를 받아들임 ^~^.)

vim에서 i 켜면 insert모드, esc 입력하고 :wq 치면 vim에서 나가게 됨.

q!도 가능

rosie@ming9:/etc/mysql/mysql.conf.d$ sudo service mysql status
  • 수정해도 active한지 확인

2 : eth0에 해당하는 ip를 db 생성 때 넣음

⇒ 이 과정으로 ubuntu 계정으로 연결.

rosie@ming9:/etc/mysql/mysql.conf.d$ sudo mysql -uplay -p123
mysql> create database encore;
Query OK, 1 row affected (0.02 sec)
CREATE TABLE encore.members (
    id VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    age INT,
    PRIMARY KEY (id)
);

🔵터미널 다시 켜기(끄지마라…….!!!!!)

wsl
sudo service mysql status
CREATE TABLE encore.members (
    id VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    age INT,
    PRIMARY KEY (id)
);
  • VARCHAR : 문자열인데 유동적
    • 고정된 CHAR이면 255여서 메모리 낭비 심하지만 속도가 빠름

  • DROP → 객체를 통으로 삭제
  • TRUNCATE → 값만 지우고 구조는 남겨둔다.
CREATE TABLE encore.members (
    id VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    age INT,
    PRIMARY KEY (id)
);

select * from members;

INSERT INTO members (id, name, age) VALUES ('user1', '홍길동', 30);
INSERT INTO members ( name, age ,id ) VALUES ( '대한민국', 30, 'user2');

  • id 가 PK이므로 중복 허하지 않음
  • PK는 null도 허락하지 않음

🔵ERD

  • 아키텍쳐
INSERT INTO members VALUES ('user6', '장동건', 31);
  • float, double : 둘 다 소수 관리하지만 담을 수 있는 용량이 다름
    • 보통 금융권에서는 안쓴다.
    • 숫자 건드렸을 때 오류 날 가능성 있음
    • 금액을 다 정수로 작성하고 자릿수를 표시한다.
  • 너무 큰 숫자를 담을 때는 자료형으로 BIGINT 사용 .

🟢SQL과 파이썬 연동

pip install sqlalchemy
pip install mysqlclient

import MySQLdb

conn=MySQLdb.connect(host='172.19.196.11',user='play',passwd='123',db='encore')

cursor= conn.cursor()
cursor.execute("show tables")

cursor.fetchall() #(('members',),)
cursor.execute("select * from members") 
#파이썬에서는 세미콜론 안써도 됨
cursor.fetchall()
#출력
(('user1', '홍길동', 30),
 ('user2', '대한민국', 30),
 ('user5', None, None),
 ('user6', '장동건', 31))

sql= """CREATE TABLE onnuri(
    name varchar(100),
    market_name varchar(100),
    address varchar(100),
    category varchar(100),
    paper_voucher char(1),
    digital_voucher char(1),
    year char(4)
)"""

cursor.execute(sql) #0
import csv

sql_insert="INSERT INTO onnuri VALUES (%s %s %s %s %s %s %s)"

file = "./소상공인시장진흥공단_전국 온누리상품권 가맹점 현황_20250731.csv"
with open(file, 'r', encoding='utf-8') as f:
    csv_reader = csv.reader(f)
    header = next(csv_reader)
    # print(f"헤더: {header}")
    for row_index, row_data in enumerate(csv_reader):
            if len(row_data) != 7:
                # print(row_data)
                cursor.execute(sql_insert,row_data)
  • 이렇게만 하면 아직 db에 업데이트 되지 않음

🟢SQL을 위한 서버 구축

🔵powertoys.

원래 인터넷 주소 : 120.2234..6.7.8…..

⇒ 외울 수 없으므로 DNS 사용.

  • domain name system

DNS보다 먼저 작동하는 것이 host.

  • 호스트 파일 편집기에 myserver를 추가하면 db에 추가된다.

  • SQL라이트 ⇒ 따로 설치가 필요없음.
    지금은 mysql쓰는 중

Database에도 주소를 넣을 수 있다.

SELECT * FROM onnuri LIMIT 5;
SELECT name , market_name FROM onnuri LIMIT 5;
  • 테이블 5줄만 출력
DESC onnuri;
  • 구조 출력

SELECT name , market_name FROM onnuri LIMIT 5;
SELECT * FROM onnuri o
WHERE address ='경기';
SELECT * FROM onnuri o
WHERE address ='경기'
-- AND market_name = '단국대 앞 골목형상점가'
AND category = '치킨'
AND name LIKE '%교촌%';

SELECT count(1) CNT
FROM 
(SELECT DISTINCT (category)
from onnuri o) A

  • conn.close()
  • 주피터에서 sql하고 우분투에서 동시에 뭘 시행하려고 하면 시행이 안된다.
(encore) rosie@ming9:~$ sudo vim /etc/hosts
  • 여기서 vim 열어서 localhost를 myserver로 바꿈
(encore) rosie@ming9:~$ ping 8.8.8.8
(encore) rosie@ming9:~$ ping myserver
  • 내가 바꾼 서버 응답

나중에 회사 서버를 받게 된다.

그러면 dns에 등록하면 됨!

profile
지루하게 선명하기보다는 흐릿해도 흥미롭게

0개의 댓글