파이썬 class

윤태영·2023년 11월 18일
0
post-thumbnail

이미지 출처: https://wikidocs.net/192339

여러분 혹시 객체지향이라는 단어 들어보신 적 있으신가요? 객체 지향이 뭔지 요약해서 그 이론을 바탕으로 파이썬에서 클래스, 인스턴스등 python에서 클래스를 활용해서 어떤 코딩을 할 때 필요한 패턴들을 알아봅시다.😎

클래스 개념

  • OOP란?
  • 클래스, 인스턴스
  • Self 개념
  • 인스턴스 메소드
  • 클래스 인스턴스 변수

객체 지향 프로그래밍(OOP)은 소프트웨어를 설계하고 구현하는 한 가지 방법론입니다. 프로그램을 객체들의 모임으로 간주하며, 이 방법론은 현실 세계의 객체(object)들과 그 객체 간의 상호 작용을 모형화하고자 하는 개념에서 기인합니다. 객체 지향 프로그래밍의 주요 개념들 안에는 클래스, 객체 상속 같은 것들이 있습니다.

  • 클래스(class) : 클래스는 객체를 정의하는 틀입니다. 속성(데이터)과 메서드(함수)를 포함하며, 클래스를 이용하여 여러개의 객체를 생성할 수 있습니다. 쉽게 이해하면 붕어빵을 만든다고 가정하면, 붕어빵을 만드는 틀이라고 생각하면 됩니다.

  • 인스턴스 : 특정 클래스의 실제 객체를 의미합니다. 붕어빵 틀을 가지고 우리가 코드에서 사용하는 어떤 객체를 인스턴스라고 생각하면 됩니다.

  • 네임스페이스 : 객체를 인스턴스화 할때 저장되는 공간

  • 클래스 변수 : 직접 접근 가능, 공유

  • 인스턴스 변수 : 객체마다 별도 존재

  • 객체 : 소프트웨어에 구현할 대상

자세한 내용들은 코드를 보면서 이해합시다.

클래스 생성 📕

예1

  • Dog라는 클래스를 생성해보자.
  • 인스턴스는 클래스를 가지고 코드에서 사용하는 어떤 객체(인스턴스가 객체에 포함된다고도 볼 수 있다.)
# 모든 class는 object를 상속 받는다.
# Dog 라는 클래스 생성
class Dog: 
    # 클래스 속성
    species = 'firstdog' # 클래스 변수(직접 접근가능)
    # 초기화/인스턴스 속성(모든 클래스는 초기화 메소드를 가진다.)
	# 클래스를 가지고 사용할 변수와 속성들을 지정할 수 있다. name,age를 입력받자.
    # 초기화/인스턴스 속성(모든 클래스는 초기화 메소드를 가진다.)
    # 클래스를 가지고 사용할 변수와 속성들을 지정할 수 있다. name,age를 입력받자.
    # 파이썬에서는 클래스가 초기화 될때 반드시 한번 호출되는 함수가 있다.
    def __init__(self,name,age):  
        self.name = name  # self가 붙은것은 인스턴스 변수
        self.age = age
# 클래스 정보
print(Dog)
>>> <class '__main__.Dog'> # 우리가 만든 클래스가 코드로 구현됨
# 우리는 Dog class를 가지고 수많은 애완견을 코드로 표현 가능하다.
# 인스턴스화
# 인스턴스는 코드로 직접구현해서 메모리에 올라간그시점, 그 변수를 사용할수 있는 대상
# 변수 = 클래스이름()
a = Dog('mikky', 2) #  이런 식으로 Dog라는 틀을 가지고  코드상에서 a라는 것을 변수로 할당해서 메모리에 올라가서 id값을 가진다. 이렇게 실제로 설계도를 바탕으로 구현된것을 인스턴스화라고 한다. 
b = Dog('baby', 3)
c = Dog('mikky', 2)
# 비교
print(a == b, id(a), id(b), id(c)) # 똑같은 클래스를 가지고 인스턴스화 시켰지만 age와 name이 다르다. 값이 같더라도 인스턴스화 시킨 것들은 모드 다르다.
>>> False 2162855615184 2162855615120 2162855615248
# 네임스페이스
print('dog1', a.__dict__) # class(붕어빵 기계)가 갖고있는 속성들을 확인가능
print('dog1', b.__dict__)
>>>
dog1 {'name': 'mikky', 'age': 2}
dog1 {'name': 'baby', 'age': 3}
# 인스턴스 속성 확인
print('{} is {} and {} is {}'.format(a.name, a.age, b.name, b.age))
if a.species == 'firstdog':
    print('{0} is a {1}'.format(a.name, a.species))
