Javaでは、抽象クラスにすることでクラスのインスタンス化を防ぐことができます。私はPythonが同じように動作すると思った。しかし、私の驚きに、私は抽象クラスのオブジェクトを作成することが分かっ:抽象クラスのインスタンス化を防止する
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
はなぜPythonはこれを許可しないとどのように私はこれを防ぐことができますか?
Javaでは、抽象クラスにすることでクラスのインスタンス化を防ぐことができます。私はPythonが同じように動作すると思った。しかし、私の驚きに、私は抽象クラスのオブジェクトを作成することが分かっ:抽象クラスのインスタンス化を防止する
from abc import ABCMeta
class Foo(metaclass=ABCMeta):
pass
Foo()
はなぜPythonはこれを許可しないとどのように私はこれを防ぐことができますか?
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()
....
ただ、完全を期すために - 彼らは、少なくとも1つの「abstractmethod」を含む場合はPythonでABCMetaさんがインスタンス化されていません。他のO.O.より静的な言語で強化された機能は、習慣によってこれを持つことです。しかし、はい、私は、AbstractClassのメカニズムを作成する作業に慣れて以来、おそらくあまり驚くべきことではないはずです。つまり、デフォルトでインスタンス化できないようにすべきです。
おそらく、抽象クラスにはいくつかの '@ abstractmethod'もあります。もしそうであれば、インスタンス化ができなくなります。現実には、ほとんど問題ではないはずです。 – deceze
Pythonは面白いです。抽象メソッドはそれらの中にコードを持つことができ、スーパーも使用して呼び出すことができます。さて、 '抽象的な'であるために)# – codingsplash
これはPythonの抽象的な概念です。:P – deceze