Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 681 – 데이터 클래스 변환

Author:
Erik De Bonte <erikd at microsoft.com>, Eric Traut <erictr at microsoft.com>
Sponsor:
Jelle Zijlstra <jelle.zijlstra at gmail.com>
Discussions-To:
Typing-SIG thread
Status:
Final
Type:
Standards Track
Topic:
Typing
Created:
02-Dec-2021
Python-Version:
3.11
Post-History:
24-Apr-2021, 13-Dec-2021, 22-Feb-2022
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Important

This PEP is a historical document: see The dataclass_transform decorator and @typing.dataclass_transform for up-to-date specs and documentation. Canonical typing specs are maintained at the typing specs site; runtime typing behaviour is described in the CPython documentation.

×

See the typing specification update process for how to propose changes to the typing spec.

초록

PEP 557은 Python 표준 라이브러리에 데이터 클래스를 도입했습니다. 여러 인기 라이브러리가 데이터 클래스와 유사한 동작을 제공하지만, 이러한 동작은 표준 타입 어노테이션으로 설명할 수 없습니다. 이러한 프로젝트에는 attrs, pydantic, 그리고 SQLAlchemy와 Django 같은 객체 관계 매퍼(ORM) 패키지가 포함됩니다.

대부분의 타입 검사기, 린터 및 언어 서버는 데이터 클래스를 완전히 지원합니다. 이 제안은 이 기능을 일반화하고, 특정 데코레이터 함수, 클래스 및 메타클래스가 데이터 클래스와 유사한 동작을 제공한다는 사실을 서드파티 라이브러리가 나타낼 방법을 제공하는 것을 목표로 합니다.

이러한 동작에는 다음이 포함됩니다.

  • 선언된 데이터 필드를 기반으로 __init__ 메서드를 합성합니다.
  • 선택적으로 __eq__, __ne__, __lt__, __le__, __gt____ge__ 메서드를 합성합니다.
  • 정적 타입 검사 중 불변성을 강제하는 방법인 “frozen” 클래스 지원
  • “필드 지정자” 지원. 이는 정적 타입 검사기가 각 필드의 속성 중 해당 필드에 기본값이 제공되는지 여부와 같이 알아야 하는 사항을 설명합니다.

표준 라이브러리 데이터 클래스의 전체 동작은 Python documentation에 설명되어 있습니다.

이 제안은 typing.pydataclass_transform 데코레이터를 추가하는 것을 제외하면 CPython에 직접 영향을 주지 않습니다.

동기

데이터 클래스와 유사한 의미 체계를 가진 라이브러리가 타입 검사기에 자신의 동작을 선언할 수 있는 기존의 표준 방법은 없습니다. 이러한 제한을 우회하기 위해 여러 라이브러리용 Mypy 사용자 정의 플러그인이 개발되었지만, 이러한 플러그인은 다른 타입 검사기, 린터 또는 언어 서버에서 작동하지 않습니다. 또한 이러한 플러그인은 라이브러리 작성자가 유지 관리하기에 비용이 많이 들며, Python 개발자가 이러한 플러그인의 존재를 알고 자신의 환경에 다운로드하여 구성해야 합니다.

근거

이 제안의 목적은 데이터 클래스와 유사한 의미 체계를 가진 모든 라이브러리의 모든 기능을 지원하는 것이 아니라, 이러한 라이브러리의 가장 일반적인 기능을 정적 타입 검사와 호환되는 방식으로 사용할 수 있게 하는 것입니다. 사용자가 이러한 라이브러리를 중요하게 여기면서 정적 타입 검사도 중요하게 여긴다면, 특정 기능의 사용을 피하거나 사용 방식을 조금 조정해야 할 수 있습니다. 모든 데이터 클래스 유사 라이브러리의 모든 기능을 지원하지 않는 Mypy 사용자 정의 플러그인에도 이미 같은 제약이 있습니다.

향후 데이터 클래스에 새로운 기능이 추가되면, 적절한 경우 해당 기능을 dataclass_transform에도 지원할 예정입니다. 이 두 기능 집합을 동기화하면 데이터 클래스 사용자가 dataclass_transform을 이해하고 사용하기 쉬워지며, 타입 검사기에서 데이터 클래스 지원을 유지 관리하는 일도 간소화됩니다.