>>>
mikky is 2 and baby is 3
mikky is a firstdog
# 클래스변수는 직접 접근가능!
print(Dog.species) # 클래스로도 접근 가능하고
>>> firstdog
# 인스턴스화된 변수로도 접근 가능
print(a.species) 
>>> firstdog
# 클래스 변수는 하나의 값을 공유가능, self가붙은 것들은 별도 존재
print(b.species)  
>>> firstdog

코드 재사용이 가능하다. 클래스를 하나 만들어 놓고 붕어빵을 찍듯이 사용하면 되고 필요의 경우에는 나만의 공간도 있고, 별도로 공유하는 공간도 있기에 활용에 따라서 코드를 세련되고 객체지향에 입각해서 불필요한 중복을 방지하고 깔끔한 코드를 통해서 프로그래밍 개발이 가능합니다. 그에 따라 생산성 향상 또 성능도 좋아진다. 이게 객체지향의 핵심이라고 생각하면됩니다.

self의 이해 📕

  • self가 붙으면 나만의 인스턴스 속성이다.
  • init 메소드가 없으면 파이썬이 내부적으로 코드가 클래스를 만들때 내부적으로 실행, 근데 우리는 필요한 name이나 age같은것이 없고 기본으로 사용할 것이라 만들지 않은것

예2

class Selftest:
    def func1(): # 메소드2개 생성, 즉 암묵적으로 클래스내부의 매개변수를 선언하는데 셀프가 없다 이런것은 클래스 매소드이다.
        print('Func1 called')
    def func2(self):
        print('Func2 called')
f = Selftest() # 인스턴스화, self는 인스턴스를 요구한다. self에 f가 넘어간것
f안에 네임스페이스에 있는 우리가 사용할 수 있는 모든 메소드
print(dir(f)) # f안에 네임스페이스에 있는 우리가 사용할 수 있는 모든 메소드
>>> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'func1', 'func2']
>>> print(id(f))
>>> 2520622536848
f.func1()
# 오류가 발생했는데 일단 예외 처리하겠습니다.
>>> Selftest.func1() takes 0 positional arguments but 1 was given
# func2는 호출이 잘 된다.
f.func2()
>>> Func2 called

self의 id값을 출력해보겠습니다.

# self는 인스턴스를 요구
# self에 f가 넘어간것
# 클래스를 인스턴스 시킨 f의 id값과 self로 넘어온 id값이 같다.
# 암묵적으로 이 클래스 내부의 매개변수를 선언하는데 셀프가 없다면 이건 클래스 메소드이다.
class Selftest:
    def func1(): 
        print('Func1 called')
    def func2(self):
    	print(id(self))
        print('Func2 called')
f = Selftest() 
print(id(f))
>>> 2990033180880
>>> 2990033180880
# 클래스 메소드는 아래와 같이 호출
# 이때는 self가 없고 클래스로 바로 접근해서 호출할 수 있는 메소드가 되는거고, self라는 메소드가 있으면 f처럼 클래스를 생성한 인스터스화 시킨 변수가 self로 넘어간다.
Selftest.func1()
>>> Func1 called
# 하나의 매개변수를 요구하지만 들어가지 않아서 오류, 즉 인스턴스화 시킨 변수를 넣어주면 오류가 발생하지 않는다.
# 즉 클래스로 바로 접근해서 호출할때 self가없으면 여기서 생성한 인스턴스 변수를 넣어주면 되고, 인스턴스화 시켜서 호출하면 바로 알아서 self로 id가 f의 인스턴스값이 넘어간다.
Selftest.func2()
>>> Selftest.func2() missing 1 required positional argument: 'self'
Selftest.func2(f)
>>> Func2 called
  • self가 들어 있다면 인스턴스 메소드이기에 f.func2()와 같이 호출!
  • 아무것도 없다면 클래스 메소드 이기에 Selftest.func1()와 같이 호출!

