클래스는 제품의 설계도
객체 : 설계도로 만든 제품
생성자 : 객체를 만들 때 가장 먼저 실행되는 함수
class 클래스 이름:
def 메서드 이름(self):
명령블록
self : 객체 자기 자신
객체 = 클래스 이름()
객체.메서드 : .은 "~~의"
속성 추가하기
class Monster:
def __init__(self,name):
self.name = name
#이때 self.name이 monster class의 속성이 된다
def say(self):
print(f"나는 {self.name}")
shark = Monster("상어")
#name변수에 상어가 들어가고, self에는 shark가 들어간다.
=================================================
클래스(Class)란 무엇인가
클래스는 자료형을 위한 일종의 템플릿이라고 생각하면 된다. 클래스 안에는 다양한 유형의 정보가 담겨 있고, 우리가 자료형과 어떻게 상호작용할 것인지 적혀 있다.
class 정의하기
class TestClass:
pass
클래스를 정의하고 나면 그걸 불러와서 사용하는 법을 알아야겠지. 클래스를 이용해 인스턴스(instance)를 만들어주면 된다. “임시로 어떤 템플릿을 불러와서 그걸 다른 이름의 객체로 저장한다”
test_instance = TestClass()
=> 클래스 이름에 괄호를 추가하여 인스턴스를 만들고, 그걸 변수 test_instance에 할당하는 방식
객체 지향 프로그래밍 (Object-Oriented Programming)
클래스 인스턴스는 객체(object)라고도 하며, 이렇게 클래스를 정의하고 객체를 만드는 패턴을 객체 지향 프로그래밍(OOP)이라고 한다.
인스턴스를 불러온다는 건 클래스를 가져와 객체로 바꿔준다는 건데, type() 함수를 사용하는 건 그 반대라고 생각하면 된다. 객체의 type을 확인해보면 해당 객체가 어떤 클래스의 인스턴스인지를 확인할 수 있다.
클래스를 정의할 때 그 안에서 변수를 정의하면 모든 인스턴스에서 동일한 데이터를 사용할 수 있다. 이를 클래스 변수라고 부르는데, 이렇게 정의된 클래스 변수는 object.variable 구문을 사용하여 접근 가능
class Musician:
title = "Rockstar"
drummer = Musician()
guitarist = Musician()
print(drummer.title)
print(guitarist .title)
메서드는 클래스 안에서 정의된 함수
일반적인 함수를 정의할 때와 차이 : 메서드를 정의할 때는 첫 번째 인수를 항상 self로 지정해야 함
class Musician:
title = "Rockstar"
def explanation(self):
print("I am a {}!".format(self.title))
drummer = Musician()
drummer.explanation()
#I am a Rockstar!
단순히 클래스 변수 title을 사용해서 문자열을 출력하는 메서드를 정의해하고, 그걸 불러와서 사용했다.
메서드를 작성할 때 다른 인수는 필요 없었기 때문에 self만 써주었고, 함수 안에서 클래스 변수를 사용할 때는 self.title과 같은 형식으로 불러왔다.
class Circle():
pi = 3.14
def area(self, radius):
return self.pi * radius ** 2
circle = Circle()
pizza_area = circle.area(6)
table_area = circle.area(18)
Circle이라는 클래스에서 π(pi) 값은 3.14로 넣어주고, 원의 넓이 구하는 공식을 area라는 메서드로 정의했다. 원의 넓이는 π * 반지름²이다. 그리고 메서드를 정의할 때 반지름을 인수로 받아야 하기 때문에 area의 인수로 self와 radius를 넣어줬다. (메서드의 첫 번째 인수는 언제나 self다.)
클래스를 호출할 때 자동으로 어떤 함수를 실행하거나 값을 호출하고 싶다면 생성자(Constructor)라는 걸 정의하면 된다.
메서드 정의할 때와 똑같긴 한데 메서드 이름으로 init을 사용하면 된다.
class Shouter:
def __init__(self):
print("HELLO?!")
shout = Shouter()
Shouter라는 클래스를 객체로 불러올 때마다 “HELLO?!”라는 문자열이 즉시 출력된다.
물론 클래스를 호출할 때 애초에 다른 인수(매개변수)를 받는 방식으로 정의하는 것도 가능하다. 이렇게
class Circle:
pi = 3.14
def __init__(self, radius):
print("New circle with radius: {}".format(radius))
table = Circle(18)
지금까지 객체가 클래스의 인스턴스라는 것을 배웠지만, 각 객체가 메서드와 클래스 변수만으로 이루어져 있다면 객체들을 구별해야 할 필요가 있을까?
객체를 구별해서 인스턴스를 생성하는 이유는 각 인스턴스가 다른 종류의 데이터, 즉 인스턴스 변수를 보유할 수 있기 때문이다.
이렇게 각 객체가 보유한 데이터인 인스턴스 변수는 해당 클래스의 모든 인스턴스가 공유하는 게 아니다. (이게 클래스 변수와의 가장 큰 차이점이다.)
예를 보자. 일단 빈 클래스를 하나 정의해놓고, 두 개의 인스턴스(객체)를 불러오자.
class FakeDict:
pass
fake_dict1 = FakeDict()
fake_dict2 = FakeDict()
그리고 각 객체에 fake_key라는 인스턴스 변수로 각각 다른 값을 넣어주면,
fake_dict1.fake_key = "This works!"
fake_dict2.fake_key = "This too!"
이걸 별도로 사용할 수 있다.
working_string = "{} {}".format(fake_dict1.fake_key, fake_dict2.fake_key)
print(working_string)
# "This works! This too!"
어려운 게 아니다. 그냥 그동안 사용했던 변수의 개념이라고 생각하면 편하다.
왜 굳이 인스턴스 변수를 사용할까? 그냥 변수로 써도 문제 없는데?
인스턴스를 생성할 때 작동하는 생성자(constructor)를 활용해서 인스턴스 변수를 생성하고 관리하면 너무나 편리하기 때문이다.
class AutoEmail:
def __init__(self, name):
self.name = name
mail_to_park = AutoEmail("PARK")
mail_to_kim = AutoEmail("KIM")
print(mail_to_park.name)
# "PARK"
print(mail_to_kim.name)
# "KIM"
인스턴스를 만들 때 애초에 이름을 넣어주었기 때문에 각 인스턴스의 name에서 그 이름을 그대로 가지고 있게 된다.
그러면 이걸 활용해서 메서드를 작성할 수도 있다.
class AutoEmail:
intro = "안녕하세요"
def __init__(self, name):
self.name = name
def say_hello(self):
return "{intro} {name} 님".format(intro=self.intro, name=self.name)
mail_to_park = AutoEmail("PARK")
mail_to_kim = AutoEmail("KIM")
print(mail_to_park.say_hello())
# "안녕하세요 PARK 님"
print(mail_to_kim.say_hello())
# "안녕하세요 KIM 님"
클래스 변수와 인스턴스 변수를 모두 자유롭게 사용할 수 있게 되는 거다.
이게 바로 객체 지향 프로그램 작성의 장점일 거다. 클래스를 작성하여 필요한 데이터를 구조화하고, 해당 데이터와 의미있는 방식으로 상호 작용하는 메서드를 작성하는 것. 구조를 잘 짜는 게 중요하다.
print(dir([]))
dir()은 어떤 객체를 인자로 넣어주면 해당 객체가 어떤 메서드를 가지고 있는지 돌려준다.
우리가 파이썬에서 다루는 모든 자료형은 모두 int, float, str, list, dict와 같은 이름을 가진 클래스의 인스턴스인 셈이다.