<코딩도장 복습 통한 새로 이해한 내용 정리 : Unit : 34~38>
- 클래스에 대한 나의 이해 : 정의가 다양해서 이런 저런걸 다 읽어봤지만 이렇게 이해하는게 제일 마음이 편했다.
파이썬에서 쓰이는 모든 것은 다 객체다. 그 객체에는 이름이 있고 객체가 쓰이는 스타일, 속성 같은 것이 있는데 이를 분류해준 것이 클래스다. 클래스에 따라 모든 객체는 역할이 달라지고(간단하게는 int, str부터 더 어려운 객체 클래스까지) 그 객체가 사용될 때 쓰이는 함수, 즉 .~다음에 나오는 것을 '메서드'라고 한다.
self나__init___
에 대해서는 조금 더 이해가 필요할 것 같다. 일단 self가 와야 하는 이유는 인스턴스로 쓰이는 변수 자체이므로 써야 한다 정도만 이해해야겠다.(메모리 상 id값이 같다고 한다.)
(예시)
class Person:
def __init__(self): # 객체 초기화
self.hello = '안녕하세요.'
def greeting(self):
print(self.hello)
james = Person()
james.greeting() # 안녕하세요.
class Person:
def __init__(self, name, age, address):
self.hello = '안녕하세요.'
self.name = name
self.age = age
self.address = address
def greeting(self):
print('{0} 저는 {1}입니다.'.format(self.hello, self.name))
maria = Person('마리아', 20, '서울시 서초구 반포동')
maria.greeting() # 안녕하세요. 저는 마리아입니다.
print('이름:', maria.name) # 마리아
print('나이:', maria.age) # 20
print('주소:', maria.address) # 서울시 서초구 반포동
#인스턴스.속성 통한 접근
class Person:
def __init__(self, name, age, address, wallet):
self.name = name
self.age = age
self.address = address
self.__wallet = wallet # 변수 앞에 __를 붙여서 비공개 속성으로 만듦
def pay(self, amount):
self.__wallet -= amount # 비공개 속성은 클래스 안의 메서드에서만 접근할 수 있음
print('이제 {0}원 남았네요.'.format(self.__wallet))
maria = Person('마리아', 20, '서울시 서초구 반포동', 10000)
maria.pay(3000)
# 이제 7000원 남았네요
클래스 바깥으로 드러내고 싶지 않은 값을 위해 사용. 클래스 밖에서는 바꾸면 안 되는 경우일 때.
class Person:
bag = []
def put_bag(self, stuff):
self.bag.append(stuff)
james = Person()
james.put_bag('책')
maria = Person()
maria.put_bag('열쇠')
print(james.bag)
print(maria.bag)
['책', '열쇠']
['책', '열쇠']
여기서 self가 인스턴스를 모두 지칭하므로 애매한 부분이 있어서 클래스 속성(def~)이 다 똑같이 나옴. 이 때는 self.bag~ 으로 접근하지 말고 클래스 이름으로 접근해서 분리해주기.
bag = []
def put_bag(self, stuff):
Person.bag.append(stuff) # 클래스 이름으로 클래스 속성에 접근
- 클래스 속성: 모든 인스턴스가 공유. 인스턴스 전체가 사용해야 하는 값을 저장할 때 사용
- 인스턴스 속성: 인스턴스별로 독립되어 있음. 각 인스턴스가 값을 따로 저장해야 할 때 사용
class Knight:
__item_limit = 10 # 비공개 클래스 속성
def print_item_limit(self):
print(Knight.__item_limit) # 클래스 안에서만 접근할 수 있음
x = Knight()
x.print_item_limit() # 10
print(Knight.__item_limit) # 클래스 바깥에서는 접근할 수 없음
언제 쓰일까? : 클래스에서 공개하고 싶지 않은 속성이 있다면 비공개 클래스를 사용한다.
class Calc:
@staticmethod
def add(a, b):
print(a + b)
@staticmethod
def mul(a, b):
print(a * b)
Calc.add(10, 20) # 클래스에서 바로 메서드 호출
Calc.mul(10, 20) # 클래스에서 바로 메서드 호출
$ init, self, 인스턴스 등 전혀 하지 않고 만들 수 있음 : 인스턴스 속성에 접근할 수 없으므로 순수함수에 많이 사용.(출력값이 일정해야하는 연산 같은 것)
class Person:
count = 0 # 클래스 속성
def __init__(self):
Person.count += 1 # 인스턴스가 만들어질 때
# 클래스 속성 count에 1을 더함
@classmethod
def print_count(cls):
print('{0}명 생성되었습니다.'.format(cls.count)) # cls로 클래스 속성에 접근
james = Person()
maria = Person()
Person.print_count() # 2명 생성되었습니다.
인스턴스를 건너뛰고 호출할 수 있다는 것은 공통적이지만 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야 할 때 사용. (아직은 낯설다.)
class Date:
@staticmethod
def is_date_valid(date_string):
year, month, day = map(int, date_string.split('-'))
return month <= 12 and day <= 31
if Date.is_date_valid('2000-10-31'):
print('올바른 날짜 형식입니다.')
else:
print('잘못된 날짜 형식입니다.')
문자열이 올바른지 아닌지만 판단.->정적 메서드 이용.
이후 변수 정한 뒤 조건 만들기.
class Time:
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
@classmethod
def from_string(cls, time_string):
hour, minute, second = map(int, time_string.split(':'))
time = cls(hour, minute, second)
return time
@staticmethod
def is_time_valid(time_string):
hour, minute, second = map(int, time_string.split(':'))
return hour <= 24 and minute <= 59 and second <= 60
time_string = input()
if Time.is_time_valid(time_string):
t = Time.from_string(time_string)
print(t.hour, t.minute, t.second)
else:
print('잘못된 시간 형식입니다.')
문제나 답에 대한 이해가 많이 떨어진다. 클래스 메서드는 너무 어렵다.
class Person:
def greeting(self):
print('안녕하세요.')
class Student(Person):
def study(self):
print('공부하기')
james = Student()
james.greeting() # 안녕하세요.: 기반 클래스 Person의 메서드 호출
james.study() # 공부하기: 파생 클래스 Student에 추가한 study 메서드
상속관계 : 위와 같이 동등한 관계
포함관계 : 상속 사용하지 않고 속성에 인스턴스를 넣어 관리하는 형태.
상속받은 클래스가 기반 클래스 속성을 이용하는 방법(super)
class Person:
def __init__(self):
print('Person __init__')
self.hello = '안녕하세요.'
class Student(Person):
def __init__(self):
print('Student __init__')
super().__init__() # super()로 기반 클래스의 __init__ 메서드 호출
self.school = '파이썬 코딩 도장'
james = Student()
print(james.school)
print(james.hello)
class Person:
def greeting(self):
print('안녕하세요.')
class Student(Person):
def greeting(self):
super().greeting() # 기반 클래스의 메서드 호출하여 중복을 줄임
print('저는 파이썬 코딩 도장 학생입니다.')
james = Student()
james.greeting()
from abc import *
class StudentBase(metaclass=ABCMeta):
@abstractmethod
def study(self):
pass
@abstractmethod
def go_to_school(self):
pass
class Student(StudentBase):
def study(self):
print('공부하기')
def go_to_school(self):
print('학교가기')
james = Student()
james.study()
james.go_to_school()
class AdvancedList(list):
def replace(self, old, new):
while old in self:
self[self.index(old)] = new
x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.replace(1, 100)
print(x)
list에서 상속받았으므로 list 상속 받은 뒤 replace를 새로 정의(여기서 replace는 기존에 문자열 메서드가 아니라 내가 새로 정의 해야 할 메서드였음.) 반복문 형태이므로 while을 사용한 뒤 인자는 2개를 받아야 하므로 old, new를 임의로 정한다. 이 때 전 인자가 후 인자로 바뀌어야 하는 식을 index로 찾기를 한 수 바꿔주는 식으로 풀기.
import math
class Point2D:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
length = 0.0
p = [Point2D(), Point2D(), Point2D(), Point2D()]
p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y = map(int, input().split())
---(문제 부분)---
for i in range(len(p)-1):
if i <= len(p)-1:
length += math.sqrt((p[i+1].x - p[i].x)**2 + (p[i+1].y - p[i].y)**2)
----(문제 부분)----
print(length)
두 점이 떨어진 거리만큼 for 반복문으로 선을 이어 더한 뒤 sqrt처리 해주는 것.
try:
x = int(input('나눌 숫자를 입력하세요: '))
y = 10 / x
print(y)
except: # 예외가 발생했을 때 실행됨
print('예외가 발생했습니다.')
x = int(input('나눌 숫자를 입력하세요: '))
y = 10 / x
except ZeroDivisionError: # 숫자를 0으로 나눠서 에러가 발생했을 때 실행됨
print('숫자를 0으로 나눌 수 없습니다.')
else: # try의 코드에서 예외가 발생하지 않았을 때 실행됨
print(y)
finally: # 예외 발생 여부와 상관없이 항상 실행됨
print('코드 실행이 끝났습니다.')
try:
x = int(input('3의 배수를 입력하세요: '))
if x % 3 != 0: # x가 3의 배수가 아니면
raise Exception('3의 배수가 아닙니다.') # 예외를 발생시킴
print(x)
except Exception as e: # 예외가 발생했을 때 실행됨
print('예외가 발생했습니다.', e)
# 혹은
def three_multiple():
x = int(input('3의 배수를 입력하세요: '))
if x % 3 != 0: # x가 3의 배수가 아니면
raise Exception('3의 배수가 아닙니다.') # 예외를 발생시킴
print(x) # 현재 함수 안에는 except가 없으므로
# 예외를 상위 코드 블록으로 넘김
try:
three_multiple()
except Exception as e: # 하위 코드 블록에서 예외가 발생해도 실행됨
print('예외가 발생했습니다.', e)
class NotThreeMultipleError(Exception): # Exception을 상속받아서 새로운 예외를 만듦
def __init__(self):
super().__init__('3의 배수가 아닙니다.')
def three_multiple():
try:
x = int(input('3의 배수를 입력하세요: '))
if x % 3 != 0: # x가 3의 배수가 아니면
raise NotThreeMultipleError # NotThreeMultipleError 예외를 발생시킴
print(x)
except Exception as e:
print('예외가 발생했습니다.', e)
three_multiple()
심사문제 38. def 위치에 주의하고 회문 넣을 시 회문인지 아닌지도 중요하지만 글자수 제한 뒀을 때 1글자면 return하는 것 잊지 않기
class NotPalindromeError(Exception):
def __init__(self):
super().__init__('회문이 아닙니다.')
def palindrome(word):
if len(word) < 2:
return True
if word != word[::-1]:
raise NotPalindromeError
print(word)
try:
word = input()
palindrome(word)
except NotPalindromeError as e:
print(e)
어려웠지만 일단 또 한 번 부분 반복 끝냈다. 다른 것 공부하며 다시 필요하면 찾아보자.