TIL08. Python : 객체 지향 프로그래밍(OOP)

ID짱재·2021년 9월 7일
0

Python

목록 보기
20/39
post-thumbnail

📌 이 포스팅에서는 Python의 클래스에서 클래스 변수와 인스턴스 변수에 접근하는 방법과 매서드 실행에 관해 알아보겠습니다.



🌈 객체 지향 프로그래밍(OOP)

🔥 클래스 변수 VS 인스턴스 변수

🔥 매서드 실행과 self



1. 클래스 변수 VS 인스턴스 변수


🤔 클래스를 생성해 봅시다!

class Student():
    """
    Student Class
    Author : Jaewon
    """
    # 클래스 변수 생성
    student_count = 0
    def __init__(self, name, number, grade, details, email=None):
        # 인스턴스 변수 : self가 항상 붙음
        self._name = name
        self._number = number
        self._grade = grade
        self._details = details
        self._email = email
        # 클래스 변수 사용 : 클래스 변수에 접근할 때는 클래스 이름을 타고 들어감
        Student.student_count += 1
    # __str__ : 객체 출력할 경우, 반환
    def __str__(self):
        return 'str {}'.format(self._name)
    # __repr__ : __str__과 유사한 기능이나, __str__보다 우선 순위 낮음
    def __repr__(self):
        return 'repr {}'.format(self._name)    
    # detail_info 메서드 : 객체의 id값 출력
    def detail_info(self):
        print('Current ID : {}'.format(id(self)))
        print('Student Detail Info : {} {} {}'.format(self._name, self._email, self._details))
    # __del__ : 오버라이딩으로 수정
    def __del__(self):
        Student.student_count -= 1

🤔 ==is의 차이는 무엇일까?

✔️ 같은 값을 가진 2개의 객체 생성 후 id값을 확인하면, 서로 다른 것을 확인할 수 있습니다. 같은 속성값을 가진 객체라 해도 id값이 다르면 서로 다른 객체입니다.
✔️ 서로 다른 객체란 의미는 메모리에서 서로 다른 공간(=독립적 공간)에 저장되었다는 것을 의미합니다.

  • print(id(student1)) ⇢ 140518341435344
  • print(id(student2)) ⇢ 140518341435152
# 객체 생성
student1 = Student('Cho', 2, 3, {'gender':'M', 'score1':90, 'score2':44})
student2 = Student('Jang', 4, 3, {'gender':'F', 'score1':85, 'score2':74}, 'student2@student.com')
# id 확인
print(id(student1)) # 140518341435344
print(id(student2)) # 140518341435152

✔️ "=="는 속성값(저장된 데이터) 비교하고, "is"는 id값(Reference Label)을 비교하여 True 또는 False를 반환합니다.

# '==' & 'is' 차이 : is는 reference된 주소 값을 비교하고, ==는 값을 비교함
print(student1 == student2) # False
print(student1 is student2) # False
print(student1._name == student2._name) # False 👈 ("cho" == "Jang"이기 때문)
print(student1._grade == student2._grade) # True 👈 True (3 == 3이기 때문)

🤔 클래스 변수 및 인스턴스 변수 접근하는 방법

✔️ 클래스 변수는 클래스 내부에서 공용으로 사용되기 때문에 클래스명을 통해 접근 가능하며, 인스턴스명을 통해서도 접근 가능합니다.

  • 클래스명으로 접근 : 🔍 [클래스명].[클래스변수명] ⇢ print(Student.student_count)
  • 인스턴스로 접근 : 🔍 [인스턴스명].[클래스변수명] ⇢ print(student1.student_count)

✔️ 단, 인스턴스 변수는 인스턴스를 통해 접근 가능합니다.

  • 🔍 인스턴스로 접근 : [인스턴스명].[인스턴스변수명] ⇢ print(student1._name) or print(student1._details)
# 클래스 변수 호출 : 클래스 변수인 "student_count"는 공용이기 때문에 자유롭게 접근 가능
print(Student.student_count) # 2
print(student1.student_count) # 2
print(student2.student_count) # 2

✔️ dir 메서드 : class 변수를 포함하여 사용 가능한 속성, 메서드 등을 리스트로 반환시켜줍니다.

