본문 바로가기
Programming Language/Python

Effective Python. 메타클래스로 클래스 속성에 주석을 달자.

by 알파해커 2021. 3. 3.
반응형

메타클래스와 디스크립터를 활용하면, 중복 코드를 좀 더 줄이고 깔끔한 코드를 만들 수 있다.

아래와 같은 Field 디스크립터가 있다고 가정해보자.

class Field:
    def __init__(self, name):
        self.name = name
        self.internal_name = '_' + self.name
        
    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return getattr(instance, self.internal_name, '')
    
    def __set__(self, instance, value):
        setattr(instance, self.instance_name, value)

 

그리고, Field 디스크립터를 이용해, Customer 클래스의 각 속성 값을 만든다면 다음과 같이 만들어 질 것이다.

class Customer:
    first_name = Field('first_name')
    last_name = Field('last_name')
    prefix = Field('prefix')
    suffix = Field('suffix')

 

그러나, fisrt_name 이라는 속성명과

해당 속성을 만들어주기 위한 Field 디스크립터의 파라미터로 넘기는 'first_name'이라는 문자열이 중복처럼 느껴진다.

(last_name, prefix, suffix 모두 마찬가지)

 

이 중복을 제거할때 메타클래스를 활용할 수 있다.

아래와 같이, 인스턴스의 속성이 디스크립터(Field)인 경우, 해당 디스크립터 인스턴스의 속성에 접근하여 값을 할당하면 된다.

class Meta(type):
    def __new__(meta, name, bases, class_dict):
        for key, value in class_dict.items():
            if isinstance(value, Field):
                value.name = key
                value.internal_name = '_' + key
        cls = type.__new__(meta, name, bases, class_dict)
        return cls

 

이렇게 만든 메타클래스를 이용하여 기반클래스를 만들고(여기서는 DatabaseRow라는 이름의 기반 클래스를 만들어보자).

그 후, 만들어진 기반클래스를 이용하여, 원래 만들고자 했던 Customer 클래스를 만들면 된다.

class DatabaseRow(metaclass=Meta):
    pass
    

class BetterCustomer(DatabaseRow):
    first_name = Field()
    last_name = Field()
    prefix = Field()
    suffix = Field()

 

반응형

댓글