day 9 두 점 사이의 거리 구하기
두 점 사이의 거리 구하기
클래스로 점 구현하기
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point2D(x=30, y=20) # 점1
p2 = Point2D(x=60, y=50) # 점2
print('p1: {} {}'.format(p1.x, p1.y)) # 30 20
print('p2: {} {}'.format(p2.x, p2.y)) # 60 50
p1: 30 20
p2: 60 50
# 그럼 √(루트)는 어떻게 구현해야 할까요? 이때는 math 모듈의 sqrt 함수를 사용하면 편리합니다. sqrt는 제곱근을 뜻하는 square root에서 따왔습니다.
# math.sqrt(값)
# n 제곱근을 반환, 값이 음수이면 에러 발생
# 이제 sqrt 함수까지 사용해서 p1과 p2의 거리를 구해보겠습니다.
피타고라스의 정리로 두 점의 거리 구하기
import math
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point2D(x=30, y=20) # 점1
p2 = Point2D(x=60, y=50) # 점2
a = p2.x - p1.x # 선 a의 길이
b = p2.y - p1.y # 선 b의 길이
c = math.sqrt((a * a) + (b * b)) # (a * a) + (b * b)의 제곱근을 구함
# c = math.sqrt((a ** 2) + (b ** 2))
# c = math.sqrt(math.pow(a, 2) + math.pow(b, 2))
print(c) # 42.42640687119285
42.42640687119285
참고 | 절댓값 함수
# 내장 함수 abs 또는 math 모듈의 fabs 함수를 사용하면 양수 또는 음수를 절댓값(absolute value)으로 만들 수 있습니다.
# abs(값)
# 정수는 절댓값을 정수로 반환, 실수는 절댓값을 실수로 반환
# math.fabs(값)
# 절댓값을 실수로 반환
참고 | namedtuple 사용하기
# 파이썬에서는 각 요소에 이름을 지정해 줄 수 있는 튜플인 namedtuple을 제공합니다( collections 모듈). namedtuple은 자료형 이름과 요소의 이름을 지정하면 클래스를 생성해줍니다. 여기서 자료형 이름은 문자열, 요소의 이름은 문자열 리스트로 넣어줍니다.
# 클래스 = collections.namedtuple('자료형이름', ['요소이름1', '요소이름2'])
# namedtuple로 생성한 클래스는 값을 넣어서 인스턴스를 만들 수 있으며 인스턴스.요소이름 또는 인스턴스[인덱스] 형식으로 요소에 접근할 수 있습니다.
# 인스턴스 = 클래스(값1, 값2)
# 인스턴스 = 클래스(요소이름1=값1, 요소이름2=값2)
# 인스턴스.요소이름1
# 인스턴스[인덱스]
# 다음은 namedtuple을 사용하여 점을 표현한 뒤 두 점의 거리를 구합니다.
import math
import collections
Point2D = collections.namedtuple('Point2D', ['x', 'y']) # namedtuple로 점 표현
p1 = Point2D(x=30, y=20) # 점1
p2 = Point2D(x=60, y=50) # 점2
a = p1.x - p2.x # 선 a의 길이
b = p1.y - p2.y # 선 b의 길이
c = math.sqrt((a * a) + (b * b))
print(c) # 42.42640687119285
42.42640687119285
사각형의 넓이 구하기
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
rect = Rectangle(x1=20, y1=20, x2=40, y2=30)
width = abs(rect.x2 - rect.x1)
height = abs(rect.y2 - rect.y1)
area = width * height
print(area)
200
# 표준 입력으로 x, y 좌표 4개가 입력되어
# Point2D 클래스의 인스턴스 리스트에 저장됩니다.
# 여기서 점 4개는 첫 번째 점부터 마지막 점까지 순서대로 이어져 있습니다.
# 다음 소스 코드를 완성하여
# 첫 번째 점부터 마지막 점까지 연결된 선의 길이가 출력되게 만드세요.
import math
import collections
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(1,len(p)):
a = p[i-1].x - p[i].x # 선 a의 길이
b = p[i-1].y - p[i].y # 선 b의 길이
length += math.sqrt((a * a) + (b * b))
print(length)
10 10 20 20 30 30 40 40
42.42640687119285
요약
클래스
클래스는 객체를 표현하기 위한 문법입니다. 클래스는 class에 클래스 이름을 지정하고 :(콜론)을 붙인 뒤 다음 줄부터 def로 메서드를 작성합니다. 메서드는 클래스 안에 들어있는 함수를 뜻합니다.
class 클래스이름: # 클래스 만들기
def 메서드(self): # 메서드 만들기
코드
클래스는 ()(괄호)를 붙인 뒤 변수에 할당하여 인스턴스(객체)를 만듭니다. 그리고 인스턴스 뒤에 .(점)을 붙여서 메서드를 호출합니다.
인스턴스 = 클래스() # 인스턴스(객체) 만들기
인스턴스.메서드() # 인스턴스로 메서드 호출
클래스의 속성
클래스에 인스턴스 속성을 만들 때는 __init__ 메서드 안에서 self.속성에 값을 할당해줍니다. 그리고 인스턴스 속성에 접근할 때는 메서드 안에서 self 뒤에 .(점)을 붙여서 접근하거나, 인스턴스 뒤에 .을 붙여서 접근합니다.
class 클래스이름:
def __init__(self):
self.속성 = 값 # 인스턴스 속성 만들기
def 메서드(self):
self.속성 # self 뒤에 .을 붙여서 인스턴스 속성에 접근
인스턴스 = 클래스() # 인스턴스(객체) 만들기
인스턴스.속성 # 인스턴스 속성에 접근
클래스에 바로 속성을 만들면 클래스 속성이 되며 해당 클래스로 만든 모든 인스턴스가 값을 공유합니다. 클래스 속성은 self 또는 클래스 뒤에 .(점)을 붙여서 접근합니다.
class 클래스이름:
속성 = 값 # 클래스 속성 만들기
def 메서드(self):
self.속성 # self 뒤에 .을 붙여서 클래스 속성에 접근
클래스.속성 # 클래스 뒤에 .을 붙여서 클래스 속성에 접근
클래스.속성 # 클래스 속성에 접근
속성을 만들 때 __속성과 같이 __(밑줄 두 개)로 시작하면 비공개 속성이 됩니다. 비공개 속성은 클래스 안에서만 접근할 수 있고, 클래스 바깥에서는 접근할 수 없습니다(비공개 메서드도 같은 방식).
class 클래스이름:
__속성 = 값 # 비공개 클래스 속성
def __init__(self):
self.__속성 = 값 # 비공개 인스턴스 속성
정적 메서드와 클래스 메서드
정적 메서드와 클래스 메서드는 인스턴스를 통하지 않고 클래스에서 바로 호출할 수 있는 메서드입니다. 정적 메서드는 메서드 위에 @staticmethod를 붙이며 매개변수에 self를 지정하지 않습니다.
class 클래스이름:
@staticmethod # 정적 메서드 만들기
def 메서드(매개변수1, 매개변수2):
코드
정적 메서드는 self를 받지 않으므로 인스턴스 속성에 접근할 수 없습니다. 따라서 정적 메서드는 인스턴스 속성, 인스턴스 메서드가 필요 없을 때 사용합니다.
클래스 메서드는 메서드 위에 @classmethod를 붙이며 매개변수에 cls를 지정합니다.
class 클래스이름:
@classmethod # 클래스 메서드 만들기
def 메서드(cls, 매개변수1, 매개변수2):
코드
클래스 메서드는 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야 할 때 사용합니다.
클래스 상속
클래스 상속은 물려받은 기능을 유지한채로 다른 기능을 추가할 때 사용합니다. 기능을 물려주는 클래스를 기반 클래스, 상속을 받아 새롭게 만드는 클래스를 파생 클래스라고 합니다.
상속은 클래스를 만들 때 ( )(괄호)를 붙이고 괄호 안에 기반 클래스 이름을 넣어줍니다.
class 기반클래스이름:
코드
class 파생클래스이름(기반클래스이름): # 기반 클래스를 상속받음
코드
기반 클래스의 속성에 접근하거나 메서드를 호출할 때는 super() 뒤에 .을 붙여서 사용합니다. 또는, super(파생클래스, self) 형식으로 사용할 수도 있습니다.
class 기반클래스이름:
def \__init__(self):
self.속성 = 값
class 파생클래스이름(기반클래스이름):
def \__init__(self):
super().\__init__() # super()로 기반 클래스의 메서드 호출
super().속성 # super()로 기반 클래스의 속성에 접근
super(파생클래스, self).속성 # super에 파생 클래스와 self를 넣는 형식
상속 관계와 포함 관계
상속은 학생과 사람처럼 명확하게 같은 종류이며 동등한 관계일 때 사용하며 is-a 관계라고 부릅니다. 포함은 사람과 사람 목록처럼 동등한 관계가 아니라 포함 관계일 때 사용하며 has-a 관계라고 부릅니다.
메서드 오버라이딩
파생 클래스에서 기반 클래스의 메서드를 새로 정의하는 것을 메서드 오버라이딩이라고 합니다. 메서드 오버라이딩은 파생 클래스에서 메서드를 정의할 때 기반 클래스의 메서드 이름과 똑같이 만들어줍니다.
class Person:
def greeting(self):
pass
class Student(Person):
def greeting(self): # 메서드 오버라이딩
super().greeting() # super()로 기반 클래스의 메서드 호출
james = Student()
james.greeting() # Student의 greeting 메서드가 호출 됨
메서드 오버라이딩은 원래 기능을 유지하면서 새로운 기능을 덧붙일 때, 프로그램에서 어떤 기능이 같은 메서드 이름으로 계속 사용되어야 할 때 활용합니다.
다중 상속
다중 상속은 여러 기반 클래스로부터 상속을 받아서 파생 클래스를 만드는 방법입니다. 클래스를 만들 때 ( )(괄호) 안에 클래스 이름을 ,(콤마)로 구분해서 넣어줍니다.
class 기반클래스이름1:
코드
class 기반클래스이름2:
코드
class 파생클래스이름(기반클래스이름1, 기반클래스이름2): # 다중 상속 사용하기
코드
추상 클래스
추상 클래스는 메서드 목록만 가진 클래스이며 상속받는 클래스에서 메서드 구현을 강제하기 위해 사용합니다. 추상 클래스를 사용하려면 import로 abc 모듈을 가져온 뒤 클래스의 ( )(괄호) 안에 metaclass=ABCMeta를 지정하고, 메서드 위에 @abstractmethod를 붙여줍니다.
from abc import *
class 추상클래스이름(metaclass=ABCMeta): # 추상 클래스 만들기
@abstractmethod
def 메서드이름(self):
코드
Leave a comment