본문 바로가기
파이썬/기초문법

Python 클래스에 대해 1

by 행복론자 2020. 3. 15.

함수형 프로그래밍이 인기를 얻고 있지만 여전히 클래스 기반 언어는 강력하다고 생각합니다.

다만 객체지향의 문제점으로는 프로그램의 규모가 커지고 참여하는 사람들이 많을수록 소스가 스파게티마냥 꼬이기 쉬워져 객체 간 책임/역할을 나누기가 모호해지면서 점점 왜 이렇게 한 클래스에서 하는 일이 많아지지.. 뭐하러 상속했지? 하면서 이게 객체지향인가 싶어지는 경우가 많은 것 같습니다. 

 

그럼에도 객체지향은 현실로 넘어 우리의 상상을 구현할 수 있다는 점에서 매력적이고 강력한 것 같습니다.

문/이과를 넘어 요즘 'Python 쉽다. Python 배워라' 하는 말이 많은데 이 Python도 클래스 기반 언어입니다.

 

클래스는 무엇일까요?

클래스는 설계도라고 생각할 수 있습니다. 

Python에서 클래스를 만드는 방법은 다음과 같습니다.

class 클래스이름:
    def 함수(self):
        코드

 

 

클래스를 하나 만들어 보겠습니다.

class Person():
    def talk(self):
        print("Hello")

 

 

클래스 이름을 Person으로 정하고 여기서 talk라는 함수를 하나 만들었습니다. 그럼 이 함수를 호출해보겠습니다.

Person.talk()

 

 

에러 납니다. talk 함수에 매개변수로 self를 적어주었는데 실제로는 전달되지 않아서 그렇습니다.

여기서 self는 인스턴스를 의미합니다. self에 대한 설명은 이글을 참고 바랍니다.

Traceback (most recent call last):
    Person.talk()
TypeError: talk() missing 1 required positional argument: 'self'

 

 

아무튼 Person.talk()을 통해 함수를 호출하려고 하면  self가 필요하다고 적어줬는데 실제로 호출할 때는 self를 전달하지 않을 것이니 애초에 talk 함수에서 매개변수를 제거하고 그냥 호출해보겠습니다.

class Person():
    def talk():
        print("Hello")
        
Person.talk()  # Hello      

 

 

잘 됩니다.

그런데 이렇게 Person을 만들면 사실상 아무 필요 없는 클래스가 된다는 문제가 있습니다.

Person이라는 클래스를 이용해 객체를 만들어보겠습니다. 객체를 만드는 방법은 이렇습니다.

vip_investor = Person()

 

 

vip_inverstor란 변수에 Person 객체가 담겼습니다. 이를 인스턴스화시켰다고 표현하고 vip_investor는 Person의 인스턴스가 됩니다. 이렇게 만든 vip_inverstor는 Person 설계도에 있는 함수를 사용할 수 있습니다.

하지만 우리의 vip_investor은 talk 함수를 호출할 수 없습니다.

class Person():
    def talk():
        print("Hello")

vip_investor = Person()
vip_investor.talk() # error

 

 

왜냐하면 인스턴스를 이용해 함수를 호출할 때 Python에서 자동으로 해당 인스턴스를 함수의 매개변수로 전달하는데 Person클래스에 있는 talk 메소드는 아예 매개변수를 받지 않겠다고 해버리니 문제가 생기기 때문입니다. 

 

여기서 메소드에 self라는 매개변수를 받지 않도록 하면 생길 수 있는 또 다른 문제는 Person 클래스를 통해 만든 객체들이 아무 쓸모가 없어지게 만듭니다. 

 

왜냐하면 클래스에서 공통으로 가질 수 있는 변수와 객체마다 가질 수 있는 변수가 있는데 self를 사용하지 않으면 객체마다 저장할 변수를 만들 수도 없고 당연히 접근할 수가 없기 때문입니다.

 

그러지말고 객체마다 필요한 정보도 담아보고 사용할 수도 있도록 해보겠습니다.

그러기 위해서는 특정함수가 필요합니다.

예를 들어 Person을 통해 만들어지는 사람마다 나이를 저장하기 위해서는 __init__ 메소드가 필요합니다. (메소드명이 __로 시작하면 특별해집니다.)

class Person():
    def __init__(self, age):
        self.age = age

    def talk(self):
        print("Hello")

 

 

여기서 __init__ 함수는 Person을 이용해 객체를 만들 때 자동으로 호출되며