또한 여러 서드파티 라이브러리에서 채택되었지만 데이터 클래스에서는 지원되지 않는 기능에 대해 향후 dataclass_transform 지원을 추가하는 것도 고려할 예정입니다.

사양

dataclass_transform 데코레이터

이 사양은 typing 모듈에 dataclass_transform이라는 새 데코레이터 함수를 도입합니다. 이 데코레이터는 그 자체가 데코레이터인 함수, 클래스 또는 메타클래스에 적용할 수 있습니다. dataclass_transform의 존재는 정적 타입 검사기에게 데코레이트된 함수, 클래스 또는 메타클래스가 런타임 “마법”을 수행하여 클래스를 변환하고 데이터 클래스와 유사한 동작을 부여한다는 것을 알립니다.

dataclass_transform이 함수에 적용되면, 데코레이트된 함수를 데코레이터로 사용하는 경우 dataclass와 유사한 의미가 적용되는 것으로 가정합니다. 함수에 오버로드가 있는 경우, dataclass_transform 데코레이터는 함수의 구현 또는 오버로드 중 하나에 적용할 수 있지만, 둘 이상의 오버로드에 적용할 수는 없습니다. 오버로드에 적용되는 경우에도 dataclass_transform 데코레이터는 해당 함수의 모든 사용에 영향을 줍니다.

dataclass_transform이 클래스에 적용되면, 데코레이트된 클래스에서 직접 또는 간접적으로 파생되거나 데코레이트된 클래스를 메타클래스로 사용하는 모든 클래스에 dataclass와 유사한 의미가 적용되는 것으로 가정합니다. 데코레이트된 클래스와 그 베이스 클래스의 속성은 필드로 간주되지 않습니다.

각 접근 방식의 예는 다음 섹션에 나와 있습니다. 각 예에서는 dataclass와 유사한 의미를 갖는 CustomerModel 클래스를 생성합니다. 간결성을 위해 데코레이트된 객체의 구현은 생략하지만, 다음과 같은 방식으로 클래스를 수정한다고 가정합니다.

  • 클래스와 부모 클래스 내부에 선언된 데이터 필드를 사용하여 __init__ 메서드를 생성합니다.
  • __eq____ne__ 메서드를 생성합니다.

이 PEP를 지원하는 타입 검사기는 합성된 __init__ 메서드를 사용하여 CustomerModel 클래스를 인스턴스화할 수 있음을 인식합니다.

# Using positional arguments
c1 = CustomerModel(327, "John Smith")

# Using keyword arguments
c2 = CustomerModel(id=327, name="John Smith")

# These calls will generate runtime errors and should be flagged as
# errors by a static type checker.
c3 = CustomerModel()
c4 = CustomerModel(327, first_name="John")
c5 = CustomerModel(327, "John Smith", 0)

데코레이터 함수 예

_T = TypeVar("_T")

# The ``create_model`` decorator is defined by a library.
# This could be in a type stub or inline.
@typing.dataclass_transform()
def create_model(cls: Type[_T]) -> Type[_T]:
    cls.__init__ = ...
    cls.__eq__ = ...
    cls.__ne__ = ...
    return cls

# The ``create_model`` decorator can now be used to create new model
# classes, like this:
@create_model
class CustomerModel:
    id: int
    name: str

클래스 예

# The ``ModelBase`` class is defined by a library. This could be in
# a type stub or inline.
@typing.dataclass_transform()
class ModelBase: ...

# The ``ModelBase`` class can now be used to create new model
# subclasses, like this:
class CustomerModel(ModelBase):
    id: int
    name: str

메타클래스 예

# The ``ModelMeta`` metaclass and ``ModelBase`` class are defined by
# a library. This could be in a type stub or inline.
@typing.dataclass_transform()
class ModelMeta(type): ...

class ModelBase(metaclass=ModelMeta): ...

# The ``ModelBase`` class can now be used to create new model
# subclasses, like this:
class CustomerModel(ModelBase):
    id: int
    name: str

데코레이터 함수 및 클래스/메타클래스 매개변수

