TIL | Python class#1

vel.Ash·2022년 5월 15일
0
post-thumbnail

객체지향 프로그래밍

클래스와 인스턴스

class User: # 클래스 이름 첫글자는 항상 대문자
    pass

user1 = User()  # 유저 인스턴트 생성
user2 = User()
user3 = User() # 이 3개의 인스턴스들은 같은 클래스로 만들었어도 서로 다른 존재

# 인스턴스 변수 정의하기
# 인스턴스 이름. 속성 이름(인스턴스 변수) = "속성에 넣을 값"
user1.name = "홍길동"  # 이름을 나타내는 속성 추가
user1.email = "gildong@naver.com"
user1.password = "12345"

user2.name = "강영훈"
user2.email = "younghoon@naver.com"
user2.password = "23456"

user3.name = "최지웅"
user3.email = "jiwoong@naver.com"
user3.password = "34567"

# 인스턴스 변수 사용하기
# 인스턴스 이름. 인스턴스 변수 이름
# 예시 print(user1.email)

클래스 변수

<예시 1>

# 클래스 변수 사용법
class User:
    count = 0

    def __init__(self, name, email, pw):
        # 유저 인스턴스의 모든 변수를 지정해주는 메소드
        self.name = name
        self.email = email
        self.pw = pw

    def say_hello(self):
        print("안녕하세요! 저는 {}입니다!".format(self.name))

user1 = User("hong","hong@naver.com","12345")
user2 = User("gil","gil@naver.com","12345")

User.count = 1  # 클래스 변수 설정
print(User.count) # 클래스 변수 출력 -> 출력값 1

<예시 2>

# 클래스 변수 사용법
class User:
    count = 0

    def __init__(self, name, email, pw):
        # 유저 인스턴스의 모든 변수를 지정해주는 메소드
        self.name = name
        self.email = email
        self.pw = pw

        User.count += 1

    def say_hello(self):
        print("안녕하세요! 저는 {}입니다!".format(self.name))

user1 = User("hong","hong@naver.com","12345")
user2 = User("gil","gil@naver.com","12345")

print(User.count)

<예시 3>

# 클래스 변수 : 한 클래스의 모든 인스턴스가 공유하는 속성
class User:
    count = 0

    def __init__(self, name, email, pw):
        # 유저 인스턴스의 모든 변수를 지정해주는 메소드
        self.name = name
        self.email = email
        self.pw = pw

        User.count += 1

    def say_hello(self):
        print("안녕하세요! 저는 {}입니다!".format(self.name))

user1 = User("hong","hong@naver.com","12345")
user2 = User("gil","gil@naver.com","12345")

user1.count = 5  # 클래스 변수와 같은 이름의 인스턴스 변수 생성해주는 것
# 따라서 클래스 변수 출력 값에는 변화 없음
# -> 이렇게 헷갈릴 수 있기 때문에 클래스 변수 값을 설정할 때는 클래스 이름으로 다뤄주기!!

print(User.count)
print(user1.count)
print(user2.count)
2
5
2
*클래스 변수의 값 읽는 법*클래스 변수의 값 설정하는 법
클래스 이름. 클래스 변수 이름클래스 이름. 클래스 변수 이름 (얘로 쓰기!!)
인스턴스 이름.클래스 변수 이름인스턴스 이름.클래스 변수 이름

메소드의 종류

1.인스턴스 메소드

: 인스턴스 변수를 사용하거나 인스턴스 변수의 값을 설정하는 메소드
*인스턴스 메소드의 특별한 규칙- 첫번때 파라미터의 이름은 꼭 self로 쓰기 !

class User:
    def say_hello(self):
        # 인사 메세지 출력 메소드
        print("안녕하세요! 저는 {}입니다!".format(self.name))
    def login(self, my_email, my_password):
        # 로그인 메소드
        if (self.email == my_email and self.password == my_password):
            print("로그인 성공, 환영합니다!")
        else:
            print("로그인 실패, 없는 아이디거나 잘못된 비밀번호입니다.")

# 파이썬에선 인스턴스 메소드의 첫번째 파라미터 이름을 self로 쓰라고 권장!!
# 인스턴스 메소드를 호출하는 인스턴스 자신이 첫번째 파라미터로 들어가기 때문에 self로 써주는 게 의미상으로도 좋은듯!

<예시 1>

class User: 
    def say_hello(some_user):
        print("안녕하세요! 저는 {}입니다!".format(some_user.name))
        # name이라는 인스턴스 변수를 사용하므로 say_hello는 인스턴스 메소드

user1 = User()  
user2 = User()
user3 = User()

user1.name = "홍길동"  
user1.email = "gildong@naver.com"
user1.password = "12345"

user2.name = "강영훈"
user2.email = "younghoon@naver.com"
user2.password = "23456"

user3.name = "최지웅"
user3.email = "jiwoong@naver.com"
user3.password = "34567"

# 인스턴스 메소드 사용하기
# 클래스 이름.메소드 이름(인스턴스)
# 예시 1. User.say_hello(user1)

# 인스턴스 이름.메소드 이름()
# 예시 2. user1.say_hello()

