模仿 Python 的 NoneType
Mimic Python's NoneType
我正在创建几个 classes 以将它们用作状态标志(这更像是一个练习,尽管我将在实际项目中使用它们),就像我们使用 [= Python 中的 15=],即
... some_var is None ...
NoneType
有几个特殊的属性,最重要的是它是一个单例,即在任何解释器会话期间不能有超过一个 NoneType
实例,并且它的实例(None
对象)是不可变的。我想出了两种可能的方法来在纯 Python 中实现有些相似的行为,我很想知道从架构的角度来看哪一种看起来更好。
1。根本不使用实例。
想法是有一个元class,它产生不可变的classes。 classes 禁止有实例。
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
显然,任何在这些 classes 上设置属性的尝试都会失败(当然有几个技巧可以克服这个问题,但直接的方法已经关闭)。 classes 本身是在命名空间中加载的唯一对象。
2。一个合适的单例 class
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
class 是真正的单例。当我们尝试创建另一个实例时,这个特定的实现不会引发错误,而是 returns 同一个对象(尽管很容易改变这种行为)。 classes 和实例都不能直接修改。重点是在导入时为每个 class 创建一个实例,就像对 None
所做的那样。
这两种方法都给了我一些不可变的独特对象,可以像 None
一样用于比较。对我来说,第二个看起来更像 NoneType
,因为 None
是一个实例,但我不确定增加思想复杂性是否值得。期待您的来信。
从理论上讲,这是一个有趣的练习。但是当你说 "though I'm going to use them in a real project" 时,你就失去了我。
如果真正的项目是高度非 Pythonic 的(使用 traits 或其他一些包来模拟静态类型,使用 __slots__
来防止人们掉到尖锐的物体上,等等)——好吧,我有对你来说没什么,因为我没用,但其他人有用。
如果真正的项目是Pythonic,那就尽可能做最简单的事情。
您的 "not use instances at all" 答案在这里是正确的,但您也不需要做很多 class 定义。
例如,如果您有一个可以接受 None 作为实际参数的函数,并且您想知道该参数是否已默认,那么只需这样做:
class NoParameterGiven:
pass
def my_function(my_parameter=NoParameterGiven):
if my_parameter is NoParameterGiven:
<do all my default stuff>
class 太便宜了,甚至没有理由在文件之间共享它。只需在需要的地方创建即可。
你的状态 class 是一个不同的故事,你可能想使用类似的东西 enum module @Dunes 提到的 - 它有一些不错的功能。
OTOH,如果你想让它变得非常简单,你可以这样做:
class MyStates:
class State1: pass
class State2: pass
class State3 pass
你不需要实例化任何东西,你可以像这样引用它们:MyStates.State1
.
我正在创建几个 classes 以将它们用作状态标志(这更像是一个练习,尽管我将在实际项目中使用它们),就像我们使用 [= Python 中的 15=],即
... some_var is None ...
NoneType
有几个特殊的属性,最重要的是它是一个单例,即在任何解释器会话期间不能有超过一个 NoneType
实例,并且它的实例(None
对象)是不可变的。我想出了两种可能的方法来在纯 Python 中实现有些相似的行为,我很想知道从架构的角度来看哪一种看起来更好。
1。根本不使用实例。
想法是有一个元class,它产生不可变的classes。 classes 禁止有实例。
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
显然,任何在这些 classes 上设置属性的尝试都会失败(当然有几个技巧可以克服这个问题,但直接的方法已经关闭)。 classes 本身是在命名空间中加载的唯一对象。
2。一个合适的单例 class
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
class 是真正的单例。当我们尝试创建另一个实例时,这个特定的实现不会引发错误,而是 returns 同一个对象(尽管很容易改变这种行为)。 classes 和实例都不能直接修改。重点是在导入时为每个 class 创建一个实例,就像对 None
所做的那样。
这两种方法都给了我一些不可变的独特对象,可以像 None
一样用于比较。对我来说,第二个看起来更像 NoneType
,因为 None
是一个实例,但我不确定增加思想复杂性是否值得。期待您的来信。
从理论上讲,这是一个有趣的练习。但是当你说 "though I'm going to use them in a real project" 时,你就失去了我。
如果真正的项目是高度非 Pythonic 的(使用 traits 或其他一些包来模拟静态类型,使用 __slots__
来防止人们掉到尖锐的物体上,等等)——好吧,我有对你来说没什么,因为我没用,但其他人有用。
如果真正的项目是Pythonic,那就尽可能做最简单的事情。
您的 "not use instances at all" 答案在这里是正确的,但您也不需要做很多 class 定义。
例如,如果您有一个可以接受 None 作为实际参数的函数,并且您想知道该参数是否已默认,那么只需这样做:
class NoParameterGiven:
pass
def my_function(my_parameter=NoParameterGiven):
if my_parameter is NoParameterGiven:
<do all my default stuff>
class 太便宜了,甚至没有理由在文件之间共享它。只需在需要的地方创建即可。
你的状态 class 是一个不同的故事,你可能想使用类似的东西 enum module @Dunes 提到的 - 它有一些不错的功能。
OTOH,如果你想让它变得非常简单,你可以这样做:
class MyStates:
class State1: pass
class State2: pass
class State3 pass
你不需要实例化任何东西,你可以像这样引用它们:MyStates.State1
.