1. 퍼블릭 변수 (Public Variable) : variable
변수 맘대로 쓰라는 뜻.
클래스 외부에서 자유롭게 접근할 수 있는 변수.
다른 클래스나 객체에서 직접 읽거나 쓸 수 있다.
2. 프로텍티드 변수 (Protected Variable) : _variable
변수 안바꾸길 권장한다는 뜻.
동일 패키지 내의 다른 클래스와 상속 관계에 있는 하위 클래스에서 접근 가능한 변수.
클래스 외부에서는 직접 접근할 수 없다.
3. 프라이빗 변수 (Private Variable) : __variable
변수 바꾸지 마
해당 클래스 내부에서만 접근할 수 있는 변수.
다른 클래스나 객체에서는 직접 접근할 수 없다.
접근을 위해서는 클래스 내부에 접근자 메소드와 설정자 메소드를 제공해야함.
class Private_Var: # Private_Var 클래스 만들기
def __init__(self): # 초기화메서드
self.x = 1 # 변수x 는 public
self._y = 2 # 변수y 는 protected
self.__z = 3 # 변수z 는 private
self.__c = 8 # 변수c 는 private
a = Private_Var() # Private_Var 클래스로 a 객체 만들기
print(f'public 변수 > {a.x}') # 1 (public 변수라서 그냥 출력됨)
# print(f'private 변수 > {a.__c}') # AttributeError: 'Private_Var' object has no attribute '__c'
# (private 변수는 출력시 예외 처리되어있음)
print(dir(a))
# 네임스페이스(객체 속성 공간들) 에서 변수만 확인해보기
# ['_Private_Var__c', '_Private_Var__z', '_y', 'x']
# private 처리한 애들은 '_클래스명__변수명' 으로 이름이 변경되어 있음!!
getter 메서드
접근자 메서드 : private 변수 값을 반환한다
setter 메서드
설정자 메서드 : private 변수 값을 재설정한다
class Private_Var_2: # Private_Var_2 클래스 만들기
def __init__(self): # 초기화메서드
self.x = 1 # 변수x 는 public
self._y = 2 # 변수y 는 protected
self.__z = 3 # 변수z 는 private
self.__c = 8 # 변수c 는 private
def get_c(self): # getter 메서드
return self.__c # __c의 값을 반환한다.(클래스 내부라서 접근할 수 있다)
def set_c(self, value): # setter 메서드
self.__c = value # __c의 값을 value로 재선언한다.(클래스 내부라서 접근할 수 있다)
a = Private_Var_2() # Private_Var_2 클래스로 a 객체 만들기
print(a.get_c()) # 8 # getter 메서드를 통해 __c 값 출력
a.set_c(88) # setter 메서드를 통해 __c 값을 88로 변경
print(a.get_c()) # 88 # 변경된 c 값 출력해보기
@property 데코레이터
메서드를 객체의 속성처럼 사용할 수 있게 해줌
메서드를 호출하지 않고도 속성에 접근하듯이 값을 가져올 수 있음
@setter 데코레이터
특성 속성에 대한 값을 설정하는 메서드를 정의
속성에 값을 할당할 때 자동으로 이 메서드가 호출됨
class Private_Var_3: # Private_Var_3 클래스 만들기
discount_rate = 0.9 # 클래스 변수
def __init__(self): # 초기화메서드
self.x = 1 # 변수x 는 public
self._y = 2 # 변수y 는 protected
self.__z = 3 # 변수z 는 private
self.__c = 8 # 변수c 는 private
@property
# @property 데코레이터
# 메서드를 객체의 속성처럼 사용할 수 있게 해줌.
# 메서드를 호출하지 않고도 속성에 접근하듯이 값을 가져올 수 있음.
def c(self):
return self.__c * Private_Var_3.discount_rate
# __c에 discaount_rate를 적용한 값을 반환하는 property
# 클래스변수이므로 변수명 앞에 .클래스명 붙여주기
@c.setter
def c(self, value):
# @property_name.setter 데코레이터
# 특정 속성에 대한 값을 설정하는 메서드를 정의
# 이 속성에 값을 할당할 때 자동으로 이 메서드가 호출됨
if value < 0:
raise ValueError('불편하네요')
self.__c = value
# __c의 값을 설정하는 setter. 값이 0보다 작다면 예외 처리
# ValueError '불편하네요' 가 발생한다.
a = Private_Var_3() # Private_Var 클래스로 a 객체 만들기
print(a.c) # 7.2 # property를 통해 __c에 discount 적용한값 출력
a.c = 888888888 # setter를 통해 __c의 값을 888888888로 설정
print(a.c) # 799999999.2 # 변경된 __c의 값에 할인율 적용한값 출력
a.c = 8 # setter로 __C를 8로 설정
print(a.c) # 7.2 # 변경된 __c의 값에 할인율 적용한값 출력
a.c = -8 # ValueError: 불편하네요
# setter를 통해 __c를 변경하려 했지만 0보다 작아서 예외 발생
4. 캡슐화 (Encapsulation)
이렇게 protected, private 변수를 사용해서 데이터를 보호하는 것을 캡슐화 라고 함.
클래스 내부 상태를 보호하고, 객체 간 상호작용을 명확하게 정의할 수 있다.
데이터 변경을 통제함으로써 코드의 유지보수도 용이함!
객체 지향 프로그래밍 개념중 하나.
# 숙제 - 전부 다 주석 다세요
students = [ # students 변수 만들기
{'name': 'won', 'age': 4444, 'grade': 'A'}, # 각 학생의 정보(이름,나이,등급)를
{'name': 'babo', 'age': 444, 'grade': 'B'}, # 딕셔너리 키:밸류 형태로
{'name': 'baboo', 'age': 44, 'grade': 'C'}, # students 리스트에 저장해준다
{'name': 'baboo', 'age': 44, 'grade': 'C'}, # 세번째 네번째는 아예 똑같네 귀찮으셨나
]
def get_student_grade(student): # 등급반환 함수정의! 변수를 받아서
return student['grade'] # 그 변수의 'grade'키에 해당하는 밸류를 반환한다.
print(get_student_grade(students[0])) # student의 0번째 인덱스를 인자로 넣어서 함수 호출
# A # 0번째 딕셔너리의 grade의 밸류는 "A"
class Student: # Student 클래스 만들기
"""
Student Class # 목적과 사용법을 설명하는 글 작성
Date: 2044.04.44 # class 나 class안의 메서드 만들 때 이렇게 설명서를 적어두면
44444444444444444 # 나중에 사람들이 사용할 때 __doc__ 를 통해 글을 읽을 수 있다
하기 싫어 # 오픈소스에 참여하는 멋진 개발자들은 다들 이렇게 살고있다
"""
def __init__(self, name, age, grade): # 초기화 메서드(생성자) : 인스턴스 생성할 때 호출됨. 이름, 나이, 성적을 초기화함.
self.name = name # 인스턴수 변수 name 에 각자의 name 저장
self.age = age # 인스턴수 변수 age 에 각자의 age 저장
self.grade = grade # 인스턴수 변수 grade 에 각자의 grade 저장
def __str__(self): # 문자열표현 메서드! string 약자. 객체를 출력할 때 호출된다. 60번째 line
return f'called __str__ >>> {self.name}, {self.age}' # 비공식적이고 사용자 친화적으로 객체의 정보를 전달할 때 사용함.
def __repr__(self): # 문자열표현 메서드! representation 약자.
return f'called __repr__ >>> {self.name}, {self.age}' # 공식적이고 개발자가 객체를 이해할 수 있는 상세한 정보 제공할 때 사용함.
# instance method # 위에 __ 붙은 메서드는 매직메서드고 얘는 새로 정의하는
def get_grade(self): # 인스턴스 메서드!
print(f'called get_grade >>> {id(self)}') # 함수 호출 시 인스턴스의 id를 출력한 후에
return f'grade >>> {self.grade}' # 인스턴스의 grade를 반환함
student_1 = Student('won', 4444, 'A') # Student 클래스의 인스턴스 생성하기
student_2 = Student('babo', 444, 'B') # init 함수에 name, age, grade 있으니깐
student_3 = Student('baboo', 44, 'C') # 순서대로 인자를 적어서 생성해준다
# id
print(id(student_1)) # 출력 : 2278781762912 # id() : 객체의 고유한 식별자를 반환하는 함수
print(id(student_2)) # 출력 : 2278781762816 # 3개 객체가 서로 개별적이어서 id가 모두 다르다.
print(id(student_3)) # 출력 : 2278781762720 # 만약 두 변수가 동일한 객체를 참조하고 있다면 id가 같음.
print(f'dir func >>> {dir(student_1)}') # dir() : 객체가 가진 모든 속성과 메서드를 보여준다. 이 객체에 어떤 함수를 쓸 수 있는지 알 수 있다.
print(f'dir func >>> {dir(student_2)}') # 원래있는 매직메서드, 새로정의한 인스턴스 메서드(get_grade), 객체가 가진 변수(age, grade, name)까지 다 알려준다.
print('-' * 50) # 매직메서드로 dict, doc, dir, class 도 확인 되었으니 사용할 수 있다!
print()
print(f'__dict__ >>> {student_1.__dict__}') # 출력 : {'name': 'won', 'age': 4444, 'grade': 'A'}
print('-' * 50) # __dict__ : 객체가 가진 속성과 속성값을 딕셔너리 형태로 보여준다.
print()
print(student_1) # 출력 : called __str__ >>> won, 4444
print('-' * 50) # 객체를 출력하면서, 클래스에서 정의했던 __str__ 메서드가 호출된다. student_1의 name, age 변수 출력됨
print() # 만약 __str__, __repr__ 정의를 안했다면 클래스 이름과 메모리 주소를 나타내는 값이 출력됨.
# 이렇게 출력됨 : <__main__.Student object at 0x000001F7F9BF3D60>
# docstring
print(student_1.__doc__) # __doc__ : 객체의 문서화 문자열(Document string)을 보여준디
print(student_2.__doc__) # student_1 과 student_2 객체는 둘 다 크래스 Student 의 인스턴스다.
# 그래서 클래스 Student의 설명('''아까 주석으로 작성한부분''')을 보여준다. 두번보여줌
# docstring 사용하여야 오픈소스 개발잘엉나ㅣ러나ㅣㅇ러닌언아ㅣ
a_list = [] # a_list 변수 선언. 빈리스트
print(type(a_list)) # type() : 이 객체의 자료유형을 보여준다. 출력 : <class 'list'>
print(dir(a_list)) # list가 가진 모든 속성과 메서드 보여주기. append, remove, sort 등등 list에서 쓸 수 있는 함수를 확인할 수 있다.
print(a_list.__doc__) # list 클래스를 만든 사람(귀도반로섬인가)이 작성해둔 설명('''주석''')을 읽어볼 수 있다
print(a_list.append.__doc__) # list 클래스의 메서드인 append 에 대한 설명(귀도반로섬이 적어놓은거)을 볼 수 있다
# Append object to the end of the list.
print(a_list.remove.__doc__) # list 클래스의 메서드인 remove 에 대한 설명(귀도반로섬이 적어놓은거)을 볼 수 있다
# Remove first occurrence of value. Raises ValueError if the value is not present.
# 아하 그래서 remove 함수를 쓰면 리스트 중복요소가 있어도 젤 첫번째 값만 삭제되는거였다!!
# 그리고 없으면 ValueError 가 뜨는거였음 오...
print('-' * 50)
print()
# self
print(f'method call _1 >>> {student_1.get_grade()}') # called get_grade >>> 1598651055456 / method call _1 >>> grade >>> A
# Student 클래스의 get_grade 함수 호출. 호출할 때 student_1 객체를 self로 넣어준다.
print(f'student_1 ID >>> {id(student_1)}') # student_1 ID >>> 1598651055456
# id 함수로 확인해본 결과 위에랑 똑같음. 한 객체의 id 고유값은 변하지 않는다.
print()
print(f'method call _2 >>> {student_2.get_grade()}') # called get_grade >>> 1598651055360 / method call _2 >>> grade >>> B
# 이번에는 student_2 객체를 self로 넣어서 함수 호출.
print(f'student_2 ID >>> {id(student_2)}') # student_2 ID >>> 1598651055360
# 마찬가지로 위에랑 id 똑같다
print('-' * 50)
print()
# __class__
print(student_1.__class__) # sudent_1 의 클래스를 알려줌. 출력 : <class '__main__.Student'>
print(student_2.__class__) # sudent_2 의 클래스를 알려줌. 출력 : <class '__main__.Student'>
print(f'id >>> {id(student_1.__class__)}, {id(student_2.__class__)}') # id >>> 1598617687808, 1598617687808
# 두 객체의 클래스의 id를 각각 출력해본 결과 동일한 것을 확인!
print(f'Class ID - Student >>> {id(Student)}') # Class ID - Student >>> 1598617687808 : 클래스 id를 직접 출력해도 동일한 것을 확인!
print('-' * 50)
print()
#------------------------------------------------------------------------------------------
class Student:
# Class var
student_total_count = 0 # 클래스 변수!! : 생성된 인스턴스의 총 개수를 세기 위한 변수
def __init__(self, name, age, grade):
self.name = name # 맘대로 볼 수 있는 변수
self.age = age
self._grade = grade # Protected 변수 : 접근할 수 잇긴한데 되도록 안하길 권장.
self.__grade = grade # Private 변수 : 외부에서 접근하지 못하도록 캡슐화 하는거.
Student.student_total_count += 1 # 인스턴스 생성할 때마다 호출되는 init 메서드에서 숫자를 하나씩 늘려준다.
# 근데 지역변수가 아니라 클래스변수로 지정했던 변수니까 앞에 Student. 붙여주기!!!
# 안붙였을 때 : UnboundLocalError: local variable 'student_total_count' referenced before assignmen
student_1 = Student('won', 4444, 'A')
student_2 = Student('babo', 444, 'B')
student_2 = Student('baboo', 44, 'C')
student_2 = Student('baboo', 44, 'C')
student_2 = Student('ba', 44, 'C') # Student 클래스의 인스턴스 9개 생성해보기
student_2 = Student('bo', 44, 'C')
student_2 = Student('babooo', 44, 'C')
student_2 = Student('baboooo', 44, 'C')
student_2 = Student('baboooooo', 44, 'C')
print(f'Class var-count student_1 >>> {student_1.student_total_count}') # Class var-count student_1 >>> 9
print(f'Class var-count student_2 >>> {student_2.student_total_count}') # Class var-count student_2 >>> 9
# student_total_count 는 클래스 변수이기 때문에 다른 객체에서도 똑같은 값이 나온다.
print()
print(f'instance var student_1 {student_1.name}') # instance var student_1 won
print(f'instance var student_2 {student_2.name}') # instance var student_2 baboooooo
# name 은 인스턴스 변수이기 때문에 객체마다 각각 본인의 값이 나온다.
print(student_2.name) # baboooooo # student_2의 name 출력
print(student_1._grade) # Protected변수 # A
# print(student_1.__grade) # Private변수 # AttributeError
print(student_1._Student__grade) # Private변수 # A
# 오 캡슐화하면 파이썬이 <변수명>을 <_클래스명__변수명> 으로 바꿔놓는다!
'스쿼드' 카테고리의 다른 글
포맷 (0) | 2024.09.10 |
---|---|
[스쿼드] Matrix 만들기 (0) | 2024.08.05 |
[스쿼드] 계산기 만들기 (0) | 2024.08.02 |
[Python] 파이썬 문법 기본문제 (0) | 2024.07.31 |
[Python] 파이썬 문법 기본문제 (0) | 2024.07.30 |