# 예시 2 -> 파라미터를 넘겨주지 않았는데 왜 오류가 안날까?
# 예시 2처럼 인스턴스 메소드를 호출하면 인스턴스가 자동으로 파라미터로 들어간다.
# 오히려 안에 파라미터 써주면 에러 발생!

<예시 2>

class User:
    def say_hello(some_user):
        # 인사 메세지 출력 메소드
        print("안녕하세요! 저는 {}입니다!".format(some_user.name))
    def login(some_user, my_email, my_password):
        # 로그인 메소드
        if (some_user.email == my_email and some_user.password == my_password):
            print("로그인 성공, 환영합니다!")
        else:
            print("로그인 실패, 없는 아이디거나 잘못된 비밀번호입니다.")

user1 = User()

user1.name = "홍길동"
user1.email = "gildong@naver.com"
user1.password = "12345"

user1.login("gildong@naver.com", "12345") 
# 위와 동일하게 첫번째 파라미터 자동으로 들어가서 생략해줘야함 
로그인 성공, 환영합니다!

<예시 3>

class User:
    def say_hello(self):
        # 인사 메세지 출력 메소드
        print("안녕하세요! 저는 {}입니다!".format(self.name))

    def check_name(self, name):
        # 파라미터로 받는 name이 유저의 이름과 같은지 불린으로 리턴
        return self.name == name

user1 = User()
user2 = User()

user1.name = "홍길동"
user1.email = "gildong@naver.com"
user1.password = "12345"

user2.name = "강영훈"
user2.email = "younghoon@naver.com"
user2.password = "23456"

print(user1.check_name("홍길동"))
True

2.클래스 메소드 (@classmethod)

: 클래스 변수의 값을 읽거나 설정하는 메소드
*인스턴스 메소드의 특별한 규칙- 첫번때 파라미터의 이름은 꼭 cls로 쓰기 !

<예시 1>

class User:
    count = 0

    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw

        User.count += 1

    def say_hello(self):
        print("안녕하세요! 저는 {}입니다.".format(self.name, self.email))

    def __str__(self):
        return "사용자: {}, 이메일: {}, 비밀번호: *****".format(self.name, self.email)

    #클래스 메소드 만들어 주기  
    @classmethod
    def number_of_users(cls):
        # 자동전달되는 cls  파라미터는 User 클래스를 나타냄. 따라서 cls.count = User.count
        print("총 유저 수는: {}입니다.".format(cls.count))

user1 = User("hong","hong@naver.com","12345")
user2 = User("gil","gil@naver.com","12345")
user3 = User("dong","dong@naver.com","12345")

User.number_of_users()
user1.number_of_users()
총 유저 수는: 3입니다.
총 유저 수는: 3입니다.

❓ 왜 클래스 메소드를 사용할까?
-인스턴스 변수를 사용하지 않기 때문에(보면 self를 써도 인스턴스 변수를 불러오지 않음. 클래스변수만 사용하기 때문에)
-인스턴스 변수가 하나도 없을 때 사용될 수 있는 경우에 !

❓그렇다면 클래스변수와 인스턴스 변수 둘다 쓴다면?
→ 인스턴스 변수 사용하기!! (인스턴스 변수, 클래스 변수 모두 사용 가능하기 때문에)
-클래스 메소드는 인스턴스 변수 사용불가!!

<예시 2>

class User:
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password

    @classmethod
    def from_string(cls, string_params):
        params_list = string_params.split(",")

        name = params_list[0]
        email = params_list[1]
        password = params_list[2]
        # cls.name 이런 식으로 쓰게 되면 인스턴스 변수가 아닌 클래스 변수에 값을 넣게 된다
        # 클래스 변수는 모든 클래스가 공통으로 가지는 변수

        return cls(name, email, password)  # 생성자를 통해 인스턴스 변수 생성

    @classmethod
    def from_list(cls, list_params):
        name = list_params[0]
        email = list_params[1]
        password = list_params[2]

        return cls(name, email, password)

# 유저 생성 및 초기값 설정
younghoon = User.from_string("강영훈,younghoon@codeit.kr,123456")
yoonsoo = User.from_list(["이윤수", "yoonsoo@codeit.kr", "abcdef"])

print(younghoon.name, younghoon.email, younghoon.password)
print(yoonsoo.name, yoonsoo.email, yoonsoo.password)
강영훈 younghoon@codeit.kr 123456
이윤수 yoonsoo@codeit.kr abcdef

3.정적 메소드

-인스턴스 변수, 클래스 변수를 전혀 다루지 않는 메소드

class User:
    count = 0
    
    def __init__(self, name, email, pw):
        self.name = name
        self.email = email
        self.pw = pw
    
        User.count += 1
    
    def say_hello(self):
        print("안녕하세요! 저는 {}입니다!".format(self.name))
    
    def __str__(self):
        return "사용자: {}, 이메일: {}, 비밀번호: ******".format(self.name, self.email)
    
    @classmethod
    def number_of_users(cls):
        print("총 유저 수는: {}입니다".format(cls.count))
    
		# 정적 메소드 
    @staticmethod
    def is_valid_email(email_address):
        return "@" in email_address

