현대 오토에버 클라우드 스쿨
파이썬 프로그래밍
Gom3rye
2025. 5. 20. 09:36
1. Data Type
- tuple
- list와 유사한데 읽기 전용 → 함수의 리턴에 많이 이용된다. ex. 데이터 분석
- 생성 방법: 하나의 데이터를 가지고 생성할 때는 데이터, or tuple(다른 순차형 데이터)
- list와 tuple은 데이터를 나누어서 저장하는 것이 가능: unpacking
- 데이터를 나눌 때 *을 사용하면 *이 없는 곳에 나누어주고 나머지를 가지고 list로 만들어서 대입한다.
- tu = (10, 20, 30) a, b, c = tu print(c) # 30 a, b, _ = tu # 대입하지 않을 데이터는 _로 매칭 print(b) # 20 a, *b = tu # *은 나머지 전부를 list로 만들어준다. print(b) # [20, 30]
- tuple을 가지고 if else에서 조건에 따라 다른 값을 대입하는 것을 수행할 수 있다. (2개의 데이터 나열)[조건]: 조건이 True면 뒤의 데이터가, False면 앞의 데이터가 대입된다.
- score = 59 pandan = ("합격", "불합격")[score < 60] # (거짓일 때, 참일 때) 조건 입력 print(pandan) # 불합격
- collections 모듈의 namedtuple 함수를 이용하면 필드명과 클래스 이름을 추가한 서브 클래스를 생성해준다.
- 이 자료형으로 만들어진 튜플은 이름을 이용해서 접근이 가능하다.
- python에서 DTO(Data Transfer Object)나 VO(Variable Object)를 만들 때 일반 클래스로 만들기도 하고 dict나 namedtuple을 이용하기도 한다.
- 사용자 요청 → Controller → Service → DAO(Data Access) → Persistence Store (3계층) (이때 계층 사이를 이동하는 걸 DTO라고 하고, 자기 계층에서만 쓰이는 걸 VO(domain)이라고 한다. (DTO : serialization(직렬화) O, VO : 직렬화 x)
- class DTO: def __init__(self, num=0, name="noname", age=1): self.num = num self.name = name self.age = age dto = DTO(1, "명준", 33) print(dto.name) # 명준 from collections import namedtuple # 첫번째 매개변수: 이 클래스의 설명, 두번째 매개변수: 문자열로 필드명을 공백과 함께 나열 VO = namedtuple("VO", "num name age") # swift vo = VO(2, "명지", 22) print(vo.name) # 명지
- set
- 데이터를 순서에 상관없이 중복 제거한 형태로 저장하는 자료구조
- 내부 데이터 변경할 수 있는 set과 변경할 수 없는 frozenset을 제공
- 생성 방법
- 빈 객체: set( )
- 다른 자료형을 가지고 생성: set(데이터)
- 기본 데이터를 가지고 생성: {데이터 나열}
- 검색 속도가 빨라짐 But, 메모리를 좀 쓴다 ex. 데이터 하나 더 들어오면 리해시해야 함 -> 데이터의 삽입과 삭제가 빈번하면 이 자료구조는 굉장히 느려진다.)
hashset = {"Hello World"} print(hashset) # {'Hello World'} hashset = set("Hello World") print(hashset) # {'o', 'H', ' ', 'd', 'r', 'e', 'l', 'W'} 순서 상관 없이 나옴 # 스마트폰 앱 : hash와 set사용함 -> 순서 없이 중복 없음 => 똑같은 앱 2번 안 깔리고 모든 앱 접근 속도 동일 # 있다 없다도 빠르게 찾을 수 있음
- dict
- key와 value를 쌍으로 저장하는 자료형
- 생성 방법
- 비어있는 상태: { } or dict( )
- 데이터를 가지고 생성: {키: 값, 키: 값 …}
- 키를 이용해서 가져오기
- dict[키] or get 메서드 이용
- dict[키] 에서 키가 존재 x → 에러
- get(키, 키가 없을 때 사용할 값)
- 데이터 삽입이나 수정
- dict[키] = 값 (이때 없으면 생성되고 있으면 수정된다. ⇒ key가 set으로 만들어지기 때문에 키는 중복 생성 x)
dict1 = {"num": 3, "name": "명준", "age": 50} dict1["height"] = 180 print(dict1) # {'num': 3, 'name': '명준', 'age': 50, 'height': 180} print(dict1["name"]) # 명준 # print(dict1["weight"]) # KeyError: 'weight' print(dict1.get("weight", "없는 키")) # 에러 안 나고 '없는 키' 출력
# __iter__가 있기 때문에 순회하면 키의 값이 순차적으로 리턴된다. for temp in dict1: print(temp) # 결과 num name age height for temp in dict1: print(temp, dict1[temp]) # 결과 num 3 name 명준 age 50 height 180
- MVC (Model View Controller)
- Model: 실제 비즈니스 로직
- View: 화면에 보여지는 부분
- Controller: 둘 사이를 연결해주는 부분 이 부분을 나누어서 구현하고 하나의 변화가 다른 하나에 영향을 거의 미치지 않도록 하는 프로그래밍 방식
kia = ["김도영", "이의리", "전상현"] hanwha = ["안치홍", "문동주", "김서현", "고삼례"] lg = ["김명준"] kbo = [kia, hanwha, lg] # 팀이 하나 추가되면 출력부분 바꿔야 한다. for team in kbo: if team == kbo[0]: print("기아: ", end='') elif team == kbo[1]: print("한화: ", end='') else: print("LG: ", end='') for player in team: print(player, end=' ') print("") # 키를 하나 더 써서 데이터에 이름을 붙여놓는 것 -> 출력할 때 더 편해진다. kbo = [{"team": "기아", "data": kia}, {"team": "한화", "data": hanwha}, {"team": "LG", "data": lg}] for teams in kbo: print(f"{teams["team"]}: ", end='') for player in teams["data"]: print(player, end=' ') print() # 결과 기아: 김도영 이의리 전상현 한화: 안치홍 문동주 김서현 고삼례 LG: 김명준
- # 자바에서 선호하는 방식 class DTO: def __init__(self, num=0, name="noname", age=1): self.num = num self.irum = name self.age = age dto = DTO(1, "명준", 33) print(dto.num) print(dto.irum) # 명준 print(dto.age) # 파이썬에서 선호하는 방식 vo = {"num":2, "name":"삼례", "age":33} for key in vo: # key이름을 출력한 적 없음 -> 전체 데이터 출력할 때는 영향 안 받음 print(key, vo[key])
- 기존의 list나 set 그리고 tuple을 가지고 생성
- dict(zip(키의 모임, 값의 모임))
- keys, values, items 메서드를 이용해서 키의 집합, 값의 집합, 키와 값의 튜플로 리턴해준다.
- del dict[키]를 이용해서 데이터 삭제 가능
- popitem( )을 이용해서 마지막 하나의 데이터를 반환하고 제거
- clear( )을 이용해서 모든 데이터 삭제
- enumerate
- 인덱스와 데이터를 하나의 튜플로 리턴해주는 함수
- list, set, tuple의 경우 인덱스와 데이터를 리턴, dict는 인덱스와 키를 리턴
- comprehension
- 데이터 순회문을 가지고 list나 tuple 그리고 set등을 만드는 것
li1 = ["삼례", "명준", "명지"]
li2 = [name for name in li1]
print(li2) # li1 == li2
li3 = [["!", "?", "@"], ["%", "$", "&"]] # 2차원 list
# 2차원 list를 가지고 1차원 list 생성
li4 = [j+"k" for i in li3 for j in i] # map보다 속도 빠름
print(li4) # ['!k', '?k', '@k', '%k', '$k', '&k']
li1 = ["삼례둥이", "명준빵", "명지"]
li2 = [name for name in li1 if len(name) >= 3]
print(li2) # ['삼례둥이', '명준빵']
- collections 모듈: 다양한 자료구조를 제공하는 모듈 → 이랑 iter 툴 쓸 수 있는지 물어봐야 한다.(코테)
- deque: 뎈 자료구조를 위한 클래스
- Counter: 데이터 개수를 파악하거나 집계를 편리하게 해주는 클래스 (word count 할 때 자주 사용, 각 단어가 몇 번씩 나왔는지)
from collections import Counter portfolio = [('GOOG', 100, 490.1), ('IBM', 50, 91.1), ('GOOG', 76, 490.1), ('APPLE', 102, 500.1)] total = Counter() for name, shares, price in portfolio: # 튜플이나 리스트는 분해 가능 total[name] += price print(dict(total)) # {'GOOG': 980.2, 'IBM': 91.1} print(total.most_common(2)) # 상위 2개 출력 [('GOOG', 980.2), ('APPLE', 500.1)]
- data = ["참외", "수박", "수박", "토마토", "수박", "참외"] counting = {} # dict를 하나 만들어놓고 for fruit in data: cnt = counting.get(fruit, 0) # get(): 지금까지 몇 번 나왔는지 확인, 없으면 0 주기 cnt += 1 counting[fruit] = cnt # 위 3코드 = counting[fruit] = counting.get(fruit, 0) + 1 print(counting) # {'참외': 2, '수박': 3, '토마토': 1} from collections import Counter counter = Counter(data) print(counter["참외"]) # 2 print(dict(counter)) # {'참외': 2, '수박': 3, '토마토': 1}
- defaultdict: 하나의 key에 여러 개의 데이터를 저장할 수 있는 dict
- 데이터를 추가로 저장할 때 append 사용
- # 하나의 키에 여러 개의 데이터를 list로 보관 holdings = defaultdict(list) for name, shares, price in portfolio: holdings[name].append((shares, price)) for x in holdings: print(x, ":", holdings[x]) # 결과 GOOG : [(100, 490.1), (76, 490.1)] IBM : [(50, 91.1)] APPLE : [(102, 500.1)]
- OrderedDict: dict는 key를 set으로 만들기 때문에 순서를 알 수 x, But, OrderedDict는 입력한 순서대로 key에 추가하기 때문에 순서를 기억할 수 있다.
- from collections import OrderedDict keys = ["one", "two", "three"] values = (1, 2, 3) dic = OrderedDict(zip(keys, values)) for key in dic: print(key,":", dic[key]) # 결과 one : 1 two : 2 three : 3
- itertools 모듈
2. 예외 처리
- 오류 종류
- 컴파일 오류: 문법적 오류
- 예외(Exception): 실행 도중 외부 요인이나 잘못된 입력으로 발생하는 오류
- Java에서는 file handling, network server, database server 만지는 일은 예외 처리 강제한다.
- 논리적 오류: 알고리즘 잘못으로 잘못된 결과가 만들어지는 경우 → 이를 찾기 위해 boundary value analysis 같이 테스트를 해야 한다.
- assert(단언): 오류나 예외가 아니지만 개발자가 고의적으로 특정 조건을 만족하지 않으면 고의적으로 중단시키는 것
- 예외 처리를 하는 이유 → 크롤링에 많이 쓰임
- 프로그램이 정상적으로 종료되도록 하기 위해서
- 예외가 발생하더라도 프로그램을 계속 수행하기 위해서
- 정상적인 값으로 수정해서 수행하기 위해서
- 예외 처리 방법 → 로깅 중요!
- try: 예외가 발생할 것 같은 코드 except: 예외가 발생했을 때 처리할 코드
- 특정한 형태의 예외만 처리하고자 할 때 → https://docs.python.org/3/library/exceptions.html try: 예외가 발생할 것 같은 코드 except 예외 클래스 이름: 예외가 발생했을 때 처리할 코드
- 예외 클래스 이름을 추가해서 작성→ except를 여러 개 연속해서 사용해도 된다.
- except는 if처럼 동작하기 때문에 클래스이름이 없는 경우는 맨 뒤에 놓아야 함 → 앞에서 전체 에러를 다 잡아버리면 어떤 에런지 알 수가 없으니까
- else 절에 예외가 발생하지 않을 때 수행할 코드 작성
- finally는 예외 발생 여부에 상관없이 수행할 문장 작성
- 강제로 예외 발생
- raise 예외처리클래스이름(”메시지”)
- 예외 객체를 사용할 때 except 예외클래스이름 as 변수명
def ten_div(x: int) -> float:
if x == 10:
raise Exception("강제로 예외 발생")
return 10/x
print(ten_div(5))
try:
print(ten_div(10))
except TypeError:
print("자료형이 잘못된 경우 처리")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
except Exception as e:
print(e) # 강제로 예외 발생
print("앞에서 처리하지 못한 예외를 처리")
else: # 예외가 발생하지 않을때
print("예외가 발생하지 않았을 때 처리")
finally:
print("무조건 수행되는 처리")
print("정상 종료")
# 결과
2.0
강제로 예외 발생
앞에서 처리하지 못한 예외를 처리
무조건 수행되는 처리
정상 종료
- assertion 만들기
- assert 조건식
- assert 조건식, 에러메시지 ⇒ 조건식이 False가 되면 AssertionError가 발생
x = 5
assert x >= 10, "x는 10보다 크거나 같아야 합니다."
# AssertionError: x는 10보다 크거나 같아야 합니다.
3. 파이썬 내장 모듈
- os.path : 파일 경로를 생성 및 수정하고 파일 정보를 다룰 수 있도록 해준다.
import os.path
print(dir(os.path))
print(os.path.abspath("0502")) # 절대 경로 나온다. C:\\Users\\kimmy\\Documents\\python\\0502\\0502
- 파일에서 중요한 정보는 수정 시간이나 생성 시간 등
- getatime(마지막으로 접근한 시간), getmtime(마지막으로 수정된 시간), getctime(생성 시간 (Windows))
- import os.path, time print(time.gmtime(os.path.getatime("exceptionhandling.py"))) print(os.path.getmtime("exceptionhandling.py")) print(os.path.getctime("exceptionhandling.py"))
- glob : 경로 안의 파일이나 디렉토리를 순회할 수 있도록 해주는 모듈 → AI할 때 많이 쓰임
import glob
print(glob.glob("./*.*")) # ['.\\\\datatype.py', '.\\\\exceptionhandling.py', '.\\\\pyvenv.cfg']
- os 모듈 : 디렉토리를 생성하거나 목록을 확인하거나 할 때 사용하는 모듈
import os
os.system("calc") # 계산기 실행
os.system("notepad") # 메모장 실행
- sys 모듈 : 파이썬 인터프리터 관련 정보와 기능을 제공한다.
- argv: 파이썬 파일이 실행될 때 넘어온 매개변수 정보
- exec_info: 예외가 발생했을 때 넘어온 매개변수 정보
- prefix, exec_prefix: 파이썬이 설치된 경로
- exit(정수): 파이썬 프로그램 종료, 정수는 0이면 정상 종료고 그 이외의 숫자는 에러코드
- executable: 파이썬 인터프리터 실행 파일 경로
- getrefcount(데이터): 데이터의 참조 횟수를 리턴하는데 1증가해서 나옴 → 공부할 때 사용 ㅊㅊ
- path: 모듈을 찾는 순서
- getdefaultencoding: 현재 인코딩 방식
- modules: 현재 로딩된 모듈의 목록을 리턴
import sys
print(f"현재 인코딩 방식: {sys.getdefaultencoding()}") # utf-8
- 복사
- 파이썬은 기본적으로 변수를 다른 변수에 대입하면 참조를 복사
- 변수의 데이터를 수정하면 원본 데이터도 수정될 수 o
- 스칼라 데이터는 참조가 복사되지만 값이 복사되는 형태로 동작한다.
- copy 모듈에서 copy 메서드와 deepcopy 메서드를 제공하는데 copy는 얕은 복사를 수행해주고 deepcopy는 깊은 복사를 수행한다.
- 1차원 데이터 묶음에서는 copy와 deepcopy가 차이가 없지만 2차원 이상 데이터 묶음에서 copy는 참조를 복사하는 형태로 동작하고 deepcopy는 재귀적으로 복제를 수행하므로 2차원 이상에서도 값을 복제하는 효과가 나타난다.
scala = 10
li = [100, 200, 300]
# 실제로는 참조가 복사되지만 작업을 수행하면 값이 복사되는 형태로 동작 -> id 찍어보면 앎
scalacopy = scala
print(id(scala))
print(id(scalacopy)) # 둘이 똑같음
licopy = li
print(id(li))
print(id(licopy)) # 둘이 똑같음
# 스칼라 데이터는 복제본에서 작업을 수행해도 원본에 영향이 없음
scalacopy = 20
print(scala) # 10 -> 10 변화 x
# 벡터 데이터는 복제본 전체를 교체하는 것은 원본에 아무런 영향을 주지 않지만
# 세부 데이터를 수정하는 것은 원본에 영향을 준다.
licopy[0] = 10000
print(li) # [100, 200, 300] -> [10000, 200, 300] 변화 o
# 일차원 벡터 데이터를 복제를 해주고자 하는 경우는 copy 모듈의 copy 메서드를 사용하면 된다.
import copy
weakcopy = copy.copy(li)
weakcopy[0] = 1
print(li) # [10000, 200, 300] -> [10000, 200, 300], li에 영향 x
print(weakcopy) # [1, 200, 300]
li = [[1,2,3], [4,5,6]]
weakcopy = copy.copy(li)
weakcopy[0][0] = 1000
print(li) # [[1000, 2, 3], [4, 5, 6]] -> 바뀌어 버림 => 2차원 이상은 copy하면 안됨
# weakcopy = copy.deepcopy(li) # 하면 재귀적으로 값 복사하기 때문에 li 안 바뀜 [[1, 2, 3], [4, 5, 6]]
728x90
반응형