在Python数据类中仅使用关键字参数
Use keyword-only arguments in Python dataclasses

原始链接: https://chipx86.blog/2025/06/29/tip-use-keyword-only-arguments-in-python-dataclasses/

Python数据类简化了数据保存类,与字典(方法、子类)和手动类(自动`__init__`、`__eq__`)相比具有优势。为了可维护性,在数据类定义过程中始终使用`kw_only=True `。这强制使用仅关键字参数,如“MyDataClass(x=1,y='foo',z=False)”,而不是位置参数(“MyDataClass(1,'foo'),False)”。 好处包括: 1.**重新排序灵活性:**如果更改数据类字段的顺序,请避免破坏现有代码。关键字参数可防止位置相关问题。 2.**子类可扩展性:**子类可以定义必填字段,而不受父类中默认值的约束。父类中具有默认值的字段不强制子类中存在默认值。 虽然对于专注于向后兼容性和可扩展性的库作者来说至关重要,但这种做法提高了任何可重用数据类驱动项目中的代码健壮性。

This Hacker News thread discusses the use of keyword-only arguments in Python dataclasses, introduced in Python 3.10. Users highlight the `KW_ONLY` sentinel type annotation as a way to enforce keyword-only arguments while still allowing for positional arguments. The discussion extends to the broader topic of keyword-only arguments in Python, with some users expressing a desire for JavaScript's shorthand property syntax. Alternatives and potential syntax additions are explored. The thread also touches on the challenges of using libraries like boto3, where the widespread use of `**kwargs` can obscure the available parameters. TypedDicts are suggested as a solution for better type hinting. Finally, dataclasses are compared with Pydantic base models, with considerations given to speed, size, and the need for data validation. The importance of interface stability and strategies for deprecating positional arguments are also discussed.
相关文章

原文

Python dataclasses are a really nice feature for constructing classes that primarily hold or work with data. They can be a good alternative to using dictionaries, since they allow you to add methods, dynamic properties, and subclasses. They can also be a good alternative to building your own class by hand, since they don’t need a custom __init__() that reassigns attributes and provide methods like __eq__() out of the box.

One small tip to keeping dataclasses maintainable is to always construct them with kw_only=True, like so:

from dataclasses import dataclass


@dataclass(kw_only=True)
class MyDataClass:
    x: int
    y: str
    z: bool = True

This will construct an __init__() that looks like this:

class MyDataClass:
    def __init__(
        self,
        *,
        x: int,
        y: str,
        z: bool = True,
    ) -> None:
        self.x = x
        self.y = y
        self.z = z

Instead of:

class MyDataClass:
    def __init__(
        self,
        x: int,
        y: str,
        z: bool = True,
    ) -> None:
        self.x = x
        self.y = y
        self.z = z

That * in the argument list means everything that follows must be passed as a keyword argument, instead of a positional argument.

There are two reasons you probably want to do this:

  1. It allows you to reorder the fields on the dataclass without breaking callers. Positional arguments means a caller can use MyDataClass(1, 'foo', False), and if you remove/reorder any of these arguments, you’ll break those callers unexpectedly. By forcing callers to use MyDataClass(x=1, y='foo', z=False), you remove this risk.
  2. It allows subclasses to add required fields. Normally, any field with a default value (like z above) will force any fields following it to also have a default. And that includes all fields defined by subclasses. Using kw_only=True gives subclasses the flexibility to decide for themselves which fields must be provided by the caller and which have a default.

These reasons are more important for library authors than anything. We spend a lot of time trying to ensure backwards-compatibility and forwards-extensibility in Review Board, so this is an important topic for us. And if you’re developing something reusable with dataclasses, it might be for you, too.

联系我们 contact @ memedata.com