模仿Python的NoneType

时间:2015-08-05 12:12:35

标签: python metaclass nonetype

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

... some_var is None ...

NoneType有几个特殊属性,最重要的是它是一个单例,即在任何解释器会话期间都不能有一个NoneType实例及其实例({ {1}}个对象)是不可变的。我已经提出了两种可能的方法来在纯Python中实现一些类似的行为,而且我很想知道从架构的角度来看哪一个看起来更好。

1。不要使用实例。

我们的想法是拥有一个产生不可变类的元类。禁止这些类具有实例。

None

我们得到了理想的行为

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

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

2。一个合适的单一类

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

这里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是一个实例,但我不确定它是否值得增加思想复杂性。期待收到你的来信。

1 个答案:

答案 0 :(得分:1)

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

如果真正的项目是高度unPythonic(使用特征或一些其他包来模拟静态类型,使用__slots__来防止人们躲在尖锐的物体上等) - 好吧,我什么都没有你,因为我对此毫无用处,但其他人也是如此。

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

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

例如,如果你有一个可以接受None作为真实参数的函数,并且你想知道参数是否已经默认,那么就这样做:

class NoParameterGiven:
    pass

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

这个课程太便宜了,甚至没有理由在文件之间分享它。只需在您需要的地方创建它。

你的州级课是一个不同的故事,你可能想要使用@Dunes提到的enum module之类的东西 - 它有一些不错的功能。

OTOH,如果你想保持简单,你可以做这样的事情:

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

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