코딩일기

[PYTHON 2] 객체지향 프로그래밍 {str, decorator}(feat. Codestates _AI_BootCamp, 부트캠프) 본문

Code/기타

[PYTHON 2] 객체지향 프로그래밍 {str, decorator}(feat. Codestates _AI_BootCamp, 부트캠프)

daje 2021. 3. 13. 11:41
728x90
반응형

 

 

 

 

안녕하십니까 다제입니다. 

 

PYTHON의 객체지향의 __str__, decorat라는 개념에 대해서 학습을 진행해보도록 하겠습니다. 

 

 

 


 

 

 

저는 init을 공부하고 인스턴스를 만들었을 때 user1, user2를 출력하면 홍길동, 심청이 이렇게 나오겠지?

 

라고 생각을 하였습니다. 바로 실험을 한 결과를 보여드리겠습니다. 

 

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

user1 = User("홍길동", "123@gmail.com", "123456")
user2 = User("심청이", "456@gmail.com", "123456")


user1, user2


#출력값
<__main__.User object at 0x10a2d2fd0> 
<__main__.User object at 0x10a2d2d30>

 

이게 무슨 일이죠? 

예상과 다르게 메모리 주소값이 출력되었습니다. 

저는 저게 메모리 주소인지를 아는 것도 매우 어려웠습니다. 

 

python 변수를 저장할 때 메모리에 값을 지정하는 방식으로 저장을 합니다. 

어려운 개념이니 python의 데이터 저장방식이 메모리를 가르키는 방식이다 정도까지만 이해해주시면 될거 같습니다. 

 

그럼 이걸 어떻게 출력을 해야할까요?

이러한 궁금증을 해결할 수 있도록 도와주는 친구가 __str__입니다. 

위 코드에 아래와 같이 __str__을 추가해줘야 합니다. 

 

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

    def __str__(self):
        return f"{self.name}, {self.email}"


user1 = User("홍길동", "123@gmail.com", "123456")
user2 = User("심청이", "456@gmail.com", "123456")

print(user1)
print(user2)

#출력값
홍길동, 123@gmail.com
심청이, 456@gmail.com

 

 


 

 

저는 서버를 운영하고 싶기 때문에 이러한 질문이 생겼습니다. 

인스턴스를 유저들이 직접생성하게 하려면 어떻게 해야할까?..

저 인스턴스를 어떻게 샐 수 있을까?..

먼저 쉬운 count부터 한번 해결해보고자 합니다. 

 

 

지금까지는 인스턴스 자신만의 속성을 나타내는 인스턴스 변수를 배웠습니다. 

즉, 우리가 어떻게 인스턴스를 만들지, 어떻게 인스턴스를 출력할지 클래스 내부를 줌인하여 학습을 한 것입니다. 

 

count를 구성하려면 인스턴스가 아니라 인스턴스를 생성하는 클래스 쪽에 작업을 해주어야겠다는 생각이 들었습니다. 

아래 코드를 한번 보실까요?

 

class User:
    count = 0
    
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password
        
        User.count +=1


user1 = User("홍길동", "123@gmail.com", "123456")
user2 = User("심청이", "456@gmail.com", "123456")

print(User.count)

#출력값
2

 

아마 count = 0까지는 이해가 되실거라 생각이 됩니다. 

User.count +=1 는 왜 저기에 저렇게 적는걸까? 하는 생각을 하고 있으시죠?

 

유저가 생성될때는 무조건 실행되는 함수가 무엇을까요?

네! 맞습니다. __init__입니다.

그렇기 때문에 __init__에 count+=1를 넣어주어야 정확히 user의 카운트를 셀 수 있습니다. 

 

 

여기에 중요한 개념인

Class변수의 값을 읽는 방법과

Class변수의 값을 설정하는 방법에 대해 집고 넘어가겠습니다. 

 

1) 읽는 방법 

  -. 클래스 이름.클래스 변수 이름 - ex) User.count

  -. 인스턴스 이름.클래스 변수 이름 - ex) user1.count

 

2) 변수값 변경 방법 

  -. 클래스 이름.클래스 변수 이름 - ex) User.count

 

즉, user1.count를 통해 Class의 변수 정보를 변경할 수 없다는 이야기 입니다. 

 

왜 이러한 방법으로 작동이 될까요?

바로 상속이라는 개념 때문입니다. 

 

상속은 쉽게 부모가 자식에게 어떠한 정보를 내려준다. 

또는 자식이 부모의 정보를 가져온다 라고 생각하시면 됩니다. 

 

