禁止从类外部使用默认构造函数

abc*_*abc 6 python class python-3.7 python-dataclasses

考虑以下数据类。我想阻止使用直接方法创建对象__init__

from __future__ import annotations
from dataclasses import dataclass, field

@dataclass
class C:
    a: int

    @classmethod
    def create_from_f1(cls, a: int) -> C:
        # do something
        return cls(a)
    @classmethod
    def create_from_f2(cls, a: int, b: int) -> C:
        # do something
        return cls(a+b)

    # more constructors follow


c0 = C.create_from_f1(1) # ok

c1 = C()  # should raise an exception
c2 = C(1) # should raise an exception
Run Code Online (Sandbox Code Playgroud)

例如,我想强制使用我定义的附加构造函数,如果直接将对象创建为c = C(..).

到目前为止我所尝试的如下。

@dataclass
class C:
    a : int = field(init=False)

    @classmethod
    def create_from(cls, a: int) -> C:
        # do something
        c = cls()
        c.a = a
        return c
Run Code Online (Sandbox Code Playgroud)

init=Falsefield防止a成为生成的参数,因此这部分解决了引发异常的__init__问题。 另外,我不喜欢它作为解决方案。c = C(1)

有没有直接的方法来禁止从类外部调用init方法?

Dun*_*nes 1

尝试在 Python 中将构造函数设置为私有并不是一件非常 Pythonic 的事情。Python 的哲学之一是“我们都是同意的成年人”。也就是说,您不会尝试隐藏该__init__方法,但您确实记录了用户可能想要使用便利构造函数之一。但如果用户认为他们真的知道自己在做什么,那么欢迎他们尝试。

您可以在标准库中看到这一理念的实际应用。和inspect.Signature。类构造函数需要一个列表Parameter,创建起来相当复杂。这不是用户创建 Signature 实例的标准方式。相反,提供了一个名为 Callable 的函数signature,该函数接受可调用对象作为参数,并完成从 CPython 中的各种不同函数类型创建参数实例并将它们编组到对象中的所有工作Signature

那就是做类似的事情:

@dataclass
class C:
    """
    The class C represents blah. Instances of C should be created using the C.create_from_<x> 
    family of functions.
    """

    a: int
    b: str
    c: float

    @classmethod
    def create_from_int(cls, x: int):
        return cls(foo(x), bar(x), baz(x))
Run Code Online (Sandbox Code Playgroud)