我创建了几个类来将它们用作状态标志(这更像是一个练习,虽然我将在实际项目中使用它们),就像我们使用None
一样在Python中,即
... some_var is None ...
NoneType
有几个特殊属性,最重要的是它是一个单例,即在任何解释器会话期间都不能有一个NoneType
实例及其实例({ {1}}个对象)是不可变的。我已经提出了两种可能的方法来在纯Python中实现一些类似的行为,而且我很想知道从架构的角度来看哪一个看起来更好。
我们的想法是拥有一个产生不可变类的元类。禁止这些类具有实例。
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
显然,任何在这些类上设置属性的尝试都将失败(当然有几种方法可以解决这个问题,但直接关闭方法)。类本身是在命名空间中加载的唯一对象。
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
是一个实例,但我不确定它是否值得增加思想复杂性。期待收到你的来信。
答案 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
。