당장 이해되지 않는다면 위의 것만 알고 계시면 나중에 이해가 되실겁니다.

예3

  • 클래스 변수(모두가 공유, 예를들어 specise, 인스턴스 변수(나만의 변수))
  • 현실세계에 존재하는 것을 클래스로 찍어내고, 이것을 객체화 시켜서 코드에서 인스턴스화 시켜사용
class warehouse:
    # 클래스 변수
    stock_num = 0 # 재고
    def __init__(self, name):
        # 인스턴스 변수(self가 붙은것)
        self.name = name
        warehouse.stock_num +=1 # 객체가 하나 만들어질때(초기화) stock_num의값을 1증가
	def __del__(self):  # del 메소드는 객체가 소멸할때 자동으로 호출되는 함수
        warehouse.stock_num -=1 # 메모리에서 소멸할때 -1
 # 창고에 사람이 한명 들어온다. Lee라는 사람을 객체를 생성하여 인스턴화되었다.
user1 = warehouse('Lee') 
user2 = warehouse('Cho') 
# 이 시점에서 객체가 2개 생성되었기에 stock_num은 2가된다.(1+1)
print(warehouse.stock_num)        
>>> 2
print(user1.name)
>>> Lee
print(user2.name)
>>> Cho
print(user1.__dict__) # 인스턴스 네임스페이스에 없으면 클래스의 네임스페이스 가서 찾아보자.
>>> {'name': 'Lee'}
print(user2.__dict__) # 'stock_num': 2는 밑의 warehouse의 클래스의 네임스페이스에 있기에 굳이 출력안해줌
>>> {'name': 'Cho'}
print('before', warehouse.__dict__)
>>> before {'__module__': '__main__', 'stock_num': 2, '__init__': <function warehouse.__init__ at 0x0000024A1E948F40>, '__del__': <function warehouse.__del__ at 0x0000024A1E948EA0>, '__dict__': <attribute '__dict__' of 'warehouse' objects>, '__weakref__': <attribute '__weakref__' of 'warehouse' objects>, '__doc__': None}
# del이 호출되어 삭제됨, 인스턴스를 메모리에서 지움
del user1  
print('after',warehouse.__dict__)  
# stock_num = 1이 된것 확인
>>>
after {'__module__': '__main__', 'stock_num': 1, '__init__': <function warehouse.__init__ at 0x000002ED80048FE0>, '__del__': <function warehouse.__del__ at 0x000002ED80048EA0>, '__dict__': <attribute '__dict__' of 'warehouse' objects>, '__weakref__': <attribute '__weakref__' of 'warehouse' objects>, '__doc__': None}

예4

class Dog2: # object 상속
    # 클래스 속성
    species = 'firstdog' 
	# 초기화/인스턴스 속성
    # 개가 가지고있는 속성과 행동을 메소드로 구현
    def __init__(self,name,age):  
        self.name = name  
        self.age = age
	def info(self): # info라는 메소드를 만든다.
        return '{} is {} years old'.format(self.name, self.age)
	def speak(self, sound): # speak을 호출할때 sound를 입력받아서 밑에 대입해서 출력
        return '{} says {}!'.format(self.name, sound)
# 인스턴스 생성
C = Dog2('july', 4)
d = Dog2('Marry', 10)
# 메소드 호출
print(C.info()) # return이 문자로 오기에 print문으로 출력
>>> july is 4 years old
# 메소드 호출
print(C.speak('wal wal'))
>>> july says wal wal!
print(d.speak('Mung Mung'))
>>> Marry says Mung Mung!

지금 바로 이해되지않더라고 코드를 보면서, 천천히 복습하다 보면 나중에는 이해가 되실겁니다. 이해되지 않는 부분은 검색하고 찾아보시길 바랍니다.🙂

출처 : 인프런

profile
ice blue

0개의 댓글