dataclass와 유사한 기능을 제공하는 데코레이터 함수, 클래스 또는 메타클래스는 특정 동작을 수정하는 매개변수를 받을 수 있습니다. 이 명세에서는 dataclass 변환에 사용되는 경우 정적 타입 검사기가 준수해야 하는 다음 매개변수를 정의합니다. 각 매개변수는 bool 인자를 받으며, bool 값(True 또는 False)을 정적으로 평가할 수 있어야 합니다.

  • eq, order, frozen, initunsafe_hash는 표준 라이브러리 dataclass에서 지원되는 매개변수이며, 그 의미는 PEP 557에 정의되어 있습니다.
  • kw_only, match_argsslots는 표준 라이브러리 dataclass에서 지원되는 매개변수이며, Python 3.10에서 처음 도입되었습니다.

dataclass_transform 매개변수

dataclass_transform에 대한 매개변수를 사용하면 기본 동작을 일부 기본적으로 사용자 지정할 수 있습니다.

_T = TypeVar("_T")

def dataclass_transform(
    *,
    eq_default: bool = True,
    order_default: bool = False,
    kw_only_default: bool = False,
    field_specifiers: tuple[type | Callable[..., Any], ...] = (),
    **kwargs: Any,
) -> Callable[[_T], _T]: ...
  • eq_default는 호출자가 eq 매개변수를 생략한 경우 해당 매개변수가 True로 가정되는지 False로 가정되는지를 나타냅니다. 지정하지 않으면 eq_default는 True로 기본 설정됩니다(dataclass의 기본 가정).
  • order_default는 호출자가 order 매개변수를 생략한 경우 해당 매개변수가 True로 가정되는지 False로 가정되는지를 나타냅니다. 지정하지 않으면 order_default는 False로 기본 설정됩니다(dataclass의 기본 가정).
  • kw_only_default는 호출자가 kw_only 매개변수를 생략한 경우 해당 매개변수가 True로 가정되는지 False로 가정되는지를 나타냅니다. 지정하지 않으면 kw_only_default는 False로 기본 설정됩니다(dataclass의 기본 가정).
  • field_specifiers는 필드를 설명하는 지원되는 클래스의 정적 목록을 지정합니다. 일부 라이브러리는 필드 지정자의 인스턴스를 할당하는 함수도 제공하며, 이러한 함수도 이 튜플에 지정할 수 있습니다. 지정하지 않으면 field_specifiers는 빈 튜플로 기본 설정됩니다(지원되는 필드 지정자 없음). 표준 dataclass 동작은 Field라는 하나의 필드 지정자 유형과 이 클래스를 인스턴스화하는 도우미 함수(field)만 지원하므로, 표준 라이브러리 dataclass 동작을 설명한다면 튜플 인자 (dataclasses.Field, dataclasses.field)를 제공합니다.
  • kwargs를 사용하면 임의의 추가 키워드 인자를 dataclass_transform에 전달할 수 있습니다. 이를 통해 타입 검사기는 typing.py의 변경을 기다릴 필요 없이 실험적 매개변수를 지원할 수 있습니다. 타입 검사기는 인식할 수 없는 모든 매개변수에 대해 오류를 보고해야 합니다.

앞으로 사용자 코드에서 일반적으로 사용되는 동작을 지원하는 데 필요한 경우 dataclass_transform에 추가 매개변수를 추가할 수 있습니다. 이러한 추가는 추가 PEP를 작성하는 대신 typing-sig에서 합의에 도달한 후 이루어집니다.

다음 섹션에서는 이러한 매개변수가 사용되는 방법을 보여 주는 추가 예제를 제공합니다.

데코레이터 함수 예제

# Indicate that the ``create_model`` function assumes keyword-only
# parameters for the synthesized ``__init__`` method unless it is
# invoked with ``kw_only=False``. It always synthesizes order-related
# methods and provides no way to override this behavior.
@typing.dataclass_transform(kw_only_default=True, order_default=True)
def create_model(
    *,
    frozen: bool = False,
    kw_only: bool = True,
) -> Callable[[Type[_T]], Type[_T]]: ...

# Example of how this decorator would be used by code that imports
# from this library:
@create_model(frozen=True, kw_only=False)
class CustomerModel:
    id: int
    name: str