이제는 객체 생성에 age를 정해서 전달해야합니다.

그렇지 않으면 에러가 납니다. 초기화할 때 (__init__ 함수를 호출할 때) 필요한 age를 전달하지 않아서 그렇습니다. 

vip_investor = Person() # error! 

 

 

이렇게 해야합니다. 

vip_investor = Person(25)

 

 

그럼 __init__은 수동으로 호출할 수도 있을까요

vip_investor = Person(25)
Person.__init__(vip_investor,10)

 

 

가능합니다만 Person(25)를 호출하면서 인스턴스(vip_investor)의 나이를 25로 초기화했는데 

다시 __init__을 호출하면 나이를 10으로 다시 초기화해버립니다. 

실제로 이렇게 클래스 밖에서 초기화 함수를 수동으로 다시 호출해서 사용할 케이스는 드물고

다시 초기화해야한다면 클래스 내에서 self.__init__()처럼 호출하는 것이 더 보편적일 것입니다. 

 

 

이제 투자자를 두 명 만들고 각각 나이를 설정해주겠습니다.

class Person():
    def __init__(self, name, age):
        print('__init__ is called %s ' % name)
        self.name = name
        self.age = age

    def talk(self):
        print("Hello my age %s" % self.age)


vip_investor1 = Person('john lee', 25)
vip_investor2 = Person('kangcfa', 35)

 

 

실행해보면 Person을 통해 객체를 만들 때마다 __init__ 함수가 자동으로 실행되며 vip_investor1과 vip_investor2가 서로 같은 클래스에서 생성되었지만 생성된 순간부터 서로 아무 연관이 없어짐을 알 수 있습니다.

vip_investor1 = Person('john lee', 25)
vip_investor1.talk()  # Hello my age 25
vip_investor2 = Person('kangcfa', 35)
vip_investor2.talk() # Hello my age 35

 

 

이렇게 생성된 인스턴스가 같은 변수에 접근하기 위해서는 클래스변수를 설정해주면 됩니다.

지금까지 self. 를 통해 접근한 변수들을 인스턴스 변수라고 하고 객체마다 따로 설정/관리되지만 클래스변수는 같은 클래스를 통해 나온 인스턴스 모두 공유가능합니다.

 

두 투자자가 공통 투자금을 이용한다고 생각해보겠습니다.

class Person():
    cash = 1000

    def __init__(self, name, age):
        print('__init__ is called %s' % name)
        self.name = name
        self.age = age
        Person.cash += 100  # 객체가 만들어질 때마다 클래스 변수에 돈 넣기 

    def talk(self):
        print('Hello my age %s' % self.age)


vip_investor1 = Person('john lee', 25)
vip_investor1.talk()

vip_investor2 = Person('kangcfa', 35)
vip_investor2.talk()

 

 

여기서 클래스 변수 cash를 출력할 수 있는 함수 talk_cash를 만들어보겠습니다.

클래스 변수에 대한 접근을 하기 위해서는 self.cash가 아니라 클래스명을 사용해야합니다. Person.cash를 써야합니다. 

class Person():
    cash = 1000

    def __init__(self, name, age):
        print('__init__ is called %s ' % name)
        self.name = name
        self.age = age
        Person.cash += 100

    def talk(self):
        print("Hello my age %s" % self.age)

    def talk_cash(self):
        print(Person.cash)


vip_investor1 = Person('john lee', 25)
vip_investor1.talk()
vip_investor1.talk_cash()

vip_investor2 = Person('kangcfa', 35)
vip_investor2.talk()
vip_investor1.talk_cash()

 

 

talk_cash 함수는 다음과 같이 만들 수도 있습니다. 

self로 전달하던 첫번째 매개변수를 cls(=class)로 바꾸어서 전달하면 됩니다. 

class Person():
    cash = 1000

    def __init__(self, name, age):
        print('__init__ is called %s ' % name)
        self.name = name
        self.age = age
        Person.cash += 100

    def talk(self):
        print("Hello my age %s" % self.age)

    @classmethod
    def talk_cash(cls):
        print(cls.cash)


vip_investor1 = Person('john lee', 25)
vip_investor1.talk()
vip_investor1.talk_cash()

vip_investor2 = Person('kangcfa', 35)
vip_investor2.talk()
vip_investor1.talk_cash()

 

 

반응형
이 포스팅은 쿠팡파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글