25. 05. 12 공부일지

behumble·2025년 5월 11일

공부일지

목록 보기
12/20

회고

  • 코드를 짜면서 클래스를 나누는 것에 대한 의문이 생겼다. 객체지향적인 클래스는 무엇일까.. 나름대로 기준을 세우는데 코드를 짜다 보면 클래스가 잘못 구분되었다는 생각이 든다.
    객체지향의 본질은 "현실에서 구분되는 개념"이라 한다. 너무 복잡하게 생각하지말고 하나하나 구분해보는 능력을 키워야겠다.

필기

스태틱메서드

  • staticmethod는 객체와 아무런 관계가 없으며, self도 매개변수로 갖지 못한다.
  • 객체를 안만들고 메서드를 사용하기 위해 사용
# static 메서드
class Test:
    def __init__(self, number):
        self.number = number
        
    def output(self):
        print(self.number)
# output함수는 매개변수인 self가 객체를 만들어서 전달할때만 작동된다.
# 대부분의 클래스는 데이터와 함수의 결합이다.
# 데이터는 없고 공통의 기능만 갖는 클래스를 만들수도 있다.


#사칙연산을 하는 클래스
#공통의 데이터 공간을 두고
class Calculator:
    def __init__(self, x, y): #공통데이터공간
        self.x = x
        self.y = y
        
    def add(self): #덧셈
        return self.x + self.y
    
    def sub(self): #뺄셈
        return self.x - self.y
    
c1 = Calculator(4,5)
print(c1.add())
print(c1.sub())

class Calculator2:
    def add(self, x, y):
        return x + y
    
    def sub(self, x, y):
        return x - y
       
c2 = Calculator2()
print(c2.add(4,5))
print(c2.sub(4,5))


#staticmethod는 객체와 아무 관계없다.
#self도 매개변수로 갖지 못한다.
#staticmethod의 사용목적은 객체를 안만들고 특정메소드를 사용하는 것이다.
class Calculator3:
    @staticmethod #데코레이터
    def add(x,y):
        return x + y
    
    @staticmethod
    def sub(x,y):
        return x - y
    
    @staticmethod
    def mul(x,y):
        return x * y
    
print(Calculator3.add(4,5))
print(Calculator3.sub(4,5))
print(Calculator3.mul(4,5))

#Math가 수학함수들 갖고 있음(sin, cos, round 등 ....)
#웹 개발을 할 때 게시글 : <h1>Hi Hello</h1>
#디비에 접근해야하는 코드를 각각의 클래스가 소유할 경우 문제점
#: 1. 디비 아이피 바뀌었을 떄 or 아이디나 패스워드가 바뀌면
#     모든 클래스를 다 바꿔야하는 문제가 발생하며 보안에도 문제가 생긴다.
#     패스워드가 드러나게하면 안된다.
#staticmethod나 classmethod로 구성된 클래스를 만들어서 사용하는것이 바람직하다.
#staticmethod 단점이 클래스 변수를 못건드린다.
#classmethod를 사용한다.
#staticmethod는 함수들간에 기능적 유기성은 있지만 데이터가 필요없을 때 유용하다.

클래스메서드

  • 객체의 개수를 카운트하거나 제한하는 클래스를 만들고자 할 때 사용
class MyClass:
    #클래스변수의 영역이다.
    #객체를 만들던 말던 한번만 만든다.
    #생성자에서 이 부분을 건드리면 안된다.
    count = 0 #객체가 만들어질때마다 몇개 만들어졌는지 확인용도
    @staticmethod
    def addCount(): #staticmethod 입장에서는 매개변수인 self를 못쓰기에 count변수가 접근을 못한다.
        count += 1
        
# print(MyClass.addCount()) # error 코드
    
    @classmethod
    def increase(cls): #cls는 class이다.
        cls.count += 1
        
MyClass.increase()
print(MyClass.count)

#객체를 만들때 객체의 개수를 카운트하거나
#제한하는 클래스를 만들고자 할때 classmethod를 쓴다.

class SelfCount:
    __count = 0 #클래스 변수를 선언
                #class 안의 변수가 보존할 가치가 있다면 __(언더바2개)
    def __init__(self):
        SelfCount.__count+=1 #생성자에서 값 증가하기
        print(SelfCount.__count)

    @classmethod
    def count_output(cls):
        print(cls.__count)

s1 = SelfCount()
SelfCount.count_output()
s1 = SelfCount()
SelfCount.count_output()
s1 = SelfCount()
SelfCount.count_output()
s1 = SelfCount()
SelfCount.count_output()
# print(SelfCount.__count) #"이 속성을 볼수 없다"라는 에러메시지가 뜬다.	

