일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- NLP
- Statistics
- SQL 날짜 데이터
- HackerRank
- 카이제곱분포
- CASE
- 그룹바이
- 자연어 논문
- torch
- sigmoid
- 자연어 논문 리뷰
- 서브쿼리
- leetcode
- 코딩테스트
- Window Function
- SQL코테
- 자연어처리
- airflow
- sql
- 논문리뷰
- 설명의무
- inner join
- 짝수
- update
- t분포
- GRU
- LSTM
- 표준편차
- MySQL
- nlp논문
- Today
- Total
HAZEL
[ Python : Class & Method ] 객체 지향 프로그래밍 , 클래스 , __str__(self) , __repr__(self) , 클래스 변수 , 인스턴스 변수, 클래스 메소드, 인스턴스 메소드, 스테이틱 메소드 본문
[ Python : Class & Method ] 객체 지향 프로그래밍 , 클래스 , __str__(self) , __repr__(self) , 클래스 변수 , 인스턴스 변수, 클래스 메소드, 인스턴스 메소드, 스테이틱 메소드
Rmsid01 2021. 5. 23. 17:55Chapter 01 : 객체 지향 프로그래밍
: 객체 지향 프로그래밍 ( oop ) 는 코드의 재사용 ,코드 중복 방지 등의 장점이 있다.
1. 객체지향적이지 않은, 날것으로 코딩을 하기
# 리스트 구조
student_names_list = ['Kim','Lee','Park']
student_numbers_list = [1,2,3]
student_grades_list = [1,2,4]
student_details_list = [
{'gender':'Male', 'score1':95 , 'score2' : 88},
{'gender':'FeMale', 'score1':77 , 'score2' : 88},
{'gender':'Male', 'score1':95 , 'score2' : 88},
]
# 삭제
del student_names_list[1]
del student_numbers_list[1]
del student_grades_list[1]
del student_details_list[1]
print(student_names_list, student_numbers_list, student_grades_list) # ['Kim', 'Park'] [1, 3] [1, 4]
print(student_details_list)
#[{'gender': 'Male', 'score1': 95, 'score2': 88}, {'gender': 'Male', 'score1': 95, 'score2': 88}]
: 위에처럼 클래스를 만들지 않고, 코드를 짜게 되면 같은 코드를 반복해서 쳐야하는 번거로움이 있다.
이러한 문제를 해결하기 위해서 등장한 것이 '객체지향' 이다
2. 객체지향적인 코드 - 클래스 구조
class Student(): # 클래스
def __init__(self, name, number, grade,details): # 생성자
self._name = name
self._number = number
self._grade = grade
self._details = details
# 우선순위는 str - > repr 이며, 둘다 없으면 그냥 객체를 반환
def __str__(self):
return 'str : {}'.format(self._name)
def __repr__(self):
return 'repr : {} - {}'.format(self._name , self._number)
student1 = Student( 'Kim' ,1, 1 , {'gender':'Male', 'score1':95, 'score2' : 30})
student2 = Student( 'Lee' ,2, 1 , {'gender':'FeMale', 'score1':95, 'score2' : 30})
student3 = Student( 'Park' ,3, 1 , {'gender':'Male', 'score1':95, 'score2' : 30})
print(student1.__dict__)
# student1 에 어떤값이 들어갔는지 다 확인할 수 있다. - 이건, 파이썬이 만들어졌을 때부터 이렇게 된거다!
print(student1, student2, student3) # str : Kim str : Lee str : Park
3. __str__(self) , __repr__(self)
: 이 두 메서드는 객체를 사용자가 이해할 수 있는 문자열로 반환하도록 해주는 함수이다.
위의 코드를 보면
print(student1 , student2, student3) 에 대해서, 각 값이 들어있는 메모리의 수치가 아니라, __str__ 함수에 적혀있는 문자열이 반환됨을 확인 할 수 있다. ( ex , str : Kim str : Lee str : Park )
만약, __str__ 함수나, __repr__ 함수가 선언되지 않는다면,
print(student1) 을 하면, <__main__.Student object at 0x10a71f5e0> 가 반환된다.
for x in student_list:
print(repr(x)) # print 에 repr 이라는 메소드가 있음
print(x)
#str : Kim # str 함수가 있기 때문에, print() 해줬을때, lee 가 나오게된다. str 함수가 없다면, 그냥
# <__main__.Student object at 0x10f7635e0> - 가 나오게 된다.
# str : Lee
# str : Park
print(x) 를 해주었을 때, str 가 우선순위이며, 그 다음 repr 이다.
repr 는 print(repr(x)) 를 입력하여 직접 출력해줄 수 도 있다.
4. 클래스 변수와 인스턴스 변수
: 아래의 4, 5, 번에 대한 설명을 쉽게 이해하기 위한 class 코드
# 클래스 재 선언
class Student():
"""
Student Class
Author : LEE
Data : 2021.05.21
"""
# 클래스 변수를 선언
student_count = 0
def __init__(self, name , number, grade, details , email = None):
# 인스턴스 변수들
self._name = name
self._number = number
self._grade = grade
self._details = details
self._email = email
# 객체가 선언될때마다 cnt 가 하나씩 증가하게 된다.
Student.student_count += 1
# 메소드 들 ..
def __str__(self):
return 'str {}'.format(self._name)
def __repr__(self):
return 'repr {}'.format(self._name)
def detail_info(self):
print('Current ID = {}'.format(id(self))) # 고유의 id 값이 출력됨
print('Studnet Detail Info : {} {} {}'.format(self._name, self._email, self._details))
def __del__(self): # 오버라이딩
Student.student_count -= 1
1 ) 클래스 변수
: self 가 없고, 메서드 밖에서 범위를 가지는 함수를 클래스 변수라고 한다.
ex, 위의 코드에서는 student_count 가 클래스 변수이다.
- 클래스 변수에 접근할때는 클래스이름 . 변수이름 을 적어야 한다.
Student.student_count += 1
2 ) 인스턴스 변수
: self 가 있고, 메서드 안에서 범윌르 가지는 함수를 인스턴스 변수 라고 한다.
def __init__(self, name , number, grade, details , email = None):
# 인스턴스 변수들
self._name = name
self._number = number
self._grade = grade
self._details = details
self._email = email
3 ) 인스턴스 변수와 클래스 변수 접근
- 인스턴스 변수 출력
print(student1._name , student2._name)
- 클래스 변수 출력
print(student1.student_count) # 변수로 접근
print(Student.student_count) # 클래스로 접근
: 사실, student1 에는 student_count 인스턴스가 존재하지 않는다.
그러나, 파이썬은 인스턴스가 없다면 상위 클래스 변수나 부모 클래스 변수로 찾는다.
5. 클래스 설명
1 ) id 값 찾기
: 변수를 선언하게 되면, 각 변수에는 하나의 메모리 를 차지하게 된다. 이때, 그 메모리의 주소값을 id(x) 를 통해서 찾을 수 있다.
student1 = Student('cho', 2, 3, {'gender':'M', 'score1':44, 'score2': 80})
student2 = Student('cho', 4, 5, {'gender':'F', 'score1':44, 'score2': 80}, 'lee@naver.com')
# id 값이 다르다 != 가지고 있는 값이 다르다. id 값은 메모리에 저장된 장소라고 생각하면 된다.
print(id(student1)) #4553099440
print(id(student2)) # 4553099248
즉, 두개의 변수의 id 값을 출력해보면 다른 장소에 저장됨을 볼 수 있다.
만약, 표면적인 값이 같더라고 저장된 공간의 주소는 다르기 때문에 id 의 값은 다르게 된다.
2 ) id 값과 표면적인 값 비교
print(id(student1) == id(student2)) # False
print(student1 is student2) # 이건 id 를 비교하는 것 # False
print(student1._name == student2._name) # 이건 값을 비교하는 것 # True
: is 를 사용하면, 각 객체의 주소를 비교할 수 있다.
3) dir 함수와 __dict__ 비교
: 현업에서는 dict 로 보고 없으면 dir 을 본다고 한다 . dir 이 더 자세하나, 출력의 양이 많다.
- dir 함수
: 변수가 가지고 있는 속성을 다 보여준다.
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__
: 인스턴스 속성 값도 가지고 있음.
print(student1.__dict__)
# {'_name': 'cho', '_number': 2, '_grade': 3,
# '_details': {'gender': 'M', 'score1': 44, 'score2': 80}, '_email': None}
4) __doc__
: Doctstring. 클래스에 대한 주석을 볼 수 있다.
print(Student.__doc__)
# Student Class
# Author : LEE
# Data : 2021.05.21
5 ) 메소드 함수 사용
class Student():
"""
Student Class
Author : LEE
Data : 2021.05.21
"""
def __init__(self, name , number, grade, details , email = None):
self._name = name
self._number = number
self._grade = grade
self._details = details
self._email = email
def detail_info(self):
print('Current ID = {}'.format(id(self))) # 고유의 id 값이 출력됨
print('Studnet Detail Info : {} {} {}'.format(self._name, self._email, self._details))
student1 = Student('cho', 2, 3, {'gender':'M', 'score1':44, 'score2': 80})
- 실행
student1.detail_info()
- 클래스로 직접 접근해도, 호출이 가능하다.
Student.detail_info(student1)
# 에러
# Student.detail_info()
# TypeError: detail_info() missing 1 required positional argument: 'self'
6. 인스턴스 메소드
: self 를 통해서 어떤것을 return 해주는 함수를 인스턴스 메소드라고 함
class Student(object):
...
# 클래스 변수
tuition_per = 1.0
# 인스턴스 메소드
def get_fee(self): # 얼만큼 등록금을 내는가 ?
return 'Before Tuition -> id : {} , fee : {}'.format(self._id, self._tuition)
# 인스턴스 메서드
def get_fee_culc(self):
return 'After Tuition -> id : {} , fee : {}'.format(self._id, self._tuition * Student.tuition_per)
! 클래스 메서드를 쓰기 전의 코드
print(student1.get_fee()) # 학비 인상 전 - 정보
Student.tuition_per = 1.2 # 학비 인상 률
print(student2.get_fee_culc()) # 학비 인상 후 - 정보
: 값은 바뀌게 되지만, 위에 코드처럼 직접 값에 접근해서 바꾸는것은 좋지 않다.
: Student.tuituion_per 은 클래스 변수로, 모든 변수가 바라보고있는 변수이다.
따라서, 이 값이 쉽게 바뀌게 되며 좋지 않다. 즉, 보호되어야 하고 캡슐화 되어야한다.
-> 클래스 변수를 캡슐화 하기 위해서 아래의 클래스 메소드를 사용하게 된다.
7. 클래스 메소드
: 아래와 같은 클래스 메소드 아래 로직도 넣을 수 있다.
: 혹은, student_construct () 처럼 인스턴스 변수들을 구성해줄 수 있다.
: 클래스 메소드를 이용하여, 파이써닉 한 코드를 작성할 수 있다. ( 보통 잘만들어진 코드들은 클래스 메서드를 선언한다고 한다. )
class Student(object):
# Class Variable
tuition_per = 1.0
...
# 클래스 메서드
@classmethod # 데코레이터
def raise_fee(cls , per): # cls 는 클래스가 넘어옴을 의미함 - 여기서는 Student 와 동일
if per <= 1:
print('Please Enter 1 or More')
return
cls.tuition_per = per # Student.tuition_per = per 도 같은 의
print('Succed ! tuition increased ! ')
# 클래스 매서드
@classmethod
def student_construct(cls, id, first_name, last_name, email , grade, tuition , gpa ):
return cls(id, first_name, last_name, email , grade, tuition * cls.tuition_per, gpa)
! 클래스 메서드를 사용한 코드
print(student1.get_fee()) # 학비 인상 전 - 정보
Student.raise_fee(1.2) # 학비 인상 률
print(student2.get_fee_culc()) # 학비 인상 후 - 정보
- 클래스 메소드 인스턴스 생성
: 아래처럼 클래스 메소드를 사용해서 변수를 생성하는 것이 분명해서 더 좋은 코드가 된다.
student3 = Student.student_construct(3, 'Park' ,'minji', 'st@naver', '3', 550, 4.0 )
8. 스테틱 메소드
! 스테틱 메소드를 사용하지 않는 코드
: 이렇게 코드를 class 에 묶지 않고 따로 함수를 생성할 수는 있지만, 같은 내용인데 따로있으면 함수를 고칠때 번거로울 수 있다.
# 장학금 혜택 여부 ( 스테틱 메소드 미사용 )
def is_scholarship(inst):
if inst._gpa >= 4.0 :
return '{} is a scholarship recipient.'.format(inst._last_name)
return 'Sorry , Not a scholarship recipient'
print(is_scholarship(student1)) # aram is a scholarship recipient.
! 스테틱 메소드를 사용한 코드
: 클래스도, 인스턴스랑도 관련이 없을 경우에 사용
: 스태틱 메소드를 사용하게 되면 접근하는 방법이 유연해진다. ( 2가지 방법 )
: 스태틱 메소드는 cls, self 로 넘겨받지 않는다. cls, self 상관없이 넘겨받는 인자로만 받는다.
< 요즘은 이것이 별로 효율성이 없다!? 라는 의견이 있기도 하다 >
class Student(object):
...
#스테이틱 메서드
@staticmethod
def is_scholarship_st(inst):
if inst._gpa >= 4.0:
return '{} is a scholarship recipient.'.format(inst._last_name)
return 'Sorry , Not a scholarship recipient'
# 1 . 클래스로 접근 가능
print(Student.is_scholarship_st(student1))
# 2. 인스턴스로도 접근 가능
print(student1.is_scholarship_st(student1))
---
: 패스트 캠퍼스 강의를 공부하고 정리한 내용입니다.
'PROGRAMMING > Python' 카테고리의 다른 글
[ Python : Sequence ] List, Comprehension( 다중 if 문 , filter, map 사용 ), (0) | 2022.10.05 |
---|---|
[ Python : Data Model ] 네임드 튜플, magic 메소드, 오버로딩, 오버라이딩 (0) | 2021.08.09 |