클래스 예제

# Indicate that classes that derive from this class default to
# synthesizing comparison methods.
@typing.dataclass_transform(eq_default=True, order_default=True)
class ModelBase:
    def __init_subclass__(
        cls,
        *,
        init: bool = True,
        frozen: bool = False,
        eq: bool = True,
        order: bool = True,
    ):
        ...

# Example of how this class would be used by code that imports
# from this library:
class CustomerModel(
    ModelBase,
    init=False,
    frozen=True,
    eq=False,
    order=False,
):
    id: int
    name: str

메타클래스 예제

# Indicate that classes that use this metaclass default to
# synthesizing comparison methods.
@typing.dataclass_transform(eq_default=True, order_default=True)
class ModelMeta(type):
    def __new__(
        cls,
        name,
        bases,
        namespace,
        *,
        init: bool = True,
        frozen: bool = False,
        eq: bool = True,
        order: bool = True,
    ):
        ...

class ModelBase(metaclass=ModelMeta):
    ...

# Example of how this class would be used by code that imports
# from this library:
class CustomerModel(
    ModelBase,
    init=False,
    frozen=True,
    eq=False,
    order=False,
):
    id: int
    name: str

필드 지정자

데이터클래스와 유사한 의미 체계를 지원하는 대부분의 라이브러리는 클래스 정의에서 클래스의 각 필드에 대한 추가 메타데이터를 제공할 수 있도록 하나 이상의 “필드 지정자” 타입을 제공합니다. 이 메타데이터는 예를 들어 기본값을 설명하거나, 필드를 합성된 __init__ 메서드에 포함해야 하는지를 나타낼 수 있습니다.

추가 메타데이터가 필요하지 않은 경우에는 필드 지정자를 생략할 수 있습니다:

@dataclass
class Employee:
    # Field with no specifier
    name: str

    # Field that uses field specifier class instance
    age: Optional[int] = field(default=None, init=False)

    # Field with type annotation and simple initializer to
    # describe default value
    is_paid_hourly: bool = True

    # Not a field (but rather a class variable) because type
    # annotation is not provided.
    office_number = "unassigned"

필드 지정자 매개변수

데이터클래스와 유사한 의미 체계를 지원하고 필드 지정자 클래스를 제공하는 라이브러리는 일반적으로 필드 지정자를 생성할 때 공통 매개변수 이름을 사용합니다. 이 사양은 정적 타입 검사기가 이해해야 하는 매개변수의 이름과 의미를 공식화합니다. 이러한 표준화된 매개변수는 키워드 전용이어야 합니다.

이러한 매개변수는 dataclasses.field이 지원하는 매개변수의 상위 집합이며, comparehash와 같이 타입 검사에 영향을 주지 않는 매개변수는 제외합니다.

필드 지정자 클래스는 생성자에서 다른 매개변수를 사용할 수 있으며, 이러한 매개변수는 위치 인자일 수 있고 다른 이름을 사용할 수도 있습니다.

  • init은 필드를 합성된 __init__ 메서드에 포함해야 하는지를 나타내는 선택적 bool 매개변수입니다. 지정하지 않으면 init의 기본값은 True입니다. 필드 지정자 함수는 리터럴 bool 값 타입(Literal[False] 또는 Literal[True])을 사용하여 init의 값을 암시적으로 지정하는 오버로드를 사용할 수 있습니다.
  • default는 필드의 기본값을 제공하는 선택적 매개변수입니다.
  • default_factory는 필드의 기본값을 반환하는 런타임 콜백을 제공하는 선택적 매개변수입니다. defaultdefault_factory중 어느 것도 지정하지 않으면 필드에 기본값이 없는 것으로 간주되며, 클래스를 인스턴스화할 때 값을 제공해야 합니다.
  • factorydefault_factory의 별칭입니다. 표준 라이브러리의 dataclasses는 default_factory라는 이름을 사용하지만, attrs는 많은 경우 factory라는 이름을 사용하므로 attrs를 지원하려면 이 별칭이 필요합니다.
  • kw_only는 필드를 키워드 전용으로 표시할지를 나타내는 선택적 bool 매개변수입니다. true이면 필드는 키워드 전용이 됩니다. false이면 필드는 키워드 전용이 되지 않습니다. 지정하지 않으면 dataclass_transform으로 데코레이트된 객체의 kw_only매개변수 값이 사용되며, 해당 값도 지정되지 않은 경우 dataclass_transformkw_only_default값이 사용됩니다.
  • alias는 필드의 대체 이름을 제공하는 선택적 str 매개변수입니다. 이 대체 이름은 합성된 __init__ 메서드에서 사용됩니다.