싱글톤

#객체를 하나만 만들 수 있는 클래스(싱글톤패턴)
#디비커넥션풀을 만들어 사용할 때 디비가 연결/읽거나쓰기/연결끊기의 과정을 거치는데
#여기서 읽거나쓰기보다 연결과 연결끊기가 더 많은 시간을 소요한다.
#이런 기법을 Pool 기법이라고 한다. 이 Pool은 객체 하나만 만들게 해야한다.
#이런 디자인 패턴을 싱글턴 패턴이라고 한다.

class Singleton:
    #객체를 하나만 만들어야 한다.
    __instance = None #객체를 만들라고 하면 None이 아닐때만 객체를 만들고
                      #None이면 있던 객체를 반환한다.
    @classmethod
    @classmethod
    def getInstance(cls):
        if cls.__instance==None:
            cls.__instance= cls.__new__(cls) #클래스를 이용해 인스턴스 만들기   
        return cls.__instance 

    def display(self):
        print("*************")
        
    def __init__(self): #편법
        #이미 객체가 존재하면 강제 에러를 발생시킨다.
        if Singleton.__instance is not None:
            raise Exception("이 클래스는 반드시 getInstance로만 객체 생성이 가능합니다.")
        
s1 = Singleton.getInstance()
s1.display()

#클래스외부에서 객체를 만드는것들은 파이썬이 막을 방법이 없다.
#다른 언어들은 생성자한테도 접근권한이 있어서 이걸 private로 만들면 외부에서 객체 생성을 못한다. 
#파이썬 생성자에 이미 붙어있어서 별도로 접근권한을 건드릴 수 없다.
#편법을 써야 한다. 데이터말고 일을 하는 클래스들을 만들 때 좋다.
#쓸데없이 객체가 만들어졌다 없어졌다 하는걸 방지할 수 있다.
s2 = Singleton() 
s2.display()

데코레이터

# @staticmethod처럼 @시작한다. 
# 함수의 전후 동작을 감싸서 함수 가로채기를해서 뭔가 작업을 
# 처리하고 원래함수를 호출한다.

#데코레이터는 함수안에 또 함수를 만든다.(중첩함수)
#매개변수로 받아가서 중첩함수안에서 받아간 함수를 호출한다.
#파이썬에서는 주로 웹에서 많이 사용한다.
#반드시 로그인을 해야 접근이 가능한 함수를 만들고 싶다.
#함수를 중간에 가로채서 실행시간 체크를 할 수 있다.
def decorator1(func): #매개변수는 중첩함수안에서 호출될 함수.
    def wrapper():
        print("함수호출 전")
        func()
        print("함수호출 후")
    return wrapper #중첩함수의 참조를 반환해야한다.

@decorator1
def hello():
    print("Hello")
    
hello() #decorator1에게 납치당함. -> wrapper -> func()를 통해 함수 호출

import time
def time_decorator(callback):
    def innerfunction():
        callback()
        start = time.time()
        callback()
        end = time.time()
        print(f"{callback.__name__} 실행시간 : {end-start}초")
    return innerfunction
        
# @time_decorator
# def sigma():
#     s = 1
#     for i in range(1,1000000):
#         s += i
#         print("합계 : ", s)
        
# sigma()

#매개변수있고 반환값 있는 경우의 데코레이터 만들기
#callback - 뒤에서 호출한다.
#보통 호출자가 시스템이다.
#직접 호출을 못하고 데코레이터한테 사용자함수를 전달한다.
def mydecorator(callback):
    #호출될 함수가 어떤 매개변수를 가질지 알 수 없을경우에
    #tuple타입, dict타입
    def wrapper(*args, **kwargs):
        result = callback(*args, **kwargs)
        return result
    return wrapper

@mydecorator
def add(x, y):
    return x + y

print(add(5,7))

#문제 : 데코레이터 만들기 - 로그내보내기
#@mylog
#함수를 sigma 매개변수 s = sigma2(10)
"""
[Log] 함수이름 : sigma2
[Log] 입력값 : args = (10), kwargs = {}
[Log] 반환값 : 55
"""

def mylog(callback):
    def wrapper(*args, **kwargs):
        result = callback(*args, **kwargs)
        print(f"[LOG] 함수이름 : {callback.__name__}")
        print(f"[LOG] 입력값 : args {args} kwargs{kwargs}")
        print(f"[LOG] 반환값 : {result}")
        return result
    return wrapper

@mylog
def sigma2(limit=10):
    s = 0
    for i in range(1, limit+1):
        s += i
    return s
