python - 模仿 Python 的 NoneType

标签 python metaclass nonetype

我正在创建几个类以将它们用作状态标志(这更像是一个练习,尽管我将在实际项目中使用它们),就像我们在中使用 None Python,即

... some_var is None ...

NoneType 有几个特殊属性,最重要的是它是一个单例,即在任何解释器 session 期间不能有多个 NoneType 实例,并且它的实例 ( None 对象)是不可变的。我想出了两种可能的方法来在纯 Python 中实现有些相似的行为,我很想知道从架构的角度来看哪一种看起来更好。

1。根本不要使用实例。

这个想法是有一个元类,它产生不可变的类。禁止类有实例。

class FlagMetaClass(type):
    def __setattr__(self, *args, **kwargs):
        raise TypeError("{} class is immutable".format(self))

    def __delattr__(self, *args, **kwargs):
        self.__setattr__()

    def __repr__(self):
        return self.__name__


class BaseFlag(object):
    __metaclass__ = FlagMetaClass

    def __init__(self):
        raise TypeError("Can't create {} instances".format(type(self)))

    def __repr__(self):
        return str(type(self))


class SomeFlag(BaseFlag):
    pass

我们得到了想要的行为

a = BaseFlag
a is BaseFlag  # -> True
a is SomeFlag  # -> False

显然,任何在这些类上设置属性的尝试都将失败(当然,有几种 hack 可以克服这个问题,但直接的方法是关闭的)。类本身是加载到命名空间中的唯一对象。

2。一个合适的单例类

class FlagMetaClass(type):
    _instances = {}

    def __call__(cls):
        if cls not in cls._instances:
            cls._instances[cls] = super(FlagMetaClass, cls).__call__()
        return cls._instances[cls] # This may be slightly modified to 
                                   # raise an error instead of returning
                                   # the same object, e.g.
    # def __call__(cls):
    #     if cls in cls._instances:
    #         raise TypeError("Can't have more than one {} instance".format(cls))
    #     cls._instances[cls] = super(FlagMetaClass, cls).__call__()
    #     return cls._instances[cls]

    def __setattr__(self, *args, **kwargs):
        raise TypeError("{} class is immutable".format(self))

    def __delattr__(self, *args, **kwargs):
        self.__setattr__()

    def __repr__(self):
        return self.__name__


class BaseFlag(object):
    __metaclass__ = FlagMetaClass
    __slots__ = []

    def __repr__(self):
        return str(type(self))


class SomeFlag(BaseFlag):
    pass

这里的 Flag 类是真正的单例。当我们尝试创建另一个实例时,这个特定的实现不会引发错误,而是返回相同的对象(尽管很容易改变这种行为)。不能直接修改类和实例。重点是在导入时为每个类创建一个实例,就像使用 None 一样。

这两种方法都为我提供了一些不可变的唯一对象,可以像 None 一样用于比较。对我来说,第二个看起来更像 NoneType,因为 None 是一个实例,但我不确定增加思想复杂性是否值得。期待您的来信。

最佳答案

从理论上讲,这是一个有趣的练习。但是当你说“尽管我将在实际项目中使用它们”时,你就失去了我。

如果真正的项目是高度非 Pythonic 的(使用 traits 或其他一些包来模拟静态类型,使用 __slots__ 来防止人们掉到尖锐的物体上,等等)——好吧,我已经对你毫无用处,因为我没有用,但其他人有。

如果真正的项目是 Pythonic,那么尽可能做最简单的事情。

你的“根本不使用实例”的答案在这里是正确的,但你也不需要做很多类定义。

例如,如果您有一个可以接受 None 作为实际参数的函数,并且您想要判断该参数是否已默认,那么只需执行以下操作:

class NoParameterGiven:
    pass

def my_function(my_parameter=NoParameterGiven):
    if my_parameter is NoParameterGiven:
        <do all my default stuff>

那个类(class)太便宜了,甚至没有理由在文件之间共享它。只需在需要的地方创建即可。

你的状态类是一个不同的故事,你可能想使用类似的东西 enum module @Dunes 提到的——它有一些不错的功能。

OTOH,如果你想让它变得非常简单,你可以这样做:

class MyStates:
    class State1: pass
    class State2: pass
    class State3  pass

您不需要实例化任何东西,您可以像这样引用它们:MyStates.State1

关于python - 模仿 Python 的 NoneType,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31832192/

相关文章:

javascript - 如何将 SQLite 本地数据库连接到 HTML 前端?

python - 通过 pyodbc 连接 python 和 SQL 时出现问题(未指定默认驱动程序)

python - 为什么调用元类的 __new__

python - 元类中的 super

python - 类型错误 : 'NoneType' object is not subscriptable

python - 无法在 python 中读取 .wav 文件

python - 替换 Pandas 数据框中的特定列值

python - 调用元类库时出错 : function() argument 1 must be code, not str

python - 尝试过滤列表时出现 TypeError : 'NoneType' object is not iterable,

将 'None' 字符串转换为 None 的 Pythonic 方式