참고 1 참고 2
클래스(Class)와 객체(Object)
- 클래스: 붕어빵 틀
- 객체: 붕어빵 틀로 만든 붕어빵
- 객체마다 고유한 성격을 가짐
- 동일한 클래스로 만든 객체들은 서로 영향을 전혀 주지 않는다는 의미
- 클래스 사용 목적
- 변수와 함수를 묶어 하나의 새로운 객제(타입) 만듦
- '클래스를 정의한다'의 의미
- 새로운 데이터 타입을 정의한 것
- 이를 실제로 사용하려면 인스턴스를 생성해야 함
객체와 인스턴스의 차이
a = Calc()
- 어떤 것이 주체인가에 따라 다름
- a는 객체이다 (O)
- a 객체는 Calc의 인스턴스이다(O)
- a는 객체이고 Calc의 인스턴스이다(O)
- a는 인스턴스이다(X)
- Calc라는 클래스의 인스턴스가 메모리의 한 위치에 생성되고, a라는 변수가 이를 바인딩하게 됨
클래스의 구조
class Calc:
def set(self, n1, n2):
self.n1 = n1
self.n2 = n2
def 함수명(매개변수):
수행할 문장
- 클래스 안에 만들어진 함수는 메서드(Method)라 부름
메서드(Method)
- 위의 set 메서드를 보면 self, n1, n2를 입력 값으로 받음
- 첫 번째 매개변수인 self는 특별한 의미가 있음(함수와의 차이점)
- 메서드의 첫 번째 매개변수는 관례적으로 self를 사용(다른 단어여도 된다고 함)
a = Calc()
a.set(10,5)
- 객체를 통해 메서드를 호출하려면
.(도트 연산자; dot operator)를 사용하여 호출
- 자세히 보면 호출했을 때 self를 입력으로 받지 않았음
a.set(10,5)로 호출했르 때 self 매개변수는 호출한 객체 a로 자동으로 전달되기 때문
- self는 객체의 인스턴스 그 자체를 말함 (즉, 객체 자기 자신을 참조하는 매개변수인 셈)
- 객체지향언어는 모두 이걸 메서드에 안 보이게 전달하지만, 파이썬은 클래스의 메서드를 정의할 때 self를 명시하고 메서드를 불러올 때 self를 자동으로 전달함
- self를 사용하는 것으로 클래스 내에 정의한 멤버에 접근 가능
a.n1 = 10
a.n2 = 5
- 객체 변수
- 객체에 생성되는 객체만의 변수
- set 메서드가 실행되면 a 객체에 객체변수 n1과 n2가 생성되고 10, 5의 값이 저장됨
※ '동일한 클래스로 만든 객체들은 서로 영향을 전혀 주지 않는다.'에 대하여:
a=Calc()
b=Calc()
a=set(10,5)
b=set(6,3)
- 동일한 클래스로 만든 a와 b에서 돌일한 메서드를 이용했을 때 각 객체가 서로 영향을 끼치지 않음
self?
- Foo 클래스를 만들고 첫 번째 인자가 self가 아닌 메서드와 self인 메서드 비교해보기
- 클래스를 만들 때 func1() 메서드의 첫 번째 인자가 self가 아님에도 에러가 발생하지 않는다
>>> class Foo:
def func1():
print("function 1")
def func2(self):
print("function 2")
- 해당 클래스의 인스턴스를 생성하고 생성된 인스턴스를 통해 인스턴스 메서드를 호출해보기
- Foo 클래스의 func2 메서드는 메서드의 인자가 self뿐이므로 실제 메서드를 호출할 때 인자를 전달할 필요가 없음
- 메서드를 호출한 결과를 보면 화면에 정상적으로 'function 2'가 출력되는걸 알 수 ㅇ,ㅁ
- 참고로 func2 메서드의 첫 번째 인자는 self지만 호출할 때는 아무것도 전달하지 않는 이유는 첫 번째 인자인 self에 대한 값은 파이썬이 자동으로 넘겨주기 때문임
>>> f = Foo()
>>> f.func2()
function 2
- func1 메서드처럼 메서드를 정의할 때부터 아무 인자도 없는 경우에는 어떻게 될까?
- 인스턴스를 통해 func1() 을 호출하면 오류가 발생
- 오류메시지는 "func1()은 인자가 없지만 하나를 받았다." 라는 의미
- 이는 앞서 설명한 것처럼 파이썬 메서드의 첫번째 인자로 항상 인스턴스가 전달되기 때문임
>>> f.func1()
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
f.func1()
TypeError: func1() takes 0 positional arguments but 1 was given
- 파이썬 내장 함수 id를 이용해 인스턴스가 메모리에 할당된 주솟값을 확인해보기
- Foo 클래스를 새롭게 정의하고 인스턴스를 다시 만들고 id() 내장함수를 이용해 인스턴스가 할당된 메모리 주소를 확인
>>> class Foo:
def func1():
print("function 1")
def func2(self):
print(id(self))
print("function 2")
>>> f = Foo()
>>> id(f)
43219856
- 생성된 인스턴스가 메모리의 43219856 번지에 있음
- f와 인스턴스의 관계: Foo 클래스에 대한 인스턴스는 메모리의 43219856번지부터 할당돼있고 변수 f는 인스턴스의 주솟값을 담고 있음