print(sigma2(100) )
print(sigma2(10))

@mylog #mylog를 가져다가 계속 써도 된다.
def sub(a, b):
    return a - b
print(sub(3,4))

과제

홈페이지_클래스

# 회원관리 : 회원번호, 회원아이디, 패스워드, 이름, 전화번호, 이메일
# 게시판 : 회원번호, 글번호, 제목, 내용, 작성일, 조회수
# 회원 가입 수정, 탈퇴, 조회(자기정보)
# 게시글 작성 - 회원번호, 제목, 내용, 작성일(date), 조회수 0
# 읽어보기, 수정(글쓴이만) 회원번호랑 패스워드 입력, 삭제(글쓴이만) 회원번호랑 패스워드 입력하면


import random
import datetime

class Homepage: # 홈페이지
    def __init__(self): 
        self.membershipList = []
        self.writingList = []
        
    def printWriteInfo(self): #글 정보 출력
        print("회원번호 : ")
        print("제목 : ")
        print("내용 : ")
        print("작성일 : ")
        print("조회수 : ")
        
    def main(self): #메뉴실행
        print("============")
        print("0. 창닫기")
        print("1. 회원가입")
        print("2. 로그인")
        print("3. 관리자")
        print("============")
        sel = input("번호를 선택 : ")
        while True:
            if sel == "1":
                print("회원가입 하실 정보를 입력해주세요.")
                
            elif sel == "2":
                print("id와 pw를 입력해주세요.")
                
            elif sel == "3":
                print("관리자모드로 접속합니다.")
            
            elif sel > "3":
                print("다시 입력하세요.")
                return
            
            elif sel == "0":
                print("프로그램 종료")
                break
        

class User: # 자기정보 수정, 탈퇴, 조회, 글쓰기(회원정보,제목,내용,작성일)
    def __init__(self, number, id, pw, name, phone, mail):
        self.number = number
        self.id = id
        self.pw = pw
        self.name = name
        self.phone = phone
        self.mail = mail
        
    def printInfo(self): #회원 정보 출력
        print(f"회원번호 : {self.number}", end = "\t")
        print(f"id : {self.id}", end = "\t")
        print(f"pw : {self.pw}", end = "\t")
        print(f"이름 : {self.name}", end = "\t")
        print(f"전화번호 : {self.phone}", end = "\t")
        print(f"메일 : {self.mail}")

class Post:
    def __init__(self, number, title, content):
        self.number = number
        self.title = title
        self.content = content
        self.datetime = datetime.date.today()
        self.count = 0
        
    def printPost(self):
        print(f"회원번호 : {self.number}", end = "\t")
        print(f"제목 : {self.title}", end = "\t")
        print(f"내용 : {self.content}", end = "\t")
        print(f"게시일 : {self.datetime}", end = "\t")
        print(f"조회수 : {self.count}")
        
class BoardSystem:
    def __init__(self):
        self.membershipList = []
        self.postList = []

    def signIn(self): #1.회원가입
        number = random.randint(1,1000)
        id = input("id : ")
        pw = input("pw : ")
        name = input("이름 : ")
        phone = input("전화번호 : ")
        mail = input("이메일 : ")
        user = User(number, id, pw, name, phone, mail)
        self.membershipList.append(user)
        
    def login(self): #2.로그인
        id = input("id : ")
        resultId = list(filter(lambda x : id in x.id, self.membershipList))
        for id in enumerate(resultId):
            pw = input("pw : ")
            break
        resultPw = list(filter(lambda x : pw in x.pw, self.membershipList))
        for pw in enumerate(resultPw):
            print(("===로그인 성공==="))
            break
        
    def writePost(self): #3.글쓰기
        title = input("제목 : ")
        content = input("내용 : ")
        post = Post(title, content)
        self.postList.append(post)
        
    def viewPost(self):
        if len(self.postList) == 0:
            print("등록된 글이 없습니다.")
        else:
            for post in self.postList:
                post.printPost()

    def main(self):
        while True:
            print("1. 회원가입 2. 로그인 3. 글쓰기 4. 글목록보기 0. 종료")
            sel = input("선택: ")
            if sel == "1":
                self.signIn()
                
            elif sel == "2":
                self.login()
                
            elif sel == "3":
                self.writePost()
                
            elif sel == "4":
                self.viewPost()
                
            elif sel == "0":
                print("프로그램 종료")
                break
            else:
                print("잘못된 입력")
                
if __name__ == "__main__":
    hpg = BoardSystem()
    hpg.main()

0개의 댓글