default, default_factoryfactory 중 둘 이상을 지정하면 오류입니다.

다음 예는 위의 내용을 보여줍니다:

# Library code (within type stub or inline)
# In this library, passing a resolver means that init must be False,
# and the overload with Literal[False] enforces that.
@overload
def model_field(
        *,
        default: Optional[Any] = ...,
        resolver: Callable[[], Any],
        init: Literal[False] = False,
    ) -> Any: ...

@overload
def model_field(
        *,
        default: Optional[Any] = ...,
        resolver: None = None,
        init: bool = True,
    ) -> Any: ...

@typing.dataclass_transform(
    kw_only_default=True,
    field_specifiers=(model_field, ))
def create_model(
    *,
    init: bool = True,
) -> Callable[[Type[_T]], Type[_T]]: ...

# Code that imports this library:
@create_model(init=False)
class CustomerModel:
    id: int = model_field(resolver=lambda : 0)
    name: str

런타임 동작

런타임에 dataclass_transform데코레이터가 수행하는 유일한 작업은 인트로스펙션을 지원하도록 데코레이터가 적용된 함수 또는 클래스에 __dataclass_transform__라는 이름의 속성을 설정하는 것입니다. 이 속성의 값은 dataclass_transform의 매개변수 이름을 해당 값에 매핑하는 딕셔너리여야 합니다.

예를 들면 다음과 같습니다:

{
  "eq_default": True,
  "order_default": False,
  "kw_only_default": False,
  "field_specifiers": (),
  "kwargs": {}
}

데이터클래스 의미 체계

이 PEP에서 달리 명시된 경우를 제외하면, dataclass_transform의 영향을 받는 클래스는 dataclass_transform로 데코레이트된 클래스를 상속하거나 dataclass_transform로 데코레이트된 함수로 데코레이트되는 경우 모두 stdlib dataclass처럼 동작하는 것으로 간주합니다.

여기에는 다음 의미 체계가 포함되지만, 이에 국한되지는 않습니다:

  • 동결된 데이터클래스는 동결되지 않은 데이터클래스를 상속할 수 없습니다. dataclass_transform이 적용된 클래스는 동결되지도 동결되지 않은 것도 아닌 것으로 간주되므로, 동결된 클래스가 이를 상속할 수 있습니다. 마찬가지로, dataclass_transform이 적용된 메타클래스를 직접 지정하는 클래스도 동결되지도 동결되지 않은 것도 아닌 것으로 간주됩니다.

    다음 클래스 예를 살펴보십시오:

    # ModelBase is not considered either "frozen" or "non-frozen"
    # because it is decorated with ``dataclass_transform``
    @typing.dataclass_transform()
    class ModelBase(): ...
    
    # Vehicle is considered non-frozen because it does not specify
    # "frozen=True".
    class Vehicle(ModelBase):
        name: str
    
    # Car is a frozen class that derives from Vehicle, which is a
    # non-frozen class. This is an error.
    class Car(Vehicle, frozen=True):
        wheel_count: int
    

    다음과 유사한 메타클래스 예도 살펴보십시오:

    @typing.dataclass_transform()
    class ModelMeta(type): ...
    
    # ModelBase is not considered either "frozen" or "non-frozen"
    # because it directly specifies ModelMeta as its metaclass.
    class ModelBase(metaclass=ModelMeta): ...
    
    # Vehicle is considered non-frozen because it does not specify
    # "frozen=True".
    class Vehicle(ModelBase):
        name: str
    
    # Car is a frozen class that derives from Vehicle, which is a
    # non-frozen class. This is an error.
    class Car(Vehicle, frozen=True):
        wheel_count: int
    
  • 필드 순서와 상속은 557에 지정된 규칙을 따른다고 가정합니다. 여기에는 재정의의 효과도 포함됩니다(부모 클래스에 이미 정의된 필드를 자식 클래스에서 다시 정의하는 경우입니다).
  • PEP 557 indicates는 기본값이 없는 모든 필드가 기본값이 있는 필드보다 먼저 나와야 한다고 명시합니다. PEP 557에 명시적으로 언급되지는 않았지만 init=False인 경우에는 이 규칙을 무시하며, 이 명세도 해당 상황에서는 이 요구 사항을 무시합니다. 마찬가지로 __init__에 키워드 전용 매개변수를 사용하는 경우에는 이 순서를 적용할 필요가 없으므로, kw_only의미 체계가 적용되면 이 규칙을 적용하지 않습니다.
  • dataclass와 마찬가지로, 클래스 내부에 명시적으로 선언된 메서드를 덮어쓰게 된다면 메서드 합성을 건너뜁니다. 기본 클래스의 메서드 선언은 메서드 합성을 건너뛰게 하지 않습니다.

    예를 들어 클래스가 __init__메서드를 명시적으로 선언하면 해당 클래스에 __init__메서드가 합성되지 않습니다.

  • KW_ONLY 센티널 값은 the Python docsbpo-43532에 설명된 대로 지원됩니다.
  • ClassVar 속성은 데이터클래스 필드로 간주되지 않으며, ignored by dataclass mechanisms로 처리됩니다.

