from datetime import datetime
datetime.now()
datetime.now().date()
datetime.now().year
datetime.now().month
datetime.now().day
datetime.now().hour
datetime.now().minute
d = datetime.now()
print(f'{d.year}/{d.month}/{d.day}')
# 가볍게 사용하긴 좋지만, 날짜나 시간은 타입이 있다.
d.strftime('올해 연도는 %Y!!')
d.strftime('%y/%m/%d')
d.strftime('%Y/%m/%d')
#가장 많이 사용하는 date format, 하나만 기억해야 한다면 이것을 기억!
datetime.now().strftime()을 통해 현재 날짜와 시간을 출력할 수 있다.
class User:
# 모든 곳에서 공유될 변수들
user_count = 0
gender = ('남', '여')
def __init__(self, name, joindate, gender, age, email, password):
self.joindate = joindate
self.accessdate = joindate
self.name = name
self.gender = gender
self.age = age
self.email = email
self.password = password # 실무에서 이렇게 저장 절대 안함
# (Django에서도 이렇게 저장해서 오류나는 경우 많음)
# self.password = 39743FFC/FB179CEB/A590B68F/FF1A7C65/A9DB72B3/A5AD63E/E01A66C6/896A07311 + salt
# Django에서도 sha256을 사용합니다. 은행권에서는 이 알고리즘이 깨졌다고 보고 있음.
# sha512를 사용하려 노력을 함.
# MD5라는 알고리즘을 암호화 알고리즘으로 많이 사용했었는데 이게 깨졌다. (레인보우 어택)
user1 = User('이호준', '2024/01/15', '남', 15, 'hojun@gmail.com', '1q2w3e4r!')
# 서비스가 몇년 정도 갈지 생각해서 연도의 자리수(24 or 2024)를 정하자. 보통 4자리를 넣는게 좋다.
user1.name
user1.accessdate
User.user_count = 1
user2 = User('홍길동', '2024/01/15', '남', 30, '햐ㅣ애ㅜㅎ@gmail.com', '1q2w3e4r!')
user2.name
User.user_count = 2
user1.user_count
# 무엇을 알 수 있는가? 실제로 class와 인스턴스의 메모리 영역은 교집합 상태
# 한 곳에서 수정이 되면 모두 수정이 된다!
# 그래서 처음에 클래스를 설계할 때 모든 인스턴스에 있을 변수(크래스 변수)와
# 인스턴스에만 있는 변수(인스턴스 변수)를 나누는 것이 매우 중요하다.
password는 해시 값을 넣어준다고 한다. 그냥 넣으면 모두가 다 볼 수 있으니까.. 문제가 될 것이다. 여기서 self가 붙은 부분은 인스턴스 변수라고 생각하면 된다.
def f():
return
f() # 반환 값이 None이면 출력을 안함
import hashlib
import re
from datetime import datetime
class User:
user_count = 0
gender = ('남', '여')
def __init__(self, name, joindate, gender, age, email, password):
self.joindate = joindate
self.accessdate = joindate
self.name = name
self.gender = gender
self.age = age
self.email = email
self.password = self._hash_password(password)
def _hash_password(self, password):
return hashlib.sha256(password.encode()).hexdigest()
def change_password(self, password): # django의 user.set_password('비밀번호')와 비슷한 역할
if len(password) < 8: # validate 또는 유효성 검증이라고 합니다.
print('너무 짧습니다!')
return
self.password = self._hash_password(password)
self.accessdate = datetime.now().strftime('%Y/%m/%d')
def update_email(self, email):
if self._validate_email(email):
self.email = email
self.accessdate = datetime.now().strftime('%Y/%m/%d')
else:
print("유효하지 않은 이메일 주소입니다.")
def _validate_email(self, email):
pattern = r"[\w.-]+@[\w.-]+\.\w+"
return re.match(pattern, email) is not None
def display_profile(self):
print(f'name: {self.name}')
print(f'joindate: {self.joindate}')
print(f'accessdate: {self.accessdate}')
print(f'email: {self.email}')
def __str__(self):
return self.name
def __repr__(self):
return self.name
user1 = User('이호준', '2024/01/15', '남', 15, 'hojun@gmail.com', '1q2w3e4r!')
user2 = User('홍길동', '2024/01/15', '남', 30, 'gildong@gmail.com', '1q2w3e4r!!')
print(user1)
user1.display_profile()
user1.password
django 코드는 위와 같이 짠다고 하는데 아직은 배우지 않았으니 이렇게 하는 거구나.. 하고 알아만 두자.
# 온라인 쇼핑몰에서 장바구니에 넣기
class Cart:
def __init__(self):
self.items = []
def add_item(self, item, count):
self.items.append({
'물품': item,
'갯수': count,
})
def total_price(self):
total_sum = 0
for i in self.items:
total_sum += i['물품'].price * i['갯수']
return format(total_sum, ',')
class Product:
def __init__(self, product_name, price):
self.product_name = product_name
self.price = price
def __str__(self):
return self.product_name
def __repr__(self):
return self.product_name
로지텍키보드 = Product('로지텍키보드', 50000)
LG모니터 = Product('LG모니터', 300000)
그래픽카드4090 = Product('GTX4090', 2000000)
hojun_cart = Cart()
hojun_cart.add_item(로지텍키보드, 10)
hojun_cart.add_item(LG모니터, 10)
hojun_cart.add_item(그래픽카드4090, 2)
hojun_cart.items
hojun_cart.total_price()
우선, 장바구니 클래스와 상품 클래스 2개를 선언을 하였다. 장바구니 클래스에는 품목들의 리스트가 인스턴스 변수로 선언이 되어있고, add_item 메서드에서 items 리스트에 품목명과 갯수를 추가해준다. total_price 메서드에서는 총 금액을 계산해주는 기능을 갖고 있다.
이제 상품 클래스를 보도록 하자.
상품 이름과 가격을 인스턴스 변수로 선언을 하였다. 이후 print()문의 출력으로는 매직매서드를 통해 상품이름이 출력되도록 하였다.
이후, 로지텍키보드, LG모니터, 그래픽카드4090 상품 객체 3개를 선언을 해주었다.
hojun_cart라는 장바구니 객체도 선언을 해줬으며, add_item 메서드를 활용하여 물건을 추가해 주었다.
마지막으로 최종 금액을 반환하도록 했다.
# 클래스 메서드는 클래스 변수를 변경하고 싶을 때 사용
# 주의해야 할 점이 첫번째 인자로 오는 cls는 관습으로 고정
# self가 a로 바꾸면 작동은 하지만 관습적으로 안되는 것처럼 cls도 바꾸면 안됨
# cls는 class를 나타낸다.
class MyClass:
count = 0
@classmethod
def increment(cls):
cls.count += 1
MyClass.increment()
print(MyClass.count) # 출력: 1
# 정적 메서드
# 언제 쓰는가? 정적 메서드는 self로 내부 변수에 접근이 안되서
# 책 클래스 만든 것 중 할인율 같이 관련은 있는데 밖으로 함수를 빼기 부담스러운 것들을 이렇게 사용한다.
class MyClass:
@staticmethod
def my_method(x, y):
return x + y
print(MyClass.my_method(5, 3)) # 출력: 8
예시를 살펴보겠다.
class Book:
def __init__(self, name, price):
self.name = name
self.price = price
@staticmethod
def 할인율(원가, 할인):
return 원가 * (1-(할인/100))
Book.할인율(9000, 10) # 밖으로 뺄 수 있는 함수이고, 굳이 안에 들어갈 필요가 없다
# 그런데 할인율은 Book과 연관이 있다.
# 이렇게 코딩을 하면 유지보수 하기 좋다.
위와 같은 결과를 출력하지만 권장하지는 않는 코드를 소개하겠다.
# 비권장하는 케이스
# 위와 같은 코드
class Book:
def __init__(self, name, price):
self.name = name
self.price = price
def 할인율(원가, 할인):
return 원가 * (1-(할인/100))
boo1 = Book('python 100제', 9000)
할인율(boo1.price, 10)
위의 코드는 할인율 함수를 클래스 밖으로 뺐다는 특징이 있는데 이러면 나중에 잘못되었을 때 유지보수가 어렵다는 단점이 있다.
# 중요도 높지 않음
# 별표 0.5개
# 속성 접근자 (Property)
class Person:
def __init__(self, first_name, last_name):
self._first_name = first_name
self._last_name = last_name
@property # 이 부분 때문에 함수를 속성처럼 사용 가능
def full_name(self):
return f'{self._first_name}{self._last_name}'
licat = Person('li', 'cat')
print(licat._first_name)
print(licat._last_name)
print(licat.full_name)
# print(licat.full_name()) # 이렇게 안써도 된다는 것!
# 덕타이핑
# 별표 0.3개
# https://world.weniv.co.kr/
# licat.move()
# move() => 직관적이고 누가 움직이는지는 알고 싶지 않고 주인공을 앞으로 한 칸 움직이고 싶다.
class Duck:
def quack(self):
print('꽥꽥!')
class Person:
def quack(self):
print("안녕하세요!")
def quack(obj):
obj.quack()
duck = Duck()
person = Person()
quack(duck) # 출력: 꽥꽥! duck.quack() 대신 quack(duck)를 사용하겠다.
quack(person) # 출력: 안녕하세요! person.quack() 대신 quack(person)를 사용하겠다.
# 오버라이딩
# 자식이 부모의 메서드를 덮어씌우는 것
class Animal:
def sound(self):
print("기본 동물 울음 소리, 악!")
class Dog(Animal):
def sound(self):
print("왈왈!")
class Cat(Animal):
def sound(self):
print("냐옹!")
# super()를 사용해서 부모의 메서드를 사용 할 수 있다.
class Bird(Animal):
def sound(self):
print("짹짹!")
class Person:
def __init__(self, name):
self.name = name
class Student(Person):
def __init__(self, name, student_id):
super().__init__(name) # 부모 클래스의 __init__ 메서드 호출
# self.name = name 위 코드와 이코드는 동일하다.
self.student_id = student_id
s = Student("Alice", "S12345")
print(s.name) # 출력: Alice
print(s.student_id) # 출력: S12345
상속 관계에 있는 부모 클래스의 메서드를 호출하는데에 사용한다.
# 추상 클래스
# 중요도는 높지만 빈도가 낮아 별 0.5개
# 추상 클래스: 반드시 구현되어야 하는 메서드를 명시하면
# 그것을 상속한 클래스에서는 반드시 그 메서드를 구현해야 한다.
# 언제 사용할까? 예를 들어 빠트리면 안되는 메서드가 있는 경우
# 게시판 만드는데 게시물 업데이트 날짜, 생성 날짜를 추상 클래스로 구현할 수 있다.
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def do_something(self): # 필수로 구현해야 하는 메서드, 안하면 에러남
pass
class Person(AbstractClassExample):
def __init__(self, name):
self.name = name
def print_name(self):
print(f'제 이름은 {self.name}입니다.')
def do_something(self):
print('hello')
hojun = Person('hojun')
hojun.print_name()
# 비공개 속성
# 시큐어 코딩
# 별표 0.3개
class MyClass:
__a = 10 # 비공개 속성(Private Attributes)
_a = 100
b = 20
def __init__(self, c, d):
self.__c = c
self.d = d
c = MyClass(30, 40)
c._a # 다른 언어에서는 보통 _ 1개가 private value
# c.__a # 어? 접근이 안되네?! 이걸로 변수를 감추면 되겠다?! => 이렇게 생각하면 안된다.
# c.__a #error
# c._a # 출력: 100
# c.b # 출력: 20
# # c.__c # error
# c.d # 출력: 40
print(c._MyClass__c) # 실제로는 이렇게 출력할 수 있다.
class Comment를 작성해주세요.
요구사항
import datetime
class Comment:
def __init__(self, id, author, content):
self.id = id
self.author = author
self.content = content
self.timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
self.replies = [] # 대댓글을 저장하는 리스트
self.likes = 0 # 좋아요 카운트
def add_reply(self, comment): # 대댓글 추가하는 기능
self.replies.append(comment)
def add_like(self): # 좋아요 추가
self.likes += 1
def display(self, level=0): # 댓글 출력
print(f"{'-'*level}{self.author}({self.timestamp})[{self.likes} likes]: {self.content}")
for reply in self.replies:
reply.display(level + 1)
# 댓글 객체 생성
comment1 = Comment("c1", "User1", "첫 번째 댓글입니다.")
comment2 = Comment("c2", "User2", "두 번째 댓글입니다.")
# 대댓글 객체 생성 및 추가
reply1 = Comment("r1", "User3", "첫 번째 댓글에 대한 대댓글입니다.")
comment1.add_reply(reply1)
reply2 = Comment("r2", "User4", "두 번째 댓글에 대한 대댓글입니다.")
comment2.add_reply(reply2)
# 좋아요 추가
comment1.add_like()
reply2.add_like()
# 댓글 및 대댓글 출력
comment1.display()
comment2.display()
# 출력
User1(2024-01-15 12:55)[1 likes]: 첫 번째 댓글입니다.
-User3(2024-01-15 12:55)[0 likes]: 첫 번째 댓글에 대한 대댓글입니다.
User2(2024-01-15 12:55)[0 likes]: 두 번째 댓글입니다.
-User4(2024-01-15 12:55)[1 likes]: 두 번째 댓글에 대한 대댓글입니다.
저번주부터 시작한 클래스 대장정이 드디어 끝이 났다. 클래스를 제대로 다뤄본 적이 없어서 애를 많이 먹었는데 계속 새로운 클래스 만들고 기능 추가하고, 새로운 클래스 만들고 하다보니 어느정도 가닥은 잡힌 것 같다. 어제까지의 연습문제는 나름 할만했다고 생각을 했는데 오늘 연습문제는 꽤나 오래 생각했던 것 같다. 다같이 타이핑 할때는 내것이 된 것 같아도 혼자 해보니 그건 또 아닌 것 같다 ㅎㅎ. 나 혼자서 클래스를 짤 수 있을때까지 복습을 해야겠다는 생각이 든다. 계속 쓰일테니까... 할 수 있을 것이다.