클래스는 인스턴스를 포함하고 있기 때문에 클래스가 부모가 되고 인스턴스가 자식이 됩니다. 

그러니 클래스 변수 count에 저장되어 있는 정보를 받아오게 되는 것이죠 

반대로 자식이 부모에게 정보를 보내줄 수는 없기 때문에 인스턴스.클래스 변수 이름으로는 설정을 할 수 없게 됩니다. 

이 말이 잘 이해가 안되시는 분들은 아래 코드를 복사하셔서 코드를 실행시켜보는 것을 추천드립니다. 

 

class User:
	count = 0
    
    def __init__(self, name, email, password):
        self.name = name
        self.email = email
        self.password = password
        
        User.count +=1


user1 = User("홍길동", "123@gmail.com", "123456")
user2 = User("심청이", "456@gmail.com", "123456")

user2.count = 100 

print(User.count)
print(user1.count)
print(user2.count)

#출력값
2
2
100

 

한가지 예를 더 보겠습니다. 

위 코드를 실행된 상태에서 아래 코드를 실행하셔야 코드가 작동 됩니다. 

#CASE1

User.count =3333333

print(User.count)
print(user1.count)
print(user2.count)

#결과값
3333333
3333333
100

-------------------------------------

#CASE2

user1.count = 1000

print(User.count)
print(user1.count)
print(user2.count)

#결과값
3333333
1000
100

위 코드에서 보시다시피 User.count를 변경한 후 출력을 하게되면 결과값이 User.count와 user1.count 값 모두 달라진 것을 확인 할 수 있습니다. CASE2에서 user1.count의 값을 변경해주었을때에는 User.count 값이 변경되지 않는 것을 확인하실 수 있습니다. 이게, 상속의 가장 대표적인 예입니다. 

 

 

 


 

 

 

이제는 데코레이터(decorator)에 대한 개념을 알아보도록 하겠습니다. 

 

decorator는 함수가 함수를 꾸며주어 새로운 모습을, 기능을 할 수 있도록 도와주는 역할을 합니다. 

 

파이썬에서는 상속이라는 개념을 좀 더 수월하게 사용하기 위해 decorator를 사용합니다. 

즉, 누가 누구를 꾸며주니? 꾸며주는 대상과 주체를 이해한다면 크게 어렵지 않습니다. 

 

 

먼저 함수가 함수를 꾸며준다는 의미를 코드로 살펴보도록 하겠습니다. 

# character라는 함수를 인자로 받아옵니다. 
def alarm_attack_warning(character):
    def emergency():
        # emergency 함수가 개릭터를 호출하기 위한 코드 
        # 이 부분이 이해가 안되신다면 character뒤에 숫자를 넣어서 출력해보시면 됩니다. 
        character()
        print("적에게 공격을 받습니다.")

    return emergency


    def character1():
        print("character1님")


    def character2():
        print("character2님")


    def character3():
        print("character3님")


# 출력하는 방법1
# alarm_attack_warning도 함수 이기 때문에 함수명만 기재하면 실행이 되지 않습니다. 
# 이에, ()를 함수명 뒤에 입력하여 실행시키는 코드 입니다. 
# 이 부분이 이해가 안되신다면, ()를 제외하고 실행해보시기는 것을 추천드립니다. 
alarm_attack_warning(character1)()
alarm_attack_warning(character2)()
alarm_attack_warning(character3)()

# 출력하는 방법2
warning_message = alarm_attack_warning(character1)
warning_message()

 

적어게 공격을 받았다는 것을 캐릭터에게 알려주기 위해서 위와 같이 함수가 함수를 꾸며주는 방식으로 코드를 구성할 수 있습니다. 그렇게 캐릭터가 1000개라면 이걸 어떻게 할 수 있을까요?

 

매번 이렇게 코드를 작성할 수 없겠죠? 그래서 데코레이터라는 개념이 나왔습니다. 

 

def alarm_attack_warning(character):
    def emergency():
        character()
        print("적에게 공격을 받습니다.")

    return emergency


    @alarm_attack_warning
    def character1():
        print("character1님")


    @alarm_attack_warning
    def character2():
        print("character2님")


    @alarm_attack_warning
    def character3():
        print("character3님")


character1()
character2()
character3()

 

이렇게 출력을 하면 코드도 깔끔하고, 출력하는 코드도 줄어드는 것을 보실 수 있습니다. 

 

이러한 개념들을 숙지하시어 클린코드가 되는 그날까지 화이팅입니다!

 

오늘도 글을 읽어주셔서 감사합니다.

 

공감 부탁드립니다!

 

 

 

728x90
반응형