- 인스턴스 f를 이용해서 func2 메서드를 호출
- func2 메서드를 호출할 때 아무런 값도 전달하지 않음
- f라는 변수가 바인딩하고 있는 인스턴스의 주솟값과 동일한 값이 출력됨
- 즉, 클래스 내에 정의된 self는 클래스 인스턴스임을 알 수 있음
>>> f.func2()
43219856
function 2
- 객체를 하나 더 만들어 비교해보기
- 새로 생성한 객체는 f2가 가리키고 있는데 id를 통해 주소가 47789232인걸 확인할 수 있음
- f2를 통해 func2 메서드를 호출하면 똑같이 47789232 가 출력됨
>>> f2 = Foo()
>>> id(f2)
47789232
>>> f2.func2()
47789232
function 2
- 파이썬의 클래스는 그 자체가 하나의 네임스페이스 이기 때문에 인스턴스 생성과 상관없이 클래스 내의 메서드를 직접 호출할 수 있음
>>> Foo.func1()
function 1
- func1 메서드를 호출했지만 앞서 인스턴스를 통해 메서드를 호출했던 것과 달리 오류가 발생하지 않음
- 앞서
인스턴스.메서드() 형태로 호출한 것과 달리 이번에는 클래스명.메서드() 형태로 호출했기 때문!
- func2에서도 클래스 이름을 통해 호출해보면
self 위치에 인자를 전달하지 않고 메서드를 호출했을 때 오류가 발생

- 인자를 하나 전달해야 하는데 전달하지 않아서 오류가 난 것
- 그럼 어떤 값을 전달하면 되는 걸까?
- 앞에서 메서드의 self로 전달되는 것은 인스턴스 자체였음
- 따라서 클래스에 대한 인스턴스를 생성한 후 해당 인스턴스를 전달하면 됨
>>> f3 = Foo()
>>> id(f3)
47789136
>>> Foo.func2(f3)
47789136
func2
- 인스턴스를 통해 fun2를 호출하는 것과 클래스 이름을 통해 func2를 호출하는 것은 어떤 차이가 있을까?
- 결론부터 말하면 아무런 차이가 없음
- 다만
인스턴스.메서드()냐 클래스.메서드(인스턴스) 냐라는 차이가 있을 뿐
생성자(Constructor)
- 객체가 생성될 때 자동으로 호출되는 메서드를 의미
class Calc:
def set(self, n1, n2):
self.n1 = n1
self.n2 = n2
def add(self, n1, n2):
return self.n1 + self.n2
- Calc 클래스에 add라는 더하기 메서드를 만든 후 set으로 n1과 n2를 정의하지 않고 add를 쓰면 오류 발생
- 이를 방지하기 위해 메서드 이름으로
__init__을 사용하면 해당 메서드는 생성자가 됨
class Calc:
def __init__(self, n1, n2):
self.n1 = n1
self.n2 = n2
def set(self, n1, n2):
self.n1 = n1
self.n2 = n2
def add(self, n1, n2):
return self.n1 + self.n2
__init__은 set과 이름만 다르고 모든 게 동일하지만 이름을 __init__으로 하고 메서드를 생성했기 때문에 생성자로 인식되어 클래스가 실행되면 자동으로 호출됨
__init__이 있으면 Calc 클래스 호출 시 매개변수 값을 입려갷 주어야 함: a-Calc(10,5)
- 생성자가 있기 때문에 매개변수 없이 클래스를 호출한다면 오류 발생
__call__
__init__과 같은 생성자
- 함수를 호출하는 것처럼 클래스의 객체를 호출하게 만들어주는 메서드
- 즉,
__init__은 인스턴스 초기화를 위해, __call__은 인스턴스 호출 시 실행을 위해 작성하는 메서드임
class Calc:
def __init__(self, n1, n2):
self.n1 = n1
self.n2 = n2
return print(self.n1, self.n2)
def __call__(self, n1, n2):
self.n1 = n1
self.n2 = n2
return print(self.n1 + self.n2)
s = Calc(1,2)
s(7,8)
1 2
15
클래스의 상속(inheritance)
- 어떤 클래스를 만들 때 다른 클래스의 기능을 물려받을 수 있게 만든 것
class 클래스 이름(상속할 클래스 이름)으로 상속
class GoodCalc(Calc):
pass
- GoodCalc는 Calc을 상속했기 때문에 add와 set 등 Calc의 모든 기능을 사용할 수 있음
- 즉, 상속은 기존 클래스를 변경하지 않고 기능을 추가하거나 변경할 때 사용
메서드 오버라이딩(overriding)
- 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것을 의미
- 메서드 오버라이딩(=덮어쓰기)을 하면 부모 클래스의 메서드 대신 오버라이딩한 메서드가 호출됨
- 부모 클래스의 메서드를 같은 이름으로 수정하고 호출할 때 사용
- 예: torch.nn.Module의 forward 메서드