print(dir(student1))
"""
['__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_details', '_email',
'_grade', '_name', '_number', 'detail_info', 'student_count']
"""

✔️ __dict__ 내장 메서드는 네임스페이스(속성명과 속성값)를 딕셔너리 형태로 반환해줍니다.
✔️ 클래스를 통해 네임스페이스 확인하면, "student_count"가 존재하는데, 인스턴스를 통해 네임스페이스를 확인하면 네임스페이스에 "student_count"가 존재하지 않습니다. "student_count"가 인스턴스의 네임스페이스에 존재하지 않음에도 불구하고 인스턴스를 통해 클래스변수에 접근 가능한 이유는 접근하려는 변수가 인스턴스의 네임스페이스 없는 경우 클래스의 네임스페이스를 탐색하여 반환해주기 때문입니다.

print(Student.__dict__) # student_count가 존재
"""
{'__module__': '__main__', '__doc__': '\n    Student Class\n    Author : Jaewon\n    Date : 2021.05.07\n    ', 'student_count': 2,
'__init__': <function Student.__init__ at 0x7fb95c9275e0>, '__str__': <function Student.__str__ at 0x7fb95c927670>,
'__repr__': <function Student.__repr__ at 0x7fb95c927700>, 'detail_info': <function Student.detail_info at 0x7fb95c927790>,
'__del__': <function Student.__del__ at 0x7fb95c927820>, '__dict__': <attribute '__dict__' of 'Student' objects>,
'__weakref__': <attribute '__weakref__' of 'Student' objects>}
"""
print(student1.__dict__) # student_count가 존재하지 않음
"""
{'_name': 'Cho', '_number': 2, '_grade': 3, '_details': {'gender': 'M', 'score1': 90, 'score2': 44}, '_email': None}
"""

⭐️ python에서 인스턴스를 통해 변수에 접근할 때, 인스턴스의 네임스페이스에 없으면, 클래스가 갖고 있는지 확인하고, 그래도 없으면 부모 클래스까지 탐색하여 반환해줍니다.
⭐️ 아래에서 위로 올라가면서 찾아주는 bottom-up 방식이며, top-down으로는 탐색하지 않기 때문에 클래스의 네임스페이스에 없다고 인스턴스의 네임스페이스를 탐색하지 않습니다. 즉, 클래스를 통해 인스턴스의 네임스페이스에 접근하면 에러가 발생합니다.



2. 매서드 실행과 self


🤔 매서드의 실행은 어떻게 할까?

✔️ 클래스의 매서드는 인스턴스를 통해 접근 가능하고, 클래스를 통해서도 접근 가능합니다. 단, 클래스를 통해 메서드에 접근할 경우, 어떤 인스턴스인의 메서드를 요청하는지 파라미터를 명시해주어야 합니다.

  • 인스턴스 통해 메서드 접근 : 🔍 [인스턴스명].[매서드명()]
  • 클래스 통해 메서드 접근 : 🔍 [클래스명].[매서드명(인스턴스명)]

✔️ 클래스를 통해 메서드를 호출하였을 때, 파라미터를 주지않으면 어떤 인스턴스 대한 매서드인지 알지 못하기 때문에 에러가 발생합니다.

# 메서드 실행
student1.detail_info()
student2.detail_info()
# Student.detail_info() ## 👈 Error : self를 찾지 못하기 때문(인스턴스로 접근해야함!)
Student.detail_info(student1) # 파라미터로 인스턴스를 넣어주면 가능(=student1.detail_info())

🤔 내장 매서드 doc

✔️ 내장 매서드 __doc__는 주석을 반환시켜줍니다. 클래스 내부에 주석을 가지고 관련한 정보를 기록해두면 __doc__를 통해 확인할 수 있습니다.

print(Student.__doc__)
"""
    Student Class
    Author : Jaewon
    Date : 2021.06.24
"""    

🤔 내장 매서드 class

✔️ 내장 매서드 __class__는 해당 인스턴스가 어떤 클래스에서 만들어졌는지 반환해줍니다.

print(student1.__class__, student2.__class__) # <class '__main__.Student'> <class '__main__.Student'>
print(id(student1.__class__) == id(student2.__class__)) # True
# True를 반환하는 이유는 Class(=Student)의 id를 비교했기 때문
profile
Keep Going, Keep Coding!

0개의 댓글