# %% [markdown]
# DataClass
# 기존 클래스 사용보다 조금은 편하다
# %%
#데이터 클래스 생성하기(오류,개발속도 부분에서 유리)
from dataclasses import dataclass
@dataclass
class Student:
name : str
age : int
major : str
student1 = Student("샘", 30, "OpenAI")
# %%
student1
# %%
#일반 클래스와 비교
# class Student_1:
# def __repr__(self):
# %%
#심화
# from dataclasses import dataclass
@dataclass
class Student:
name : str
age : int
major : str
def __post_init__(self):
if not isinstance(self.age, int):
raise TypeError(f"나이는 숫자로 들어와야함")
student1 = Student("샘", "서른살", "OpenAI") #검사하는 기능?(+알파,포트폴리오에 추가하면 좋음)
# %%
student2 = Student("민수",20,"우아한형제들")
student3 = Student("태연",25,"카카오")
# %%
student2 == student3
# %%
class Student_1:
def __init__(self,name,age,major):
self.name = name
self.age = age
self.major = major
# %%
student3_1 = Student_1("태연",25,"카카오")
student4_1 = Student_1("태연",25,"카카오")
student3_1 == student4_1
# %%
student5_1 = Student("태연",25,"카카오")
student6_1 = Student("태연",25,"카카오")
# %%
student5_1 == student6_1
# %%
#
'''
@dataclass
'''
# %%
student6_1.major = 'Google'
# %%
student6_1
# %%
@dataclass(frozen=True)#값을 고정
class Employee:
name : str
position : str
employee1 = Employee("John","Manager")
# %%
employee1
# %%
employee1.name = 'Jane' #값을 고정했기 때문에 문제 발생
employee1
# %%
def func(msg="Hi"):
print(msg)
func("Hello")
func()
# %%
@dataclass
class AppConfig: #앱의 설정 값을 다뤄보자
debug : bool = False #기본값은 False
database_url : str ="some_url"
port : int = 1234
default_config = AppConfig()
# %%
default_config
# %%
custom_config = AppConfig(debug = True,database_url='naver',port=4321)
custom_config
# %% [markdown]
# 개인 프로젝트에서 데이터 클래스 적용해보기
# 데이터클래스는 비교할 때 인스턴스의 내용이 같으면 같은 걸로 취급
# %%
#가변 타입 필드 사용할 때 이렇게 하면 됨
from dataclasses import dataclass, field
@dataclass
class StudentCourses:
name : str
courses : list = field(default_factory=list)
# %% [markdown]
# Python의 dataclasses 모듈에서는
# field() 함수를 사용하여
# 클래스 필드의 기본값을 설정할 수 있는 방법을 제공하고 있습니다.
#
# 이 field() 함수는
# 데이터 클래스 필드를 세부적으로 커스터마이징 할 수 있게 도와줍니다.
#
# 이 중 default_factory 는 기본값을 생성하는 함수를 의미합니다.
#
# list = field(default_factory=list) 이 부분은
# courses 필드의 기본값을 빈 리스트로 설정하고 있습니다.
# 이것은 가변 객체를 기본값으로 사용하려는 경우에 주로 사용됩니다.
# 왜냐하면 가변 객체는 공유될 수 있기 때문에,
# 이런 식으로 함수를 사용해서 각 인스턴스마다 새로운 객체를 생성하는 것이 안전합니다.
#
# 즉, 여기서 list = field(default_factory=list)는
# 새로운 StudentCourses 인스턴스가 생성될 때마다,
# courses 필드에 새로운 빈 리스트를 할당하는 것을 보장합니다. 이렇게 하면
# StudentCourses 인스턴스 간에
# courses 리스트가 공유되지 않으므로
# 각 학생이 수강하는 과목 리스트를 독립적으로 관리할 수 있게 됩니다.
# %%
student10 = StudentCourses(name='멋사')
student10.courses.append("파이썬 문법")
student10.courses.append("웹서비스")
student10.courses.append("배포")
# %%
student10
# %% [markdown]
#
#
# %%
# class에서 초기값 지정할 때 조심해야 되는 점
class A:
def __init__(self,name,courses=[]):
self.name = name
self.courses = courses
# %%
a = A("a")
a
# %%
a.courses.append("파이썬")
# %%
b = A("b")
a.courses, b.courses
# %%
# class에서 초기값 지정할 때 조심해야 되는 점
class A:
def __init__(self,name,courses=None):
self.name = name
if courses is None:
self.courses = []
else:
self.courses = courses
# %%
a = A('a')
a.courses
# %%
b = A('b')
b.courses
# %%
a.courses.append("good")
a.courses
# %%
b.courses
# %% [markdown]
# **TDD란?**
# Test Driven Development 테스트 주도 개발
# 소프트웨어 개발 방법론 중 하나로,
# 소프트웨어의 기능을 구현하기 전에 테스트를 작성하고,
# 그 테스트를 통과시키는 코드를 작성한 후에야 기능을 구현하는 방식
#
# TDD 개발 과정
# 실패하는 테스트 작성 > 테스트 통과하게 만드는 코드 작성 > 코드 리팩토링
# %% [markdown]
# assert
# assert 조건, "에러 메시지"
# %%
def get_age(age):
assert age >= 0, "값이 잘못 입력됨"
print("당신의 나이는 {}세".format(age))
# %%
get_age(15)
# %%
get_age(-15)
# %% [markdown]
# Mock 객체를 사용한 테스트
# setUP 및 tearDown 사용
# 조건부 테스트 실행
# %% [markdown]
# Pythonic 코드 개발
# 파이썬의 철학과 관용구를 따라
# 효율적이고 가독성 높은 코드를 작성하는 방식
# %%
import this
# %% [markdown]
# 명확함이 애매함보다 낫다
# %%
# 명확한 변수명 사용
# dt = 10
days_to_complete = 10
# %%
# 함수 이름으로 기능 명시
def process(data):
pass
def remove_duplicated_records(data):
pass
# %%
#조건문 간소화
status = True
if status == True:
pass
if status:
pass
# %% [markdown]
# 단순함이 복잡함보다 낫다
# %%
#리스트 컴프리헨션 사용
result = []
for i in range(10):
if i % 2 == 0:
result.append(i**2)
result = [i**2 for i in range(10) if i%2 == 0]
# %%
# 함수 분리
def process_data(data):
# 데이터 전처리
# 데이터 처리
# 결과 반환
pass
#데이터 전처리
def preprocess_data(data):
pass
#데이터 처리
def process_data(data):
pass
# %%
# 내장 함수 사용
nums = [ i for i in range(100)]
# %%
total = 0
for num in nums:
total += num
average = total /len(nums)
average
# %%
average = sum(nums) / len(nums)
average
# %%
# 조건문 간소화
status = None
if status == "success" or status == "complete" or status == "finished":
pass
if status in ["success","complete","finished"]:
pass
# %% [markdown]
# 가독성이 중요하다
# %%
#적절한 줄바꿈과 들여쓰기
result = some_function(param1, param2, param3, param4, param5)
result = some_function(param1,
param2,
param3,
param4,
param5)
# %%
# 의미 있는 주석 추가
# 현재 시간에서 일주일을 더한다.
next_week = current_time + week_time
# %%
# 함수와 변수의 적절한 분리
print("Result : ", process_data(data))
result = process_data(data)
print("Result : ", result)
# %%
# 적절한 변수명 사용
# %%
# 중첩 제한하기
items = [(i,i*3) for i in range(10)]
# %%
for item in items:
if item:
for value in item:
pass
# %%
# 오류는 결코 조용히 지나가지 않아야 한다.
def process_data(data):
return int(data)
# %%
data = "일이삼"
try:
process_data(data)
except ValueError as e:
print(f"ValueError:{e}")
except Exception as e:
print(f"Unexpected error : {e}")
# raise
# %% [markdown]
# 명시적인 것이 암시적인 것보다 낫다
# %%
# from math import *
# print(sqrt(4))
# %%
from math import sqrt
print(sqrt(4))
# %%
def make_request(url, timeout=5):
pass
make_request("http://example.com",10)
make_request(url = "http://example.com",timeout = 10)
# %%
def get_position():
return 100,200
x,y = get_position()
x,y
# %%
position = get_position()
x = position[0]
y = position[1]
x,y
x,y = get_position()
x,y
# %% [markdown]
# 실용성은 순수성보다 중요
# %%
result = list(map(lambda x:x**2, filter(lambda x:x%2==0,range(10))))
result
# %%
result = [x**2 for x in range(10) if x%2 == 0]
# %%
#성능을 위한 실용적 최적화
def is_prime_1(n):
return n>1 and all(n%i for i in range(2,n))
def is_prime_2(n):
if n <= 1:
return False
for i in range(2, int(n**0.5)):
if n % i == 0:
return False
return True
# %%
%%time
is_prime_1(10007)
# %%
%%time
is_prime_2(10007)
# %%
# 유지 보수를 위한 실용적 구조
class Animal: pass
class Dog(Animal): pass
def make_sound(animal_type):
sounds = {"dong":"bark","cat":"meow"}
return sounds.get(animal_type, 'unknown')
# %% [markdown]
# 일관성은 중요하다
# %%
#네이밍 컨벤션 일관성
class MyClass:
pass #class는 camel case
def my_function():
pass #변수는 snake case
# %%
import requests #코랩에서 가능
url = "https://www.dhlottery.co.kr/common.do?method=getLottoNumber&drwNo=100"
# %%
response = requests.get(url)
# %%
output = response.json()
# %%
output
# %% [markdown]
# 특정 회차 정보를 가져오려면 어떻게 해야 되나?->함수
# 그 회차의 당첨번호,보너스 번호는 몇번인가?->함수
# 파이써닉한 코드에 대해 고민해보기
import requests
# 특정 회차 정보를 가져오려면 어떻게 해야하나? => 함수
# 그 회차의 당첨번호, 보너스 번호는 몇 번인가? => 함수
# 파이써닉한 코드에 대해 고민해보기
def get_lotto_data():
# 입력값에 대한 예외처리를 진행하고, 올바른 값을 입력할 때까지 while문으로 반복
while True:
try:
# 입력한 값이 숫자가 아닐 경우 -> ValueError 발생
number = int(input("찾고자 하는 회차 번호를 입력하세요 : "))
url = "https://www.dhlottery.co.kr/common.do?method=getLottoNumber&drwNo={}".format(number)
response = requests.get(url)
output = response.json()
# 입력한 숫자가 0회차, -100회차, 10000회차 등 값이 존재하지 않는 회차일때
# -> 강제로 ValueError 발생
if output['returnValue'] == 'fail':
raise ValueError
except ValueError:
print("입력하신 값은 숫자가 아니거나 해당하는 회차의 정보가 존재하지 않습니다. 다시 입력해주세요.")
else:
break
print("====={}회차 복권 정보=====".format(number))
return output
# 당첨번호를 출력하는 함수
def get_drwt(lotto_data):
# print 함수로 당첨번호를 출력하기
for i in range(1, 7):
print("{}번째 당첨 번호 : {}".format(i, lotto_data["drwtNo{}".format(i)]))
# 리스트 컴프리헨션으로 리스트 값을 반환한다면 아래 주석처럼 쓰기
# answer = [lotto_data["drwtNo{}".format(i)] for i in range(1, 7)]
# 보너스 번호를 출력하는 함수
def get_bnusNo(lotto_data):
print("보너스 당첨 번호 :", lotto_data["bnusNo"])
# 위에서 만든 함수를 한꺼번에 묶어서 출력해주는 함수
def get_number(lotto_data):
get_drwt(lotto_data)
get_bnusNo(lotto_data)
if __name__ == "__main__":
lotto_data = get_lotto_data()
get_number(lotto_data)
if name == "main":
이 부분은 파이썬 코드를 실행할 때
해당 스크립트 파일이 직접 실행되는지,
아니면 다른 파일에 의해 import되어 사용되는지를 판단하는 구문입니다.
파이썬 파일이 실행될 때,
파이썬 인터프리터는
먼저 name이라는 특별한 내장 변수를 만들어둡니다.
이 name 변수에는
해당 파이썬 파일의 이름이 문자열로 저장됩니다.
그런데 여기서 중요한 점은,
파이썬 파일이 '직접 실행'되는 경우에는
name 변수의 값이 'main'이 됩니다.
즉, if name == "main": 구문은
"이 파이썬 파일이 직접 실행되는 경우에만 아래의 코드를 실행하라"는 의미를 가지게 됩니다.
반면에
해당 파이썬 파일이 다른 파이썬 파일에 import되어 사용되는 경우, name 변수의 값은 원래의 파이썬 파일 이름이 됩니다.
이 경우 if name == "main":
구문 아래의 코드는 실행되지 않습니다.
따라서 if name == "main": 구문은
특정 파이썬 파일이 모듈로써 import되어 사용될 때와
직접 실행될 때를 구분하기 위해 사용됩니다.
이를 통해 해당 파일이 직접 실행될 때만 실행되어야 하는 테스트 코드나 그 외의 코드를 작성할 수 있습니다.