정의되지 않은 동작

하나의 함수(오버로드 포함), 하나의 클래스 또는 클래스 계층 구조 내에서 여러 dataclass_transform데코레이터가 발견되는 경우 결과 동작은 정의되지 않습니다. 라이브러리 작성자는 이러한 상황을 피해야 합니다.

참조 구현

Pyrightdataclass_transform에 대한 타입 검사기 지원의 참조 구현을 포함합니다. Pyright의 dataClasses.ts source file는 구현을 이해하기 위한 좋은 출발점이 될 것입니다.

attrspydantic 라이브러리는 dataclass_transform을 사용하며, 실제 사례에서의 사용 예를 제공합니다.

거부된 아이디어

auto_attribs 매개변수

attrs 라이브러리는 PEP 526 변수 어노테이션으로 장식되었지만 할당이 없는 클래스 멤버를 데이터 필드로 처리할지 나타내는 auto_attribs 매개변수를 지원합니다.

auto_attribs와 이에 대응하는 auto_attribs_default 매개변수의 지원을 고려했지만, 이는 attrs에만 해당하므로 지원하지 않기로 결정했습니다.

Django는 타입 어노테이션만 사용하여 필드를 선언하는 것을 지원하지 않으므로, dataclass_transform을 활용하는 Django 사용자는 항상 할당된 값을 제공해야 한다는 점을 알고 있어야 합니다.

cmp 매개변수

attrs 라이브러리는 eqorder를 모두 True로 설정하는 것과 동일한 불리언 매개변수 cmp를 지원합니다. cmp 매개변수는 attrs에만 적용되므로 이를 지원하지 않기로 결정했습니다. 사용자는 대신 eqorder 매개변수 이름을 사용하여 cmp 동작을 모방할 수 있습니다.

자동 필드 이름 별칭 지정

attrs 라이브러리는 단일 밑줄로 시작하는 필드 이름에 대해 automatic aliasing을 수행하여, 해당 __init__매개변수 이름에서 밑줄을 제거합니다.

이 동작은 attrs에만 해당하므로 이 제안에서는 제외합니다. 사용자는 alias 매개변수를 사용하여 이러한 필드에 별칭을 수동으로 지정할 수 있습니다.

대체 필드 순서 지정 알고리즘

attrs 라이브러리는 현재 클래스 내 필드의 순서를 지정하는 두 가지 방식을 지원합니다.

  • 데이터클래스 순서: 데이터클래스에서 사용하는 것과 동일한 순서입니다. 이는 이전 API(예: attr.s)의 기본 동작입니다.
  • 메서드 결정 순서(MRO): 이는 최신 API(예: define, mutable, frozen)의 기본 동작입니다. 이전 API(예: attr.s)는 collect_by_mro=True를 지정하여 이 동작을 선택할 수 있습니다.

