防止实例化抽象 class
Prevent instantiation of an abstract class
在 Java 中,我们可以通过将 class 设为抽象 class 来防止其实例化。我认为 python 的行为方式相同。但令我惊讶的是,我发现我可以创建一个抽象的对象 class:
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
为什么 python 允许这种情况,我该如何防止这种情况?
Python 用于“同意的成年人”——如果需要(或模块成员资格),您可以通过项目内的命名约定将 class 标记为抽象。然而,做一个硬性的“无法实例化”的抽象是可行的 class - 但正如问题的评论者所建议的那样,这不会增加项目本身的安全性或良好实践。
所以,要保留ABC抽象classes的剩余机制,可以继承ABCMetaclass,用它来修饰__new__
方法,这样就不会了实例化 - 否则,只需执行相同的操作,但改为从 type
继承。
换句话说,下面的代码将 __new__
方法包装在 classes 上作为元 class 创建。当该方法是 运行 时,它会检查它正在实例化的 class 是否是用 ABC 元本身标记的 class,如果是,它会引发类型错误。
class ReallyAbstract(ABCMeta):
def __new__(metacls, name, bases, namespace):
outter_cls = super().__new__(metacls, name, bases, namespace)
for bases in outter_cls.__mro__:
if getattr(getattr(bases, "__new__", None), "_abstract", False):
# Base class already marked as abstract. No need to do anything else
return outter_cls
original_new = getattr(outter_cls, "__new__")
if getattr(original_new, "_abstract", False):
# If we get a method that has already been wrapped
# just return it unchanged.
# TODO: if further classes on the hierarhy redfine __new__
return outter_cls
def __new__(cls, *args, **kw):
if cls is outter_cls:
raise TypeError
return original_new(cls, *args, **kw)
__new__._abstract = True
outter_cls.__new__ = __new__
return outter_cls
在控制台上:
In [7]: class A(metaclass=ReallyAbstract):
...: pass
...:
In [7]: A()
TypeError Traceback (most recent call last)
<ipython-input-7-...> in <module>()
----> 1 A()
....
为了完整起见 - 如果 ABCMeta 在 Python 中包含至少一个“抽象方法”,则它们不可实例化。就像其他 O.O。在更多静态语言中强制执行的功能,我们的想法是按照惯例拥有它。但是,是的,我同意,既然他们开始着手创建一个 AbstractClass 机制,它的行为应该不会那么令人惊讶,这意味着默认情况下不应该实例化。
在 Java 中,我们可以通过将 class 设为抽象 class 来防止其实例化。我认为 python 的行为方式相同。但令我惊讶的是,我发现我可以创建一个抽象的对象 class:
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
为什么 python 允许这种情况,我该如何防止这种情况?
Python 用于“同意的成年人”——如果需要(或模块成员资格),您可以通过项目内的命名约定将 class 标记为抽象。然而,做一个硬性的“无法实例化”的抽象是可行的 class - 但正如问题的评论者所建议的那样,这不会增加项目本身的安全性或良好实践。
所以,要保留ABC抽象classes的剩余机制,可以继承ABCMetaclass,用它来修饰__new__
方法,这样就不会了实例化 - 否则,只需执行相同的操作,但改为从 type
继承。
换句话说,下面的代码将 __new__
方法包装在 classes 上作为元 class 创建。当该方法是 运行 时,它会检查它正在实例化的 class 是否是用 ABC 元本身标记的 class,如果是,它会引发类型错误。
class ReallyAbstract(ABCMeta):
def __new__(metacls, name, bases, namespace):
outter_cls = super().__new__(metacls, name, bases, namespace)
for bases in outter_cls.__mro__:
if getattr(getattr(bases, "__new__", None), "_abstract", False):
# Base class already marked as abstract. No need to do anything else
return outter_cls
original_new = getattr(outter_cls, "__new__")
if getattr(original_new, "_abstract", False):
# If we get a method that has already been wrapped
# just return it unchanged.
# TODO: if further classes on the hierarhy redfine __new__
return outter_cls
def __new__(cls, *args, **kw):
if cls is outter_cls:
raise TypeError
return original_new(cls, *args, **kw)
__new__._abstract = True
outter_cls.__new__ = __new__
return outter_cls
在控制台上:
In [7]: class A(metaclass=ReallyAbstract):
...: pass
...:
In [7]: A()
TypeError Traceback (most recent call last)
<ipython-input-7-...> in <module>()
----> 1 A()
....
为了完整起见 - 如果 ABCMeta 在 Python 中包含至少一个“抽象方法”,则它们不可实例化。就像其他 O.O。在更多静态语言中强制执行的功能,我们的想法是按照惯例拥有它。但是,是的,我同意,既然他们开始着手创建一个 AbstractClass 机制,它的行为应该不会那么令人惊讶,这意味着默认情况下不应该实例化。