파이썬 기초편(1) - 클래스와 객체 본문
● 전역변수와 지역변수
- 함수 안에 선언되는 변수 <지역변수>
- 함수 밖에 선언되는 변수 <전역변수>
지역변수의 범주에는 매개변수도 포함이 된다
def func(n): # 매개변수 n도 지역변수 범주에 포함(지역변수의 일종이다)
lv = n + 1
print(lv)
print(lv) # 함수 밖에서 지역변수 lv에 접근, 따라서 오류!
'''
지역변수는 함수 내에 만들어졌다가 함수를 벗어나면 사라지는 변수이다
'''
cnt = 100 # 함수 밖에서 선언된 전역변수 cnt
cnt += 1 # 전역변수 cnt에 접근
def func():
print(cnt) # 함수 내에서 전역변수 cnt에 접근!
func()
함수 내에서는 얼마든지 함수 밖에 선언된 변수에 접근할 수 있다
cnt = 100 # 전역변수 cnt 선언
def func():
cnt = 0 # 이럴 경우엔 "지역변수 cnt를 선언하고 0을 저장한다"
print(cnt) # 새로 생성된 지역변수의 값인 0을 출력한다
func()
'''만약! global 키워드가 있다면?'''
cnt = 100
def func1():
global cnt # 이 함수 내에서 접근하는 cnt는 "전역변수"임을 알려준다
cnt = 0 # 전역변수 cnt에 0 저장
print(cnt) # 전역변수 cnt의 값인 0출력
func1()
● 객체지향 프로그래밍
- 객체지향 프로그래밍(OOP; Object Oriented Programming)
OOP와 별개로 클래스와 객체는 좋은 프로그램을 만드는 도구가 된다. 다시 말해 OOP와 상관없이 내게 필요한 클래스를 만들고 또 객체를 만들 수 있어야 한다.
● 클래스와 객체 이전의 프로그램에 대한 반성
fa_age = 39
def up_fa_age():
global fa_age # 이 함수에서 접근하는 fa_age는 전역변수임을 선언함!
fa_age += 1
def get_fa_age():
return fa_age
mo_age = 35
def up_mo_age():
global mo_age # 이 함수에서 접근하는 fa_age는 전역변수임을 선언함!
mo_age += 1
def get_mo_age():
return mo_age
def main():
print("2019년...")
print("아빠:", get_fa_age())
print("엄마:", get_mo_age())
prin("2020년...")
up_fa_age()
up_mo_age()
print("아빠:", get_fa_age())
print("엄마:", get_mo_age())
함수를 만들어서 전역변수에 접근하는 방식은 직접 전역변수에 접근하지 않기에 코드를 더 안정적이고 이해하기 쉽게 만든다. 하지만 만약 여기에 본인과 동생의 나이까지 관리한다고 생각해보자. 코드양이 배로 늘어날 것이다. 이러한 문제점을 클래스와 객체를 통해서 해결해보자
● 클래스와 객체의 이해
- '객체(object)'란 우리 주변에 존재하는 모든 사물 하나하나를 뜻한다
- 이 '객체'들을 만들기 위해서는 '설계도'가 필요하다. 그리고 '설계도'가 있다면 이를 기반으로 얼마든지 똑같은 모습의 객체를 만들 수 있는데 바로 이 설계도를 가리켜 "클래스"라 한다.
파이썬 기반으로 우리가 원하는 형태의 객체를 만들기 위해서는 먼저 그 객체의 설계도에 해당하는 '클래스'라는 것을 만들어야 한다. 다시 말해서 클래스를 '정의'해야 한다.
- "객체를 만들려면 그 객체의 설계도에 해당하는 클래스를 먼저 정의해야 한다"
위의 코드를 수정하기 위해 클래스를 하나 만들어본다. 나이와 정보관리를 위해 변수와 함수들을 만든다. 이 클래스가 아빠 나이만을 대상으로 하지 않으므로 수정한다
- fa_age -> age
- up_fa_age() -> up_age()
- get_fa_age() -> get_age()
이것들을 설계도에 포함시키려면 다음과 같이 수정해야 한다
def up_age(self): # self가 왜 등장했는지 아직 모름, 단 self는 매개변수임!
self.age +=1 # age가 아니라 self.ag이다, 이렇게 바뀐 이유 아직 모름
def get_age(self):
return self.age
일단 global 선언은 필요 없다. 클래스 안에 담길 변수 age는 전역변수가 아니기 때문이다. 그리고 self라는 매개변수가 등장했다.
자 이 두 함수를 클래스에 담아보겠다. 클래스의 이름은 AgeInfo라 하자! 진짜 그냥 담으면 된다
class AgeInfo: # 클래스 AgeInfo의 정의
def up_age(self): # 클래스 안에 담긴 up_age 함수
self.age +=1
def get_age(self): # 클래스 안에 담긴 get_age 함수
return self.age
근데 age 변수가 클래스 안에 없다. 그런데 파이썬이 알아서 넣어준다(실제와는 차이가 좀 있는 설명이지만 이렇게 이해하자)
# class_object.py
class AgeInfo: # 클래스 AgeInfo의 정의
def up_age(self):
self.age += 1
def get_age(self):
return self.age
def main():
fa = AgeInfo() # AgeInfo 객체를 생성하고 이를 변수 fa에 저장
fa.age = 39
print("현재 아빠 나이...")
print("아빠:", fa.get_age())# get_age 호출할 때 self에 값 전달하지 않음!
print("1년 뒤...")
fa.up_age() # up_age 호출할 때 self에 값 전달하지 않음
print("아빠:", fa.get_age())# get_age 호출할 때 self에 값 전달하지 않음!
main()
- fa = AgeInfo() # AgeInfo의 객체를 생성하고 이를 변수에 저장
위 문장이 실행되면 AgeInfo라는 클래스(설계도)를 기반으로 객체가 생성되고, 이 객체를 변수 fa에 저장하게 된다.
- fa.age = 39
파이썬에 객체 fa에 변수 age를 넣어주는 것은 이 문장이 실행될 때이다. 이 때 변수 age가 생성된다(추가설명은 중급편에서). 변수이름에 점을 찍는 것은, 해당 변수에 저장된 객체의 변수나 함수에 접근하는 행위이다.
이제 객체 내부의 상태는 이러하다
- age = 39
- def up_age(): age += 1
- def get_age(): return age
객체 안에 존재하는 변수 age는 어떤 종류의 변수일까? 우리는 지역변수와 전역변수를 알고 있다. 그러나 객체 안의 변수는 이 둘과는 부류가 다른 '인스턴스 변수'이다. 더불어 객체 안에 있는 함수는 '메소드'라고 한다. 정확히는 '인스턴스 메소드'이다.
- 인스턴스 변수 : 인스턴스(객체) 안에 존재하는 '변수'를 뜻하는 말
- 인스턴스 메소드 : 인스턴스(객체) 안에 존재하는 '함수'를 뜻하는 말
인스턴스는 '객체'의 또 다른 표현이다. 의미적인 차이가 조금 있지만 보통은 동일하게 취급되므로 지금은 신경쓰지 않아도 된다. 객체 생성 부분을 이렇게 말해도 된다
- "AgeInfo의 인스턴스가 생성되어서 변수 fa에 저장되었다"
● 나이 정보 관리하는 이전 예제의 수정 결과
class AgeInfo:
def up_age(self):
self.age+=1
def get_age(self):
return self.age
def main():
fa = AgeInfo()
ma = AgeInfo()
me = AgeInfo()
fa.age = 39
ma.age = 36
me.age = 12
sum = fa.get_age() + ma.get_age() + me.get_age()
print("가족 나이의 합:", sum)
fa.up_age()
ma.up_age()
me.up_age()
sum = fa.get_age() + ma.get_age() + me.get_age()
print("1년 후의 합:", sum)
main()
가족이 하나 더 추가되었다 하더라도 그에 따른 변수나 함수를 추가할 필요는 없다. 그저 객체만 하나 더 생성하면 되는 것이다. 이것이 클래스가 주는 장점이다.
● self 너 뭐냐!
위의 사진에 있는 up_age, get_age 함수가 똑같으니 공유할 수 있지 않을까? 의문이 생겼고 그 결과 파이썬은 다음과 같은 모델을 생각해내고 완성한다
fa.up_age() # 변수 fa에 저장된 객체의 up_age 함수 호출
# AgeInfo 클래스의 함수가 실제 저장된 위치로 가서 up_age 함수를 호출하되,
# fa를 인자로 전달하면서 다음과 같은 형태로 호출
up_age(fa)
# 매개변수 self에 fa가 전달되므로 다음과 같은 형태로 함수 호출이 진행된다.
# (fa의 메모리공간에 self라는 이름이 하나 더 붙어서 이 순간 self는 fa가 된다)
def up_age(fa):
fa.age += 1
def get_age(self):
return self.age
# AgeInfo 클래스의 두 함수를 직접 호출하는 방법은 다음과 같다
AgeInfo.up_age(...)
AgeInfo.get_age(...)
# 즉 우리가 다음과 같이 문장을 작성하면,
fa.up_age()
# 파이썬은 이 문장을 다음 형태로 바꿔서 함수를 호출한다
AgeInfo.up_age(fa)
# fa메모리공간에 self 이름이 붙어 self로 객체를 접근한게 된다. 때문에 self가 필요하고 어떻게 사용되는지 알 수 있다
● self 이외의 매개변수를 갖는 메소드들(함수들) 정의해보기
클래스의 인스턴스 메소드에도 얼마든지 매개변수를 추가할 수 있다.
def set_age(self, n): # 매개변수로 self도 있고 n도 있다
self.age = n
# 이렇게 정의한 메소드를 호출할 때는 self에는 파이썬이 알아서 전달을 하니, n에만 매개변수만 전달하면 된다
def set_age(self, age):
self.age = age # age는 매개변수, self.age는 인스턴스 변수
# '매개변수'와 '인스턴스 변수'의 이름이 같아지지만, 함수 안에서 그냥 age라고 쓰면 매개변수가 되고,
# self.age라고 쓰면 인스턴스 변수가 되기때문에 이름이 같아도 된다
코드
# family_age4.py
class AgeInfo:
def up_age(self):
self.age += 1
def get_age(self):
return self.age
def set_age(self, age):
self.age = age
def main():
fa = AgeInfo()
fa.set_age(39)
fa.up_age()
print("1년 후 아빠 나이 :", fa.get_age())
main()
fa.age = 9 처럼 인스턴스 변수에 직접 접근해서 초기화 하는 대신
fa.set_age(39) 처럼 메소드 호출을 통해 인스턴스 변수 초기화를 할 수 있다
● 생성자
객체 생성 후에는 반드시 다음처럼 "인스턴스 변수의 초기화"를 해줘야 한다.
def main():
fa = AgeInfo() # AgeInfo의 객체 생성
fa.age = 39 # 인스턴스 변수 age의 값을 20으로 초기화
객체 안에 존재하는 모든 변수는 초기화를 해야 하며, 이러한 초기화를 객체 생성 후에 바로 하는 것이 일반적. 그래서 객체의 생성과 변수의 초기화를 동시에 진행할 수 있도록 '생성자(constructor)'라는 것을 제공
# ctor1.py
class Const:
def __init__(self): # 생성자라 불리는 메소드, 메소드 이름이 __init__이다
print("new")
def main():
o1 = Const()
o2 = Const()
main()
생성자는 객체 생성 시 자동으로 호출이 되는 특징이 있다. 생서아도 다른 메소드들과 마찬가지고 매개변수로 self를 넣어줘야한다.
# ctor2.py
class Const:
def __init__(self, n1, n2):
self.n1 = n1 # self.n1은 인스턴스 변수, n1은 매개변수
self.n2 = n2 # self.n2는 인스턴스 변수, n2는 매개변수
def show_data(self):
print(self.n1, self.n2)
def main():
o1 = Const(1, 2) # 생성자에 1과 2를 전달
o2 = Const(3, 4) # 생성자에 3과 4를 전달
o1.show_data() # 결과: 1 2
o2.show_data() # 결과: 3 4
main()
family_age4.py 파일 수정하여 생성자 사용한 코드
# family_ag5.py
class AgeInfo:
def __init__(self, age):
self.age = age
def up_age(self):
self.age += 1
def get_age(self):
return self.age
def main():
fa = AgeInfo(39) # 객체 생성 후 초기화
fa.up_age()
print("나이 출력 :", fa.get_age())
main()
● 사실 파이썬의 모든 데이터는(값은) 객체
s = "coffee"
s.upper() # 이런 함수 호출이 가능하다는 것은 s에 담긴 것이 객체라는 의미!
# 결과: COFFEE
n = 1000
n.bit_length() # 변수 n에 담긴 정수도 객체라는 증거!
# 결과: 10
f = 3.14
f.is_integer() # 변수 f에 담긴 실수도 객체라는 증거!
# 결과: False
정수나 실수를 입력하면 파이썬은 이를 객체로 만든다. 따라서 그 객체를 대상으로 인스턴스 메소드를 호출할 수 있는 것이다.
'Programming > python' 카테고리의 다른 글
파이썬 기초편(2) - 레퍼런스 카운트와 가비지 컬렉션 (0) | 2022.06.19 |
---|---|
파이썬 기초편(1) - 예외처리 (0) | 2022.06.16 |
파이썬 기초편(1) - 딕셔너리(Dictionary) (0) | 2022.06.14 |
파이썬 기초편(1) - '모듈의 이해' 그리고 '수학 모듈' 이용하기 (0) | 2022.06.12 |
파이썬 기초편(1) - 튜플(tuple)과 레인지(range) (0) | 2022.06.10 |