결과로 생성되는 필드 순서는 특정 다이아몬드 형태의 다중 상속 시나리오에서 서로 다를 수 있습니다.

단순성을 위해 이 제안에서는 데이터클래스에서 사용하는 것 이외의 필드 순서를 지원하지 않습니다.

서브클래스에서 다시 선언된 필드

attrs 라이브러리는 서브클래스에서 다시 선언된 상속 필드를 처리하는 방식에서 표준 라이브러리 데이터클래스와 다릅니다. 데이터클래스 사양은 원래 순서를 유지하지만, attrs는 서브클래스를 기반으로 새로운 순서를 정의합니다.

단순성을 위해 데이터클래스 동작만 지원하기로 결정했습니다. attrs에 특화된 순서에 의존하는 attrs 사용자는 생성된 __init__ 메서드에서 예상한 매개변수 순서를 확인할 수 없습니다.

Django 기본 키 및 외래 키

Django는 기본 키와 외래 키에 대해 additional logic for primary and foreign keys을 적용합니다. 예를 들어 기본 키로 지정된 필드가 없으면 id필드와 __init__매개변수를 자동으로 추가합니다.

이는 데이터클래스 라이브러리에 광범위하게 적용되는 사항이 아니므로 이 제안에서는 이러한 추가 로직을 수용하지 않습니다. 따라서 Django 사용자는 id필드를 명시적으로 선언해야 합니다.

클래스 전체 기본값

SQLAlchemy는 변환된 클래스의 모든 필드에 대한 기본값이 None임을 지정하는 방법을 공개해 달라고 요청했습니다. 일반적으로 SQLAlchemy의 모든 필드는 선택 사항이며, None은 해당 필드가 설정되지 않았음을 나타냅니다.

이 기능은 SQLAlchemy에 특화되어 있으므로 지원하지 않기로 했습니다. 대신 사용자는 이러한 필드에 default=None을 수동으로 설정할 수 있습니다.

디스크립터 타입 필드 지원

SQLAlchemy에서 흔히 사용되는 디스크립터 타입 필드를 더 잘 지원할 수 있도록 dataclass_transform에 불리언 매개변수를 추가하는 방안을 고려했습니다. 활성화하면 디스크립터 타입 필드에 해당하는 합성된 __init__ 메서드의 각 매개변수 타입은 디스크립터 타입 자체가 아니라 디스크립터의 __set__ 메서드에 대한 값 매개변수의 타입이 됩니다. 마찬가지로 필드를 설정할 때는 __set__의 값 타입이 예상됩니다. 또한 필드의 값을 가져올 때는 해당 필드의 타입이 __get__의 반환 타입과 일치할 것으로 예상됩니다.

이 아이디어는 dataclass가 디스크립터 타입 필드를 제대로 지원하지 않는다는 믿음에 기반했습니다. 실제로는 지원하지만, 타입 검사기(적어도 mypy와 pyright)가 런타임 동작을 반영하지 않았으며, 이로 인해 잘못 이해하게 되었습니다. 자세한 내용은 Pyright 버그를 참조하십시오.

converter 필드 지정자 매개변수

attrs 라이브러리는 converter 필드 지정자 매개변수를 지원하며, 이는 생성된 __init__ 메서드가 제공된 값을 원하는 다른 값으로 변환하기 위해 호출하는 Callable인 호출 가능 객체입니다. 합성된 __init__ 메서드의 매개변수 타입은 아직 파악되지 않은 값을 허용해야 하지만, 결과 필드는 변환기의 출력에 따라 타입이 지정되므로 이를 지원하기가 까다롭습니다.

이 문제의 일부 측면은 Pyright 토론에서 자세히 설명합니다.

입력 매개변수의 타입을 도출할 정보가 충분하지 않으므로 이를 지원하는 좋은 방법이 없을 수 있습니다. 한 가지 가능한 해결책은 converter 필드 지정자 매개변수에 대한 지원을 추가하되, __init__ 메서드에서 이에 해당하는 매개변수에 Any 타입을 사용하는 것입니다.

참조사항