print(User.is_valid_email("taehosung"))
print(User.is_valid_email("taehosung@codeit.kr"))
    
print(user1.is_valid_email("taehosung"))
print(user1.is_valid_email("taehosung@codeit.kr"))
# 인스턴스, 클래스 두가지 모두를 통해 사용 가능 
False
True
False
True

실습 1

class User:
    # 인스턴스 변수 설정
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password

        self.following_list = []    # 이 유저가 팔로우하는 유저 리스트
        self.followers_list = []    # 이 유저를 팔로우하는 유저 리스트

    # 팔로우
    def follow(self, another_user):
        # 나의 팔로잉 리스트
        self.following_list.append(another_user)
        another_user.followers_list.append(self)

    # 내가 몇 명을 팔로우하는지 리턴
    def num_following(self):
        return len(self.following_list)

    # 나를 몇 명이 팔로우하는지 리턴
    def num_followers(self):
        return len(self.followers_list)

# 유저들 생성
user1 = User("Young", "young@codeit.kr", "123456")
user2 = User("Yoonsoo", "yoonsoo@codeit.kr", "abcdef")
user3 = User("Taeho", "taeho@codeit.kr", "123abc")
user4 = User("Lisa", "lisa@codeit.kr", "abc123")

# 유저마다 서로 관심 있는 유저를 팔로우
user1.follow(user2)
user1.follow(user3)
user2.follow(user1)
user2.follow(user3)
user2.follow(user4)
user4.follow(user1)

# 유저 이름, 자신의 팔로워 수, 자신이 팔로우하는 사람 수를 출력합니다
print(user1.name, user1.num_followers(), user1.num_following())
print(user2.name, user2.num_followers(), user2.num_following())
print(user3.name, user3.num_followers(), user3.num_following())
print(user4.name, user4.num_followers(), user4.num_following())
Young 2 2
Yoonsoo 1 3
Taeho 2 0
Lisa 1 1

매직 메소드(=스페셜 메소드)

= 특정 상황에서 자동으로 호출되는 메소드
= 더블 언더스코어(double underscore)를 줄여서 던더 메소드라고 부르기도함

1.init 메소드(이닛 메소드) 사용법

: 한줄에 인스턴스 생성과 초기값을 바로 한 줄에 생성해줄 수 있게 한다

class User:
    # __init__은 인스턴스가 생성될 때 자동으로 호출
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password

# user 생성, 초깃값을 설정
user1 = User("hong","hong@naver.com","12345")

user2 = User("gil","gil@naver.com","12345")

user3 = User("dong","dong@naver.com","12345")

print(user1.email)
print(user2.name)
print(user3.password)
hong@naver.com
gil
12345

2.str 메소드(던더 에스티알)

: print 사용할 때 자동으로 호출(어떤 인스턴스를 호출하면 이 메소드의 리턴값이 출력

class User:
    def __init__(self, name, email, pw):
        # 유저 인스턴스의 모든 변수를 지정해주는 메소드
        self.name = name
        self.email = email
        self.pw = pw

    def say_hello(self):
        print("안녕하세요! 저는 {}입니다!".format(self.name))

    def __str__(self):
        # __str__는 print 사용할 때 자동으로 호출(어떤 인스턴스를 호출하면 이 메소드의 리턴값이 출력 
        return "사용자: {}, 이메일: {}, 비밀번호 : *****".format(self.name, self.email)

user1 = User("hong","hong@naver.com","12345")
user2 = User("gil","gil@naver.com","12345")

# __str__ 정의하지 않을 경우
print(user1) # 인스턴스가 어떤 클래스인지 나오고 주솟값이 나온다  <__main__.User object at 0x10cac7c40>

# __str__ 정의 한 뒤
print(user2) # 사용자: gil, 이메일: gil@naver.com, 비밀번호 : *****

데코레이터

-파라미터로 어떤 함수를 받아 그 함수를 꾸며서 새로운 함수를 리턴해준다

def print_hello():
    print("안녕하세요!")

# 데코레이터 함수 생성 
def add_print_to(original): # 파라미터로 함수를 받는다
    def wrapper():
        print('함수 시작') # 부가기능 1
        original()
        print('함수 끝') # 부가기능 2 -> original(print_hello)를 꾸며줌(데코레이팅)
    return wrapper

add_print_to(print_hello)()

# 좀 더 깔끔하게 출력
print_hello = add_print_to(print_hello)
print_hello()
함수 시작
안녕하세요!
함수 끝
함수 시작
안녕하세요!
함수 끝

⭐ 더 간단하게 데코레이터 사용하기!!! @데코레이터

def add_print_to(original): # 파라미터로 함수를 받는다
    def wrapper():
        print('함수 시작') # 부가기능 1
        original()
        print('함수 끝') # 부가기능 2 -> original(print_hello)를 꾸며줌(데코레이팅)
    return wrapper

@add_print_to
# print_hello함수를 add_print_to로 꾸며주라는 뜻
def print_hello():
    print("안녕하세요!")

print_hello()
함수 시작
안녕하세요!
함수 끝
profile
코린이의 개발공부

0개의 댓글