본문 바로가기
컴퓨터 프로그래밍/python

Python 클래스 (Class)

by JaeBaek 2020. 8. 16.

■ 클래스 (Class)

★ 클래스란?

클래스가 많이 헷갈리실 수도 있어서 그림자료와 함께 설명을 하도록 하겠습니다. 그림과 같이 각기 다른 모양의 빵을 만드는 것으로 예시를 들겠습니다. 각각의 반죽틀의 모양은 다르지만 제일 처음에 시작하는 밀가루에 물, 계란 등을 넣고 섞는 과정을 모든 모양에 상관없이 동일합니다. 만약 어떤 누군가가 분명히 다르다고 생각을 하여 하나의 모양마다 소량씩 동일하게 반복을 한다고 생각하면 그 방법은 엄청 비효율적일 것입니다. 결과물인 모양만 다르지 내용문을 동일해서 전체를 대량으로 만들면 되기 때문이죠. 저희가 코딩을 할 때도 계속해서 반복되게 쓰이는 그러한 문장들을 class를 통해서 간단하게 나타낼 수 있습니다.

실제 코딩의 예시를 들기전에 대략적인 문법 설명을 드리도록 하겠습니다. 기본 문법구조는 아래와 같습니다. __init__같은 경우 생성자로서 객체를 초기화하는 역할을 합니다. 즉 간단히 설명하자면 여러 변수를 받아들일 예정인데 그 값들을 정의시킨다고 생각하시면 됩니다. self 같은 경우에는 첫 번째 인수로서 자기 자신을 의미합니다. 사실 다른 단어를 사용해도 되지만 관행적으로 self를 사용하고 있습니다. 멤버 초기화같은 경우에는 계속해서 값들을 사용할 수 있도록 만들어주는 것으로서 self.멤버=초기값 형식으로 대입하면 클래스의 멤버 변수가 됩니다. 그 다음 사용하고 싶은 method를 정의하면 됩니다.

 

class의 문법 구조입니다. 

class 이름:

    def __init__(self,초기화):

        멤버 초기화

    mothod 정의

class

class Human:

    def __init__(self,age,name):

        self.age=age

        self.name=name

    def introduction(self):

        print(str(self.age)+"세 입니다.")

    def introduction2(self):

        print("이름은 " +self.name+" 입니다.")



lee=Human(23,"LeeJaeBaek")

lee.introduction()

lee.introduction2()

result

23세 입니다.
이름은 LeeJaeBaek 입니다.

 

 이 처럼 공통적인 과정에 포함을 시킬 수 있는 것들을 반복적인 과정을 피할 수 있다. 만약 나이, 이름만 다르고 동일한 문장을 계속해서 타이핑해야하는 경우에는 엄청나게 많은 반복적인 문장들이 필요할 것입니다. 그럴경우 미리 class로 선언만 시켜놓으면 간단하게 출력을 할 수 있습니다. 

 

예시에서 보면 제일 마지막에 객체를 생성하는 구문은 다음과 같습니다. 

객체 = 클래스명(인수)

 클래스 이름을 함수처럼 호출하되 인수로 초기값을 전달합니다. 객체를 먼저 생성한 후 이객체를 생성자인 __init__의 첫번 째 인수 self로 전달하고 생성문에서 전달한 인수는 두 번째 이후의 인수로 전달되어 새로 생성되는 객체의 멤버에 대입됩니다. 

 따라서 생성자는 객체 생성 직후에 호출되어 멤버를 초기화하는 중요한 역할을 한다고 볼 수 있습니다. 그리고 method는 기능이 필요할 때마다 추가해서 사용을 할 수 있고, __init__이 있는 함수에서 정의된 인수들은 이후 사용을 할때 self.변수명을 적어서 이용을 해야합니다.

 

★ 상속

상속은 기존 클래스를 확장하여 멤버를 추가하거나 동작을 변경하는 방법입니다. 비슷한 클래스가 있다면 처음부터 다시 만들 필요없이 상속받아 확장 또는 변형을 해서 사용할 수 있습니다. 상속받는 클래스의 구문은 다음과 같습니다.

class 이름(부모):

    .....

상속같은 경우에 아까 빵을 만드는 것에 비유를 하면 빵을 굽는 class를 부모 class 각 틀을 내부 class로 생각하시면 될 것 같습니다. 빵을 굽는 것을 전체 과정이라고 본다면 공통적인 부분을 부모 class에 두고, 각각의 반죽 모양을 결정하는 부분을 자식 class에 해당합니다.

 

 이전에 한 자기소개 영역에서 학번을 말하는 부분을 추가적으로 나타내는 코드를 상속을 사용해서 작성해보도록 하겠습니다.

상속

class Human:

    def __init__(self,age,name):

        self.age=age

        self.name=name

    def introduction(self):

        print(str(self.age)+"세 입니다.")

    def introduction2(self):

        print("이름은 " +self.name+" 입니다.")

 

class Student(Human):

    def __init__(self,age,name,stunum):

        super().__init__(age,name)

        self.stunum=stunum

    def introduction3(self):

        super().introduction()

        print("학번 : "+str(self.stunum))

 

lee=Human(23,"LeeJaeBaek")

lee.introduction2()

lee=Student(23,"LeeJaeBaek",1234567)

lee.introduction3()

result

이름은 LeeJaeBaek 입니다.
23세 입니다.
학번 : 1234567

더 구체적인 특징을 추가하기 위해서 stunum이라는 변수를 추가를 하였습니다. 당연히 stunum은 추가적으로 추가를 하였으므로 self.stunum=stunum을 해야하고, 자식 class에서 부모 class를 호출하기 위해서는 super() method를 사용하시면 됩니다. 

 

 

