포스트

파이썬을 다루면서 알게 된 점 몇 가지

파이썬을 다루면서 알게 된 점 몇 가지


클래스 내외부 변수를 구분할 필요가 있다

파이썬에서는 클래스 변수를 선언할 때 self 객체를 이용하는 방법이 일반적이지만 이 방법은 정확히는 인스턴스에서 사용할 내부 변수를 사용하는 방법입니다. 해당 클래스 변수 접근을 위해서는 인스턴스 생성이 필수적으로 요구되기 때문에 모든 객체에서 동일값을 보장해야 하거나, C#이나 Java와 같은 다른 언어의 static 키워드와 비슷한 효과를 의도하고 싶은 경우 등에는 __init__() 함수 외부에 선언해야 합니다.

1
2
3
4
5
6
7
8
9
class Person:
    ''' 아래과 같이 선언할 수 있습니다.
    '''
    type = "person"
    
    def __init__(self):
        self.name = name
        self.age  = age
        # ...

이 변수는 모든 인스턴스에서 동일한 값으로 제공됩니다. 이때 객체에 대한 접근은 심지어 객체 내부에서조차 클래스명.변수명과 같이 이루어짐에 주의해야 할 필요가 있습니다. 예를 들어 위의 People 클래스 내에서 type 변수값을 another_people_type와 같이 수정해야 하는 경우 People.type = another_people_type으로 접근할 수 있습니다.

파이썬도 getter, setter를 사용할 수 있다

C#, Java 등의 언어처럼 gettersetter로 불리는 것은 아니지만, 클래스 내부 변수와 공개용 프로퍼티를 연결한다는 개념은 같습니다. 클래스 내부 변수를 은닉화하는 용도로도 유용하지만 그보다는 어떤 변수의 값이 변경될 때의 로직을 연결할 수 있다는 점에서 더 편리하므로 알아둘 필요가 있습니다.

1
2
3
4
5
6
7
8
9
10
class Example:
    def __init__(self):
        self._variable = None
    
    @property
    def variable(self):
        return self._variable

    @variable.setter(self, value):
        self._variable = value

다른 언어에서 getter만 선언했을 때 읽기 전용으로 동작하는 것과 마찬가지로 @property만 선언하면 해당 프로퍼티로 변수를 수정하려고 할 때 오류가 발생하므로 주의해야 합니다.

모듈명에 클래스 개수를 반영할 수 있다

기본적으로 함수는 코드의 분류 단위, 클래스는 함수와 변수의 분류 단위, 모듈은 클래스의 분류 단위입니다. 이러한 관점을 개념적으로 더 잘 구현하는 방법중 하나는 한 개 모듈에 여러 개의 클래스가 있는 경우 모듈명을 단순히 복수형으로 명기하는 겁니다.

1
2
3
4
5
6
7
8
9
10
11
myproject/
│
├── app/
│   ├── users/
│   │   ├── models.py
│   │   ├── views.py
│   │   └── controllers.py
│   ├── products/
│   └── orders/
│
└── main.py

이때 models.py에는, 실제 프로젝트의 예시가 아니라서 구체적이지는 않지만 예를 들어 UserModel() 또는 ProductModel와 같이 이름 + 유형 형식의 클래스명을 사용할 수 있습니다. 이런 구조는 한 개 모듈에 한 개 클래스가 있을 때에 비해 클래스에 대한 분류가 명확해지고, 모듈을 사용할 때 from models import UserModel as UM와 같이 자연스러운 표현을 사용할 수 있다는 이점이 있습니다.

비유를 쓰는 것 보다는 직관적인 이름이 낫다

비유를 이용하는 경우 그 직관성은 대부분 반쪽짜리입니다. 그 반쪽 덕에 코드를 처음 접헀을 때 동작과정이 간결해지고 읽기가 더 재밌어지기는 하지만, 나머지 반쪽 덕에 코드가 작성된 의도가 모호해진다는 단점이 있어 되도록이면 피하는 것이 옳다고 생각합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def main():
    ''' 보석 세공 장인을 주제로 하면 이런 식
    '''
    self.mining()  
    self.cutting() 
    self.crafting()
    self.selling()

def main()
    ''' 파인다이닝 셰프를 주제로 하면 이런 식
    '''
    self.washing()
    self.cutting()
    self.cooking()
    self.plating()

코드의 전반적인 동작을 위와 같이 보석 판매를 주제삼아 채굴-절삭-세공-판매 과정에 빗대어 표현하거나, 요리사가 요리를 하는 과정을 흉내내어 세척-손질-요리-플레이팅의 구조로 표현하는 등 위의 예시 외에도 몇 가지 비유법을 사용해서 코드를 구조화해봤지만 비유법을 거친 함수명이 코드의 역할을 명확히 반영하지 않는다는 문제가 있었습니다.

이 때문에 의미를 잘 이해하기까지의 과정중 한 단계가 추가되어 타인 또는 미래의 나 자신이 코드를 읽을 때 의미를 직관적으로 이해하기에 불필요한 어려움이 발생했고, 간혹 주객전도가 이루어지는 양 클래스와 함수가 갖고 있는 테마를 의식하며 작성하는 경우도 있었습니다.

대신, 재미는 좀 없더라도 클래스의 역할을 정석적으로 작성하는 것이 깔끔했습니다.

1
2
3
4
5
6
def main():
    ''' 그냥 일반적인 경우
    '''
    download_data()
    basic_process()
    save_results()

사자성어나 유명 일화를 인용하는 등 비유에 있어서 보조관념이 가지는 직관성이 압도적일 경우에는 또 괜찮을 것 같기는 하지만, 이외의 대부분의 경우에는 위와 같이 코드의 동작 자체를 간결히 묘사하는 식으로 작성하는 것이 더 실용적이었습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.