Lina's Toolbox

스파르타 내일 배움 캠프 AI웹개발 | 파이썬 팀 과제 / 클래스 인스턴스(객체) 활용 본문

스파르타 내일 배움 캠프 AI 웹개발 과정/python

스파르타 내일 배움 캠프 AI웹개발 | 파이썬 팀 과제 / 클래스 인스턴스(객체) 활용

Woolina 2024. 7. 4. 16:27

 

과제 내용

 

더보기
  1. Member 클래스와 Post 클래스를 정의하세요.
  2. Member 클래스에는 다음과 같은 속성을 가지고 있어야 합니다.
    • 회원 이름 (name)
    • 회원 아이디 (username)
    • 회원 비밀번호 (password)
  3. Member 클래스에는 다음과 같은 메소드를 가지고 있어야 합니다.
    • 회원 정보를 print해주는 display (회원이름과 아이디만 보여주고 비밀번호는 보여줘서는 안됩니다!)
  4. Post 클래스에는 다음과 같은 속성을 가지고 있어야 합니다.
    • 게시물 제목 (title)
    • 게시물 내용 (content)
    • 작성자 (author) : 회원의 username 이 저장되어야 함!
  5. 회원 인스턴스를 세개 이상 만들고 members 라는 빈리스트에 append를 써서 저장해주세요
    1. members 리스트를 돌면서 회원들의 이름을 모두 프린트 해주세요
  6. 각각의 회원이 게시글을 세개 이상 작성하는 코드를 만들어주세요.(회원이 세명이명 총 9개 이상의 post 인스턴스가 만들어져야 합니다). 만들어진 게시글 인스턴스들은 posts 빈리스트에 append를 써서 저장해주세요
    1. for 문을 돌면서 특정유저가 작성한 게시글의 제목을 모두 프린트 해주세요
    2. for문을 돌면서 ‘특정 단어’가 content에 포함된 게시글의 제목을 모두 프린트 해주세요.

 

추가 도전 과제:

  1. input을 이용하여 Member 인스턴스 만드는것을 사용자가 터미널에서 할 수 있게 해주세요.
  2. post도 터미널에서 생성할 수 있게 해주세요.
  3. (심화)비밀번호 해싱이 무엇인지 공부한 후 hashlib 라이브러리를 써서 회원 비밀번호를 해시화하여 저장하게 해주세요

 

코드 스니펫
# ----- 코드 정의 ------
class Member:
    # TODO : 코드 구현이 필요합니다.

    def display(self):
        # TODO : 코드 구현이 필요합니다.
        pass


class Post:
    # TODO : 코드 구현이 필요합니다.
    pass


# ----- 코드 실행 ------
members = []
posts = []

# TODO : 코드 구현이 필요합니다.

 

평가 기준
더보기
  • 클래스와 인스턴스 개념을 설명할 수 있는가?
  • 메소드와 어트리뷰트(속성)을 설명할 수 있는가?
  • 클래스를 정의할 수 있는가?
  • 인스턴스를 생성할 수 있는가?

 

과제 난이도가 쉽고 양이 많지 않아 3명이서 역할 분담하는 데에 고민이 많았다.

두명이면 나누기 쉬울 것 같은데.. 클래스도 2개뿐

클래스와 객체 관계를 이해하는 것은 매우 중요한 부분이기 때문에 우리 조는 개인적으로 각자 코드를 완성한 후,

다음날 각자 코드를 설명한 후에 잘 된 부분을 합치기로했다.

 

naive code
class Member:
    def __init__(self, name, username, password):
        self.name = name            # 회원 이름
        self.username = username    # 회원 아이디
        self.password = password

    # 회원 정보 print(회원이름과 아이디만 보여주고 비밀번호는 보여줘서는 안됩니다!)
    def display(self):
        print(f"회원 이름 : {self.name}, 회원 아이디: {self.username}")


class Post:
    def __init__(self, title, content, author):
        self.title = title
        self.content = content
        self.author = author        # 작성자 Member.username


# 맴버 리스트 생성 및 객체 생성
members = []
members.append(Member("김우린", "kimwoolina", 1234))
members.append(Member("이상현", "sanghyun", 3456))
members.append(Member("이새예", "saeye", 6789))

# 회원 이름 출력
for member in members:
    print(member.name)


