How do I indicate that the .value of an enum is an unstable implementation detail?

huangapple go评论59阅读模式
英文:

How do I indicate that the .value of an enum is an unstable implementation detail?

问题

Here's the translation of the code portion you provided:

官方的Enum HOWTO有[这个示例](https://docs.python.org/3.11/howto/enum.html#planet):

```python
class Planet(Enum):
    MERCURY = (3.303e+23, 2.4397e6)
    VENUS   = (4.869e+24, 6.0518e6)
    EARTH   = (5.976e+24, 6.37814e6)
    MARS    = (6.421e+23, 3.3972e6)
    JUPITER = (1.9e+27,   7.1492e7)
    SATURN  = (5.688e+26, 6.0268e7)
    URANUS  = (8.686e+25, 2.5559e7)
    NEPTUNE = (1.024e+26, 2.4746e7)

    def __init__(self, mass, radius):
        self.mass = mass       # in kilograms
        self.radius = radius   # in meters

    @property
    def surface_gravity(self):
        # universal gravitational constant  (m3 kg-1 s-2)
        G = 6.67300E-11
        return G * self.mass / (self.radius * self.radius)
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)

>>> Planet.EARTH.surface_gravity
9.802652743337129

假设我正在做类似于这样的事情,我希望将.value,即类似于(3.303e+23, 2.4397e6)的元组,视为Planet API的不稳定实现细节。我不希望我的API使用者依赖于它们。相反,我希望他们使用我明确公开的属性,如.surface_gravity

有没有一种传统的方法来指示这一点?

我目前只是在docstring中添加一个注释,像这样:

class Planet(Enum):
    """.value is an implementation detail. Use .surface_gravity instead."""

但这似乎太容易被忽略。

如果这是一个普通的类,我只需将其命名为._value而不是.value。但在这里,.value是自动添加的,因为我从Enum中继承,我没有看到覆盖它的方法。


<details>
<summary>英文:</summary>

The official Enum HOWTO has [this example](https://docs.python.org/3.11/howto/enum.html#planet):

```python
class Planet(Enum):
    MERCURY = (3.303e+23, 2.4397e6)
    VENUS   = (4.869e+24, 6.0518e6)
    EARTH   = (5.976e+24, 6.37814e6)
    MARS    = (6.421e+23, 3.3972e6)
    JUPITER = (1.9e+27,   7.1492e7)
    SATURN  = (5.688e+26, 6.0268e7)
    URANUS  = (8.686e+25, 2.5559e7)
    NEPTUNE = (1.024e+26, 2.4746e7)

    def __init__(self, mass, radius):
        self.mass = mass       # in kilograms
        self.radius = radius   # in meters

    @property
    def surface_gravity(self):
        # universal gravitational constant  (m3 kg-1 s-2)
        G = 6.67300E-11
        return G * self.mass / (self.radius * self.radius)
&gt;&gt;&gt; Planet.EARTH.value
(5.976e+24, 6378140.0)

&gt;&gt;&gt; Planet.EARTH.surface_gravity
9.802652743337129

Suppose I'm doing something like this, and I want to treat the .values—the tuples like (3.303e+23, 2.4397e6)—as unstable implementation details of the Planet API. I don't want my API consumers to ever rely on them. Instead, I want them to use the properties that I explicitly expose myself, like .surface_gravity.

Is there a conventional way to indicate this?

I'm currently just adding a note in the docstring like this:

class Planet(Enum):
    &quot;&quot;&quot;.value is an implementation detail. Use .surface_gravity instead.&quot;&quot;&quot;

But that seems too easy to miss.

If it were a normal class, I would just make it ._value instead of .value. But here, .value is added automatically because I subclassed from Enum, and I don't see a way to override that.

答案1

得分: 2

以下是翻译好的内容:

枚举的确切值几乎总是一个实现细节;之所以将其公开,是因为有时候可以访问它是有用的。

有几种方式来减少它的存在:

  • 更改该枚举类的 repr()
    def __repr__(self):
        return '<%s.%s>' % (self.__class__.__name__, self._name_)
  • 使用自定义的 __new__ 来使 value 显然是 "错误" 的,以便视为表面重力(或其他)(可能与上面的 __repr__ 结合使用):
    def __new__(cls, mass, radius):
        member = object.__new__(cls)
        member._value_ = len(cls._member_names_)
        member.mass = mass
        member.radius = radius
        return member
  • 您可以与 dataclass 结合使用(它会自动更新 repr):
    @dataclass
    class PlanetData:
        mass: float
        radius: float

    class Planet(PlanetData, Enum):
        MERCURY = (3.303e+23, 2.4397e6)
        VENUS   = (4.869e+24, 6.0518e6)
        # 等等

    >>> Planet.VENUS
    <Planet.VENUS: mass=4.869e+24, radius=6051800.0>

披露:我是 Python 标准库 Enumenum34 回溯高级枚举 (aenum) 库的作者。

英文:

The exact value of any enum is nearly always an implementation detail; the reason it's exposed at all is that sometimes it's useful to be able to access it.

There are several ways to de-emphasize it's presence:

  • change the repr() of that enum class
    def __repr__(self):
        return &#39;&lt;%s.%s&gt;&#39; % (self.__class__.__name__, self._name_)
  • have a custom __new__ to make the value obviously "wrong" to treat as surface gratity (or whatever) (probably combined with the __repr__ above):
    def __new__(cls, mass, radius):
        member = object.__new__(cls):
        member._value_ = len(cls._member_names_)
        member.mass = mass
        member.radius = radius
        return member
  • you could combine with a dataclass (which automatically updates the repr):
    @dataclass
    class PlanetData:
        mass: float
        radius: float

    class Planet(PlanetData, Enum):
        MERCURY = (3.303e+23, 2.4397e6)
        VENUS   = (4.869e+24, 6.0518e6)
        # etc

    &gt;&gt;&gt; Planet.VENUS
    &lt;Planet.VENUS: mass=4.869e+24, radius=6051800.0&gt;

Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

答案2

得分: 0

以下是翻译好的部分:

问题之一是您有一个执行两个任务的单一类:

  1. 存储物理常数
  2. 进行计算

个人而言,我会将计算分离成一个接受来自枚举的行星参数的全局函数:

def surface_gravity(planet: Planet):
    #...与原实现相同,只需使用 `planet` 替代 `self`。

如果您需要进一步的翻译或帮助,请告诉我。

英文:

One of the problems is that you have a single class that is doing two things:

  1. Storing physical constants
  2. Doing a calculation

Personally, I would separate the calculation into a global function that accepts a planet from the enum:

def surface_gravity(planet: Planet):
    #...same implementation except use `planet` instead of `self`.

huangapple
  • 本文由 发表于 2023年4月20日 06:14:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059187.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定