在Java中,我们可以通过使类成为抽象类来阻止类的实例化。我以为python会表现得一样。但令我惊讶的是,我发现我可以创建一个抽象类的对象:
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
为什么python允许这样做?如何防止这种情况?
答案 0 :(得分:1)
Python用于"同意成年人" - 如果需要(或模块成员资格),可以通过在项目中命名约定来将类标记为抽象。但是,做一个难以解决的问题是可行的。抽象类 - 但这不会增加项目本身的安全性或良好的实践,正如问题的提交者提出的那样。
因此,为了保留ABC的抽象类的剩余机制,你可以继承ABCMeta类,并使用它来装饰__new__
方法,这样它就不会实例化 - 否则,只是做同样的事,但继承自type
。
换句话说,下面的代码将__new__
方法包装在用它创建的类作为元类上。当运行该方法时,它会检查它实例化的类是否是标记有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()
....
仅仅为了完整性 - 如果Python中的ABCMeta包含至少一个&#34; abstractmethod&#34;则它不可实例化。就像其他O.O.在更多静态语言中强制执行的功能,其想法是遵循惯例。但是,是的,我同意,因为他们完成了创建一个AbstractClass机制的工作,它应该表现得更少的意外,这意味着默认情况下不应该是可实例化的。