★ accessor

 python 같은 경우에는 클래스의 멤버가 모두 공개되어 있고, 누구나 외부에서 액세스할 수 있습니다. 따라서 자유롭게 위와 같이 이름을 잘 못 입력해서 다시 변경을 쉽게 할 수 있지만 우발적인 사고로 인해서 잘못된 값을 대입하면 오작동의 원인이 될 수 있습니다.

 이에 대한 해결법으로 무작위 값에 대한 입력을 받는 것 보다는 일정한 규칙을 마련하고 안전하게 액세스하도록 해야 합니다. 그 방법으로는 멤버 값을 대신 읽어주는 Getter method와 변경해주는 Setter method를 정의를 해줍니다. 

 

1부터 10까지의 수만 출력을 하는 프로그램을 코딩해보도록 하겠습니다. 답은 1과 10사이의 수이므로 그 외의 수는 출력이 되지 않도록 하면 getter와 setter를 이용하여 각 값을 비교해서 맞는지 봐줘야 합니다.

setter, getter

class Number:

    def __init__(self,num):

        self.num=num

    def getnum(self):

        return self.num

    def setnum(self,num):

        if 1<=num<=10:

            self.num=num

 

n=Number(1)

n.setnum(12)

print(n.getnum())

result

1

위 코딩은 setnum 함수를 통해서 값이 1~10 인지 확인으로 하고 self.num으로 값을 넘겨 줍니다. 그 넘겨준 값을 getnum을 통해서 출력을 하는 방식입니다. 하지만 이 방법이 완벽하지는 않습니다. 따라서 getter, setter를 정의하고 property(getter, setter) 형식으로 하시면 됩니다. 

 

property

class Number:

    def __init__(self,num):

        self.num=num

    def getnum(self):

        return self.num

    def setnum(self,num):

        if 1<=num<=10:

            self.num=num

    numb=property(getnum,setnum)

 

n=Number(8)

n.numb=12

print(n.numb)

result

8

 

 위 두 가지의 기능이 완벽하다고는 할 수 없습니다. 첫 번째 같은 경우에는 값을 "n.num= 숫자" 의 형식으로 값을 넣어버리면 1~10 이외의 숫자가 올 수 있고, 두 번째 같은 경우에는 "n.numb=숫자" 를 대입하면 이외의 숫자가 올 수 있기 때문입니다.

 

 보통 변수이름을 알고 있는 경우에는 그런 실수를 하지 않지만, 많은 양의 코드를 작성할 때 이름들을 전부 기억하지 못하기 때문에 중간에 값을 함부로 바꾸기 쉽습니다. 따라서 숨겨진 멤버의 이름을 __로 시작을 하면 이 멤버를 바로 참조하지 못하도록 특수 문자를 붙입니다. 

 python이 언어 차원에서 정보 은폐를 지원하지 않기 때문에 여러 가지 방법이 동원이 됩니다. 그렇다고 너무 복잡한 방법까지는 쓸 필요가 없고, getter, setter정도만 적절히 작성을 해도 어느 정도 안정성 있게 코딩을 할 수 있을 거라 생각합니다.

 

 

■ 각종 method

★ class method

classmethod는 특정 개체에 대해 작업을 차리하는 것이 아니라 클래스 전체가 공유합니다. 따라서 함수 앞에 @classmethod decorator를 붙이고 첫 번쨰 인수로 클래스에 해당하는 cls인수를 받아들입니다.  기본적인 구조는 다음과 같습니다. 

class 클래스 이름:

    @classmethod

    def 이름(cls, 매개변수1 .... ) 

        code....

 

classmethod

class Car:

    count=0

    def __init__(self,name):

        self.name=name

        Car.count+=1 # Car의 class에 count라는 변수를 누적

    @classmethod

    def outcount(cls):

        print(cls.count)  # cls 로서 class 속성에 접근

Porsche=Car("Porsche")

BMW=Car("BMW")

Car.outcount()

result

2

 

 

★ 정적 (static method)

정적 method는 클래스 method와는 다르게 특정 객체에 소속되지 않고 클래스와 관련된 동작을 하는 것도 아니어서 self나 cls를 인수로 받지 않습니다. 클래스 또는 객체와는 직접적인 연관이 없기 때문에 단순히 클래스에 소속되어 있어서 객체가 전혀 없어도 호출할 수 있습니다. 객체와 상관없는 아주 일반적인 동작만 가능합니다. 클래스에 포함되어 있으므로 호출할 때는 클래스명.method() 식으로 호출합니다.

 

간단하게 사칙연산을 하는 프로그램을 클래스 내에 포함시켜보도록 하겠습니다.

staticmethod

class Cals:

    @staticmethod

    def add(a,b):

        print("%d + %d = %d"%(a,b,a+b))

    

    @staticmethod

    def sub(a,b):

        print("%d - %d = %d"%(a,b,a-b))

    

    @staticmethod

    def mul(a,b):

        print("%d * %d = %d"%(a,b,a*b))

    

    @staticmethod

    def div(a,b):

        print("%d / %d = %f"%(a,b,a/b))

 

Cals.add(2,3)

Cals.sub(2,3)

Cals.mul(2,3)

Cals.div(2,3)

result

2 + 3 = 5
2 - 3 = -1
2 * 3 = 6
2 / 3 = 0.666667

 

 

 

 

'컴퓨터 프로그래밍 > python' 카테고리의 다른 글

Python 모듈, 패키지  (0) 2020.08.16
Python 파일 (file)  (0) 2020.08.14
Python 예외 처리 (exception process)  (0) 2020.08.14
Python 표준 모듈  (0) 2020.08.13
Python 컬렉션(Collection)  (0) 2020.08.13

댓글