Classes는 데이터와 동작을 결합해요.
Classes는 함께 묶인 데이터와 동작의 복사본, 즉 instances를 만드는 데 사용되며, 이것을 흔히 objects라고 불러요.
objects는 현실 세계의 개체(예: 자동차나 고양이)를 나타낼 수도 있고, 정수, 탈것, 포유류처럼 더 추상적인 개념을 나타낼 수도 있어요.
Classes는 객체 지향 프로그래밍(OOP) 접근법의 핵심이에요. 이 접근법은 프로그래머가 문제를 하나 이상의 객체로 모델링하는 것을 생각하도록 해요. 그 객체들은 서로 상호작용하고, 상태를 유지하며, 데이터를 바탕으로 동작해요.
클래스는 새로운 _객체 유형_의 정의이며, 여기서 새로운 객체의 instances가 만들어져요.
클래스는 흔히 데이터(fields, attributes, properties, data members, variables라고도 해요)를, 그 데이터를 다루는 코드나 함수(methods라고도 해요)와 함께 묶어요.
이런 의미에서 클래스는 설계도 또는 일련의 지침으로, 여기서 비슷한 유형의 객체를 여러 개 만들고 사용할 수 있어요.
복잡한 프로그램에는 클래스가 여러 개 있을 수 있고, 각 클래스는 다양한 종류의 객체를 만들어요.
클래스로부터 객체를 만들고 사용자 정의하는 과정을 instantiation(또는 클래스의 인스턴스를 만드는 것)이라고 해요.
Python에서 클래스 정의는 간단해요:
class MyClass:
# Class body goes here
클래스 필드(프로퍼티, 어트리뷰트, 데이터 멤버, 변수라고도 해요)는 클래스 본문에 추가할 수 있어요.
class MyClass:
number = 5
string = "Hello!"
MyClass의 인스턴스(객체)를 만들어 이름에 할당할 수 있어요:
>>> new_object = MyClass()
# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>
Class attributes는 클래스에서 만들어진 모든 객체(또는 인스턴스)가 공유하며, dot notation을 통해 접근할 수 있어요. 객체 이름 뒤, 속성 이름 앞에 .을 놓는 방식이에요:
>>> new_object = MyClass()
# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5
# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'
# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()
>>> second_new_object
<__main__.MyClass at 0x15ad99970>
# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True
클래스 속성은 다른 어떤 메서드보다도 앞서, 클래스 본문 안에 정의돼요. 클래스 속성은 클래스가 소유하기 때문에, 인스턴스 간에 공유될 수 있어요. 이 속성들은 클래스의 모든 인스턴스가 공유하기 때문에, 클래스에서 직접 값에 접근하고 조작할 수 있어요. 클래스 속성의 값을 바꾸면 _클래스에서 만들어진 모든 객체_의 값이 바뀌어요:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
# Accessing a class attribute from an object.
>>> obj_two.number
5
# Accessing the class attribute from the class itself.
>>> MyClass.number
5
# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27
# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27
>>> obj_two.number
27
항상 데이터가 동기화된 객체를 잔뜩 가지고 있는 것은 별로 유용하지 않아요.
다행히도, 클래스에서 만든 객체는 각자의 instance attributes(또는 인스턴스 프로퍼티, 변수, 필드)로 사용자 정의할 수 있어요.
이름에서 알 수 있듯이, 인스턴스 속성은 각 객체에 고유하며 독립적으로 수정할 수 있어요.
__init__()로 객체 인스턴스화 사용자 정의하기특별한 "던더 메서드"("double underscore method"의 줄임말) __init__()는 클래스 인스턴스를 사용자 정의하는 데 쓰이며, 객체의 인스턴스 속성이나 프로퍼티를 초기화하는 데 사용할 수 있어요.
인스턴스 속성을 초기화하는 역할 때문에 __init__()는 class constructor 또는 initializer라고도 해요.
__init__()는 self라는 필수 매개변수 하나를 받는데, 이는 새로 만들어진 객체를 가리켜요.
그다음 인스턴스 속성이나 프로퍼티를 위한 데이터를 self 매개변수 뒤에 __init__()의 인자로 전달할 수 있어요.
아래에서 MyClass는 이제 location_x와 location_y라는 인스턴스 속성을 가져요.
보시다시피, 두 속성은 __init__()에 전달된 location(튜플) 인자의 첫 번째와 두 번째 인덱스에 할당됐어요.
이제 클래스를 인스턴스화해서 객체를 만들면, 클래스 인스턴스의 location_x와 location_y 속성이 초기화돼요:
class MyClass:
# These are class attributes, variables, or fields.
number = 5
string = "Hello!"
# This is the class "constructor", with a "location" parameter that is a tuple.
def __init__(self, location):
# This is an instance or object property, attribute, or variable.
# Note that we are unpacking the tuple argument into two separate instance variables.
self.location_x = location[0]
self.location_y = location[1]
# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))
# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))
# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1
>>> new_object_two.location_x
-8
위에서 MyClass를 초기화할 때는 인자를 하나만 전달하면 된다는 점에 주목해요. 클래스를 호출하면 Python이 self를 알아서 전달해 줘요.
인스턴스 변수를 만드는 또 다른 방법은 객체를 통해 클래스 변수에 접근해서 다른 값으로 바꾸는 거예요:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'
>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'
>>> obj_one.string
'Hello!'
이제 클래스 변수가 바뀌면 어떻게 되는지 볼까요:
>>> MyClass.string = "World!"
>>> obj_two.string
# obj_two.string has not changed
'Hi!'
>>> obj_one.string
# obj_one.string changed
'World!'
이제 string 속성은 obj_two의 경우 _인스턴스 변수_가 되지만, obj_one에서는 여전히 _클래스 변수_로 남아 있어요.
클래스 내부에서 이렇게 할 수도 있어요:
class Demo:
new_var = 3
def add_two(self):
self.new_var += 2
<object>.add_two()가 호출되고 self.new_var += 2가 실행되는 순간, new_var는 클래스 변수에서 같은 이름의 인스턴스 변수로 바뀌어요.
이는 클래스의 모든 인스턴스가 어떤 속성을 같은 값으로 시작해야 할 때, 초기화 중에 유용할 수 있어요.
하지만 그러면 인스턴스 변수가 클래스 변수를 가려서, 가려진 그 인스턴스에서는 클래스 변수에 접근할 수 없게 돼요.
이런 상황에서는 __init__() 메서드에서 인스턴스 속성을 self.<attribute>로 설정하는 것이 더 안전하고 명확할 수 있어요.
method는 클래스 자체(나중 연습 문제에서 자세히 다룰 클래스 메서드라고 해요)나 클래스의 인스턴스(객체)에 바인딩된 function이에요.
객체나 인스턴스를 다루는 메서드는 self를 첫 번째 매개변수로 두고 정의해야 해요.
그런 다음 나머지 매개변수는 "일반" 함수나 바인딩되지 않은 함수에서처럼 정의하면 돼요.
클래스를 다루는 메서드는 @classmethod 데코레이터를 붙이고 (관례상) cls를 첫 번째 매개변수로 두고 정의해야 해요.
클래스 메서드는 클래스에서 객체를 먼저 만들지 않고 클래스에서 바로 호출해요.
class MyClass:
number = 5
string = "Hello!"
# Class constructor.
def __init__(self, location):
# Instance properties
self.location_x = location[0]
self.location_y = location[1]
# Class method. Uses the @classmethod decorator, and cls as the first parameter.
# Can be called without first making an instance of the class.
@classmethod
def change_string(cls, new_string):
#Class attributes are referred to with cls.
cls.string = new_string
return cls.string
# Instance method. Note "self" as first parameter.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
속성에 접근할 때처럼, 메서드 호출은 객체 이름 뒤, 메서드 이름 앞에 .을 놓는 것만큼 간단해요.
호출된 메서드는 객체의 복사본을 첫 번째 매개변수로 받을 필요가 없어요. Python이 self를 자동으로 채워 줘요:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)
# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)
클래스 속성은 클래스 밖에서 접근하는 것과 같은 방식으로 인스턴스 메서드 안에서도 접근할 수 있어요:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances from within an instance.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5
>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6
pass로 구현 자리 표시하기 또는 스텁 만들기이전의 개념 연습 문제와 실습 문제 스텁에서, 실제 코드 대신 함수 본문 안에 pass 키워드가 쓰인 것을 보셨을 거예요.
pass 키워드는 문법적으로 유효한 자리 표시자예요. 빈 함수나 클래스 정의에 대해 Python이 문법 오류를 일으키지 않도록 막아 줘요.
본질적으로 이것은 Python 인터프리터에게 '걱정 마! 언젠가는 여기에 코드를 넣을 거야, 아직 안 했을 뿐이야'라고 말하는 방법이에요.
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
# This will compile and run without error, but has no current functionality.
def pending_functionality(self):
# Stubbing or place-holding the body of this method.
pass