# 게시글 리스트 생성 및 게시글 객체 생성
posts = []
posts.append(Post("Title 1", "content of post 1 by Lina Kim", "kimwoolina"))
posts.append(Post("Title 2", "content of post 2 by Lina Kim", "kimwoolina"))
posts.append(Post("Title 3", "content of post 3 by Lina Kim", "kimwoolina"))
posts.append(Post("Title 4", "content of post 4 by Sanghyun Lee", "sanghyun"))
posts.append(Post("Title 5", "content of post 5 by Sanghyun Lee", "sanghyun"))
posts.append(Post("Title 6", "content of post 6 by Sanghyun Lee", "sanghyun"))
posts.append(Post("Title 7", "content of post 7 by Saeye Lee", "saeye"))
posts.append(Post("Title 8", "content of post 8 by Saeye Lee", "saeye"))
posts.append(Post("Title 9", "content of post 9 by Saeye Lee", "saeye"))

# 특정유저(kimwoolina)가 작성한 게시글의 제목을 모두 프린트
for post in posts:
    if post.author == "kimwoolina":
        print(f"kimwoolina님의 작성한 게시글: {post.title}")
        
# ‘특정 단어’가 content에 포함된 게시글의 제목을 모두 프린트
for post in posts:
    if  "Lee" in post.content :
        print(f"글 내용에 'Lee'가 포함된 게시글: {post.title}")

직관적으로 요구 사항을 보면서 작성한 코드. (추가 과제 제외)

이렇게 해도 정상적으로 작동하지만 반복되는 코드들이 보기 싫었다.

 

리팩토링(Refactorying)
class Member:
    def __init__(self, name, username, password):
        self.name = name            # 회원 이름
        self.username = username    # 회원 아이디
        self.password = password

    # 회원 정보 print
    def display(self):
        print(f"회원 이름 : {self.name}, 회원 아이디: {self.username}")


class Post:
    def __init__(self, title, content, author):
        self.title = title
        self.content = content
        self.author = author        # 작성자 Member.username


# 함수 정의
def add_members(member_list, member_data):
    for name, username, password in member_data:
        member_list.append(Member(name, username, password))

def add_posts(post_list, post_data):
    for title, content, author in post_data:
        post_list.append(Post(title, content, author))

def display_member_names(member_list):
    for member in member_list:
        print(f"회원 이름: {member.name}")

# 데이터 준비
member_data = [
    ("김우린", "kimwoolina", "password1"),
    ("이상현", "sanghyun", "password2"),
    ("이새예", "saeye", "password3")
]

post_data = [
    ("Title 1", "post 1 content by Lina Kim", "kimwoolina"),
    ("Title 2", "post 2 content by Lina Kim", "kimwoolina"),
    ("Title 3", "post 3 content by Lina Kim", "kimwoolina"),
    ("Title 4", "post 4 content by Sanghyun Lee", "sanghyun"),
    ("Title 5", "post 5 content by Sanghyun Lee", "sanghyun"),
    ("Title 6", "post 6 content by Sanghyun Lee", "sanghyun"),
    ("Title 7", "post 7 content by Saeye Lee", "saeye"),
    ("Title 8", "post 8 content by Saeye Lee", "saeye"),
    ("Title 9", "post 9 content by Saeye Lee", "saeye")
]

# Members 리스트 생성 및 회원 인스턴스 추가
members = []
add_members(members, member_data)

# Members 리스트를 돌면서 회원들의 이름 프린트
display_member_names(members)

# Posts 리스트 생성 및 게시글 인스턴스 추가
posts = []
add_posts(posts, post_data)

# 특정 유저가 작성한 게시글의 제목 프린트
username_to_check = "kimwoolina"
print(f"\nPosts written by {username_to_check}:")
for post in posts:
    if post.author == username_to_check:
        print(post.title)

# 특정 단어가 content에 포함된 게시글의 제목 프린트
keyword_to_check = "Lee"
print(f"\nPosts containing '{keyword_to_check}' in content:")
for post in posts:
    if keyword_to_check in post.content:
        print(post.title)

산발적으로 작성되어있던 코드들을 각각 함수로 작성하여 묶어주었다.

그리고 데이터들은 한번에 넣어주기 위해 튜플을 사용하여 함수를 실행하기 전에 데이터를 먼저 준비했다.

검색에 이용되는 값들도 최대한 변수에 넣어주었다.

 

가독성이 올라가고 함수별로 관리할 수 있어 유지보수에 더 쉬운 코드로 수정하였다!

 

추가 과제 1 : 비밀번호 해시화하여 저장

과제 조건에 따라 hashlib 라이브러리를 사용하였다.

SHA256 방식으로 해싱하였다. 

해싱할 문자열을 인수로 update() 함수를 호출하면 해당 문자열이 해싱된다.

이 함수에 전달하는 문자열은 바이트 문자열이어야 하므로,

encode('utf-8')을 이용하여 유니코드 문자열을 UTF-8 형식의 바이트 문자열로 변환한다.

 

