如何创建既可以用作类型又可以用作值的单例对象(类似于 None)?

问题描述 投票:0回答:1

我想要自定义 NotSet 值,该值可用于类似于 None 的类型提示。

NotSet = ?


class Client:
    def partial_update(
            self,
            obj_id: int,
            obj_field: int | None | NotSet = NotSet,
            ...
    ):
        # Do not update fields which were not specified explicitly.
        if obj_field is NotSet:
           # do not update obj_field
        else: 
           # update obj_field
        ...

解决方案不够好:

  1. 使用
    None
  • 本身没有一个是为业务逻辑保留的。字段可以为空。
  1. 使用内置
    ellipsis
from types import EllipsisType


def partial_update(
   obj_field: int | None | EllipsisType = ...,
):
   pass
  • 使用内置省略号不够明确
  • 您也不能使用省略号作为类型:
    obj_field: int | None | ... = ...,
  1. 使用自定义单例。
class NotSetType:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance


NotSet = NotSetType()


def partial_update(
   obj_field: int | None | NotSetType = NotSet,
):
   pass
  • 最好的一个,但仍然使用 NotSetType 而不是所需的 NotSet 进行打字。
python type-hinting
1个回答
0
投票

我认为你不能这样做,类不能是它自己的实例(除非它是

type
,但这是一个不同的故事)。

(其实可以:

class Meta(type):
    def __new__(cls, name, bases, dct):
        x = super().__new__(cls, name, bases, dct)
        return x(name, bases, dct)

class NotSet(type, metaclass=Meta):
    pass


def partial_update(
   obj_field: int | None | NotSet = NotSet,
):
    if obj_field is NotSet:
        print('not updating')
    else:
        print(f'updating to {obj_field}')
>>> NotSet
<class '__main__.NotSet'>
>>> type(NotSet)
<class '__main__.NotSet'>

>>> partial_update()
not updating
>>> partial_update(None)
updating to None
>>> partial_update(4)
updating to 4

但是你的静态类型检查器可能不高兴,例如mypy 不是。)

我认为你的第三个选择是最Pythonic、最明确、最容易理解的。另一个建议是使用

**kwargs
而不是函数参数:

def partial_update(
    **kwargs,
):
    for field, value in kwargs.items():
        setattr(obj, field, value)

尽管您丢失了类型提示和字段名称。

© www.soinside.com 2019 - 2024. All rights reserved.