우공이산(愚公移山)

자신과 세상을 바꾸는 것은 머리좋고 가진것이 많은 사람이 아니라 결코 포기하지 않는 의지로 꾸준히 노력해 가는 사람이다. 오늘이 쌓여 내일을 만들고, 내일이 쌓여 인생을 만든다.

Code Story

Class of Python - 클래스 기본적인 사용

보노보노 2022. 1. 26. 16:53
이전글 : 2022.01.25 - [Code Story] - OOP(Object-Oriented Programming) of Python

그럼 지금부터 Python에서 OOP를 하기 위해 class를 생성하는 것부터 시작해 보자!!

1. 클래스란?

  • 클래스는 객체의 구조와 행동을 정의한다. 
  • 객체의 클래스는 초기화를 통해 제어한다.
  • 클래스는 복잡한 문제를 다루기 쉽도록 만든다.

 

2. 클래스 만들기

  • 클래스를 작성하기 위해서는 class 키워드 사용하여 새로운 클래스를 작성한다.
  • 클래스의 네이밍컨벤션은 CamelCase 를 사용한다.
    ( 첫 단어의 첫 문자는 대문자로 시작하며 연이은 단어의 첫 문자를 대문자로 하여 의미의 구문을 짓는다 )
class MyClass:
    def __init__(self, param):
        .......

2-1 클래스 생성 연습

  • 클래스 생성은 아래와 같이 class 키워드 및 클래스의 이름을 입력하여 생성.
class Flight:
    pass
  • 생성한 클래스는 아래와 같이 import할 수 있다.
>>> from airtravel import Flight
>>> Flight
<class 'airtravel.Flight'>
  • 클래스 객체 생성 및 변수에 할당
# 새로운 객체를 생성하기, java나 C# 등의 다른 언어와 다르게 new 키워드가 없다.
>>> f = Flight()
>>> type(f)
<class 'airtravel.Flight'>
  • 클래스 메소드 작성
  • 메소드란 클래스 내의 함수
# 메소드 작성하기
class Flight:
    def number(self):
        return 'SN060'
  • 인스턴스 메소드의 접근
    인스턴스 메소드란 객체에서 호출되어질수 있는 함수를 말한다. 
# 인스턴스의 메소드 사용
>>> from airtravel import Flight
>>> f = Flight()
>>> f.number()
'SN060'
  • 파이썬 메서드의 첫번째 파라미터명은 관례적으로 self라는 이름을 사용.
  • 호출 시 호출한 객체 자신이 전달되기 때문에 self라는 이름을 사용하게 된 것.
  • 이를 이용하면 클래스에서 바로 메소드로 접근하면서 위에서 할당한 Flight의 객체 f를 파라미터로 전달함으로써 똑같은 결과값을 얻을 수 있다.
# 클래스의 내부에 self 파라미터가 포함되는데 이를 이용한 접근법
>>> Flight.number(f) # f는 Flight객체
'SN060'

2-2 생성자와 초기화

  • 위 예제에서 연습했듯 파이썬에서 객체를 생성할때 아래와 같이 생성자를 사용한다.
f = Flight() # 생성자(constructor)
  • 생성자로 객체생성을 호출받으면 먼저 __new__ 를 호출하여 객체를 생성할당하고, __new__ 메소드가 __init__메소드를 호출하여 객체에서 사용할 초기값들을 초기화하게된다.
  • 간혹 여러 자료들을 보면.. __init__ 메소드를 생성자로 소개하는 경우가 있는데, 그렇지 않다.
  • 자료 https://stackoverflow.com/questions/6578487/init-as-a-constructor
  • 일반적으로 파이썬에서 클래스를 만들 시 __init__ 메소드만 오버라이딩하여 객체초기화에만 이용한다.
  • 그럼, 2-1 예제를 조금 수정해보자.
class Flight:

    def __init__(self):
        print('init')
        super().__init__()

    def __new__(cls):
        print('new')
        return super().__new__(cls)

    def number(self):
        return 'SN060'
  • 다시 REPL(컴파일 과정없이 코드를 입력해 결과를 바로 알 수 있는 방식 : >>>_ )에서 객체를 생성해보자.
  • 먼저 __new__가 클래스 자체를 받으며 할당하게되고, __init__가 self를 받으며 객체의 내부에서 사용할 속성을 초기화 합니다.
>>> from airtravel import Flight
>>> f = Flight()
new
init
class Flight:
    def __init__(self, number):
        self._number = number

    def number(self):
        return self._number
  • 다시 REPL에서 확인 합니다.
 >>> from airtravel import Flight
 >>> f = Flight(5)
 >>> f.number()
 5
 >>> f._number
 5

  • Python은 기본적으로 다른언어에 있는 접근제어자(public, private, protected)가 없음
  • 기본적으로 모두 Public