💡 만약 해싱할 문자열을 추가하고 싶으면 추가할 문자열과 함꼐 update 함수를 추가로 호출하면 됨

🚨 해싱한 문자열은 복구할 수 없음 주의 (해시 함수는 단방향 함수!)

더보기

- 해싱(Hashing)

  •  어떤 항목의 Key만을 가지고 바로 항목이 들어 있는 배열의 인덱스를 결정하는 기법
  • 원본 문자열을 알아볼 수 없는 난해한 문자열로 정의하는 방법
  • 시간복잡도 O(1)

 

- 해시 함수 

  • 키(Key) 값을 값(Value)이 저장되는 주소 값으로 바꾸기 위한 수식
  • 임의의 길이를 갖는 임의의 데이터를 고정된 길이의 데이터로 매핑하는 단방향 함수.
  • 아무리 큰 숫자를 넣더라도 정해진 크기의 숫자가 나오는 함수이다. 예를 들면 어떤 숫자를 10으로 나누었을 때 그 나머지를 구하는 함수도 해시 함수이다. 

- SHA256 방식: 유추나 복호화가 불가능함

 

- 인코딩 : 문자를 어떻게 출력할 지에 대한 약속

 

- 아스키코드(ASCII)

  • 128개의 문자조합을 제공하는 7비트 부호.
  • 아스키코드만으로는 각 나라별 언어를 표현할 수 없다. 이를 해결한 코드가 유니코드.
  • 알파벳, 숫자, 특수기호, 그 외 컴퓨터에 필요한 몇 가지만 정의되어 있어서점차 여러 나라에서 컴퓨터를 사용하게 되고 통신이 발달하다보니 기존의 아스키 인코딩보다더 많은 문자들을 정의한 새로운 인코딩이 필요해짐
  • 컴퓨터 내에서 문자 A는 65로 저장됨

- 유니코드(Unicode)

  • 각 나라별 언어를 모두 표현하기 위해 나온 코드 체계가 유니코드숫자와 글자, 즉 키 값이 1:1로 매핑된 형태의 코드
  • 사용중인 운영체제, 프로그램, 언어에 관계 없이 문자마다 고유한 코드 값을 제공하는 새로운 개념의 코드
  • 16비트를 표현하므로 최대 65,536자 표현 가능
  • 영문/숫자/한글/한자 등 모든 글자는 이론적으로 2바이트. 아주 희귀한 문자들은 2바이트를 초과할 수도 있다.
  • UTF-8은 유니코드가 파일에 저장될 때 영문/숫자는 아스키코드와 똑같이 1바이트 사용
  • 한글 등은 3바이트로 파일에 저장

- UTF-8(가변길이 인코딩)

  • 유니코드를 사용하는 인코딩 방식 중 하나
  • 영문/숫자/기호는 1바이트로, 한글/한자는 3바이트로 표현
  • 전 세계의 모든 언어를 하나의 파일에 쓸 수 있다
  • UTF-8 유니코드는 아스키 코드와 영문 영역에서는 100% 호환
  • 만약, UTF-8 유니코드 문서에 한글 등이 전혀 없고 영문과 숫자로 이루어져 있다면 그 카드는 아스키코드와 동일
  • 유니코드를 위한 가변 길이 문자 인코딩 방식 중 하나
  • 유니코드 한 문자를 나타내기 위해 1바이트에서 4바이트까지 사용

 

추가 과제 2,3: input으로 객체 생성
def create_member_from_input():
    name = input("Enter member name: ")
    username = input("Enter username: ")
    password = input("Enter password: ")
    return Member(name, username, password)


def create_post_from_input():
    title = input("Enter post title: ")
    content = input("Enter post content: ")
    author = input("Enter post author: ")
    return Post(title, content, author)

 

사용자가 input으로 입력한 값으로 객체를 생성할 수 있는 함수를 작성하였다.

 

if __name__ == "__main__":

	members = []

	post = []

	# 사용자 입력을 통한 회원 생성
    while True:
        members.append(create_member_from_input())
        another = input("Add another member? (yes/no): ")
        if another.lower() != 'yes':
            break
            

	# 사용자 입력을 통한 글 생성
    while True:
        posts.append(create_post_from_input())
        another = input("Add another Post? (yes/no): ")
        if another.lower() != 'yes':
            break

사용자가 원할 때 까지 입력을 받기 위해서 while문 안에 넣어서 작성해주었다.

이를 위해 특정한 시작 지점이 필요하여 main 함수를 작성해서 분리해주었다.

포스트 검색도 input을 받아 처리하는 방식으로 변경하였다.


 

전체 완성 코드는

 

Github : https://github.com/kimwoolina/programmers/blob/main/class_practice.py