在Java中,我们可以通过将类设为抽象类来阻止实例化类。我以为python会以同样的方式行事。但让我吃惊,我发现,我可以创造一个抽象类的一个对象:防止抽象类实例化
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
为什么蟒蛇允许这一点,我怎样才能避免这种情况?
在Java中,我们可以通过将类设为抽象类来阻止实例化类。我以为python会以同样的方式行事。但让我吃惊,我发现,我可以创造一个抽象类的一个对象:防止抽象类实例化
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
为什么蟒蛇允许这一点,我怎样才能避免这种情况?
Python是用于“成年人同意” - 如果你想(或模块成员资格),你可以通过在项目中命名约定来将类标记为抽象类。然而,做一个艰难的“不合理的”抽象类是可行的 - 但这并不会增加项目本身的安全性或良好实践,正如问题的提法者所提出的那样。因此,为了保留ABC抽象类的剩余机器,您可以继承ABCMeta类,并使用它来装饰__new__
方法,以便它不会实例化 - 否则,只需执行相同的操作,但是可以从type
继承。
换句话说,下面的代码包含了用它作为元类创建的类的方法。当该方法运行时,它会检查它正在实例化的类是否是用ABC元标记本身标记的类,如果是,则会引发类型错误。
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中是否包含至少一个“abstractmethod”没有实例化。就像其他O.O.在更多静态语言中强制执行的功能,这个想法是按照惯例。但是,是的,我同意,由于他们完成了创建AbstractClass机制的工作,所以它应该可能表现出更少的意外,并且这意味着默认情况下不应该实例化。
假设抽象类也会有一些'@ abstractmethod';如果是这样,那*表示阻止实例化。所以在现实中应该基本上不是问题。 – deceze
Python很有趣。抽象方法可以包含代码,也可以使用super来调用。那么,为什么'抽象':) – codingsplash
这是一个相当抽象的概念在Python ...:P – deceze