2-3 클래스 초기화 함수(__init__)에 객체의 불변성을 확립하자(유효성검증을 수행)

  • 일반적으로 클래스 초기화 함수(__init__) 에서 객체의 불변성을 확립하는 것이 좋다.
  • 객체 생성시 들어올 값에 대해서 __init__에서 Validation을 수행.
  • 비행기 번호는 앞에 두글자는 영문이어야하며 대문자이다. 그리고 뒤에 세번째 글자부터 마지막까지는 양의 정수여야 한다고 할 때, Flight클래스를 다음과 같이 변경해보자.
  • 객체를 생성시 규칙에 맞지 않는 값이 들어오면 ValueError를 발생시키는 것을 확인할 수 있다.
class Flight:

    def __init__(self, number):
        if not number[:2].isalpha():
            raise ValueError("첫 두글자가 알파벳이 아닙니다.")
        if not number[:2].isupper():
            raise ValueError("첫 두글자가 대문자가 아닙니다.")
        if not number[2:].isdigit():
            raise ValueError("세번째 글자 이상이 양의 숫자가 아닙니다.")
        self._number = number

    ...생략
>>> from airtravel import Flight
>>> f= Flight("abc")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/Blidkaga/Documents/CodeLab/Python_Basic/airtravel.py", line 11, in __init__
    raise ValueError("첫 두글자가 대문자가 아닙니다.")
ValueError: 첫 두글자가 대문자가 아닙니다.
>>> f= Flight("AB0")
>>> f= Flight("AB001")

2-4 비공개 속성

  • 위의 예처럼 _ 언더바 한개는 내부적으로만 사용되는 변수다라고 알리지만, 사실 값을 얻어올수도 있고 할당도 가능하다. 사람들이 '코딩컨벤션'으로 파이썬을 쓰는 사람들이면 내부적인 변수구나 하고 알고 있을 뿐..ㅎㅎ
>>> f= Flight("AB001")
>>> f._number
'AB001'
>>> f._number = 'abc'
>>> f.number()
'abc'
  • 원천적인 접근을 막으려면 __ 더블 언더바를 사용하면 막을 수 있다.
  • 코드를 다시 변경해보겠습니다. _name 변수를 __name으로 변경.
class Flight:

    def __init__(self, number):
        if not number[:2].isalpha():
            raise ValueError("첫 두글자가 알파벳이 아닙니다.")
        if not number[:2].isupper():
            raise ValueError("첫 두글자가 대문자가 아닙니다.")
        if not number[2:].isdigit():
            raise ValueError("세번째 글자 이상이 양의 숫자가 아닙니다.")
        self.__number = number

    def number(self):
        return self.__number

  • 결과를 확인해 보면,
  • number()인스턴스 메소드를 통해서 내부에서는 접근 가능한 모습을 보이나, 객체 f의 속성으로 접근 시 에러가 발생한다.
>>> from airtravel import Flight
>>> f= Flight("AB001")
>>> f.number() 
'AB001'
>>> f.__number
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Flight' object has no attribute '__number'

 

3. 주의!! 파이썬은 메소드 오버로딩이 없다.

  • 메소드 오버로딩이란? : 하나의 클래스 내부에서 메소드 명칭은 똑같고, 인자를 다르게하는 형태를 허용합니다.
  • Java코드는 아래와 같은 코드를 허용합니다.
class Adder{  
    static int add(int a,int b)
    {
        return a+b;
    }  
    static int add(int a,int b,int c)
    {
        return a+b+c;
    }  
}  
  • 파이썬은 메소드 오버로딩이 없다.
  • 아래와 같은 코드가 있다면 첫번째 show는 무시되고, 두번째 show만 유지된다.
class Korea:

    def __init__(self, name, population, captial):
        self.name = name
        self.population = population
        self.capital = captial

    def show(self):
        print(
            """
            국가의 이름은 {} 입니다.
            국가의 인구는 {} 입니다.
            국가의 수도는 {} 입니다.
            """.format(self.name, self.population, self.capital)
        )

    def show(self, abc):
        print('abc :', abc)
  • 결과
>>> from inheritance import *
>>> a = Korea('대한민국',50000000, '서울')
>>> a.show()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: show() missing 1 required positional argument: 'abc'
자, 여기까지 클래스를 정의하고 클래스를 이용해 객체를 생성하여 객체의 메소드를 호출해 보았다. 다음으로 클래스의 속성과 인스턴스 속성의 차이를 살펴보자. 
다음글 : 2022.01.26 - [Code Story] - 클래스 속성과 인스턴스 속성

'Code Story' 카테고리의 다른 글

미디어 컨트롤을 위한 이벤트 발생.  (0) 2022.04.18
클래스 속성과 인스턴스 속성  (0) 2022.01.26
OOP(Object-Oriented Programming) of Python  (1) 2022.01.25
[Admob] eCPM을 높여라  (0) 2021.01.12
[Tistory] 이미지 넣기  (0) 2021.01.10