2017-11-14 12 views
1

私は、Pythonでメタクラスについて直感を覚えようとしていました。私はPython2.7とPython3.5の両方で試しました。 Python 3.5では、私たちが明示的に継承するかどうかにかかわらず、定義したすべてのクラスがタイプ<class 'type'>であることがわかりました。しかし、タイプから継承されない場合は、そのクラスを別のクラスのメタクラスとして使用することはできません。python3.xでメタクラスを実装するための '型'を明示的に継承しました

>>> class foo: 
    pass 

>>> class Metafoo(type): 
    pass 

>>> foo 
<class '__main__.foo'> 
>>> Metafoo 
<class '__main__.Metafoo'> 
>>> type(foo) 
<class 'type'> 
>>> type(Metafoo) 
<class 'type'> 
>>> 
>>> class foocls1(metaclass=foo): 
    pass 

私は次のエラーを取得の上にやって:

Traceback (most recent call last): 
    File "<pyshell#52>", line 1, in <module> 
    class foocls1(metaclass=foo): 
TypeError: object() takes no parameters 

をしかし、新しいクラスのメタクラスとして

>>> class foocls3(metaclass=Metafoo): 
    pass 

>>> foocls3 
<class '__main__.foocls3'> 
>>> type(foocls3) 
<class '__main__.Metafoo'> 

をMetafooを使用しながら、それがケースではありませんが、誰もが理由を説明することができますこれは、クラスを他のクラスのメタクラスとして使用したい場合、明示的に継承する必要がある場合です。

+2

すべてのクラスは 'type'の*インスタンス*ですが、' type'のすべての*サブクラスではありません。 – user2357112

答えて

1

"type"は、Python 3およびPython 2以降のバージョン2.2のすべてのクラスオブジェクトの基本クラスです。 Python 2の "object"を明示的に継承しないクラスは "古いスタイルクラス"と呼ばれ、下位互換性のために残されていますが、ほとんど使用されていませんでした。)

それでは、継承:クラスのスーパークラスとは何か、そして「メタクラス」は「Pythonではクラスがオブジェクトそのものなので、そのオブジェクトのクラスは何か」は2つの異なるもの。継承するクラスは、クラスのインスタンスで属性(およびメソッド)ルックアップの順序を定義するため、共通の動作をします。

メタクラスはむしろ「あなたのクラスが構築するクラス」であり、他の目的にも役立ちますが、クラス自体の構築ステップを変更するために最もよく使用されます。周囲を検索すると、ほとんど__new____init__のメソッドを実装するメタクラスが表示されます。 (他の方法もありますが、あなたが何をしているのかを知っておく必要があります)

通常のオブジェクトを作成する必要がないアクションをいくつか作成する必要があります。これらのアクションは、ネイティブコードレイヤー(CPythonのC)で実行され、__add__,__eq__などのメソッドを実装する関数へのポインタであるクラスの特別なメソッドスロットの設定など、純粋なPythonコードでも再現できません。 CPythonでそれを行う唯一のクラスは "型"です。したがって、クラスを構築するために使用するコード、つまりメタクラスとして使用するコードは、ある時点でtype.__new__メソッドを呼び出す必要があります。 (ちょうどあなたがPythonで新しいオブジェクトを作成したいのと同じように、ある時点でコードをobject.__new__に呼び出します)。

エラーが発生したのは、type.__new__に直接または間接的に電話をしたかどうかをPythonが確認するためです。エラー: "TypeError:object()はパラメータを取らない"というのは、objectの同じメソッドがパラメータなしで渡される間に、メタクラスの__new__メソッドが3つのパラメータ(名前、ベース、名前空間)を渡されるという事実によるものです。 (両者とも自己に相当する余分な "cls"を得るが、これは数えられない)。

通常の関数であっても、任意の呼び出し可能関数をメタクラスとして使用できます。それは3つの明示的なパラメータを取らなければならないことです。この呼び出し可能なものが返すものは、その時点からのクラスとして使用されますが、type.__new__(間接的にでも)を呼び出さない場合でも、返す有効なクラスはありません。

は例えば、1は、辞書の宣言とクラスのボディを使用できるようにするだけのために、簡単な方法を作成することができます。

def dictclass(name, bases, namespace): 
    return namespace 

class mydict(metaclass=dictclass): 
    a = 1 
    b = 2 
    c = 3 

mydict["a"] 

だから、すべてのことで1つの興味深い事実があるtypeは独自のメタクラスであること。 (これはPythonの実装ではハードコードされています)。しかしtypeも自身は、オブジェクトから継承:

In [21]: type.__class__ 
Out[21]: type 

In [22]: type.__mro__ 
Out[22]: (type, object) 

をそして、ちょうどこの目的のために:それはデータとして、純粋なPythonのコードからではなく、通常可能object.__new__を呼び出さずにtype.__new__やオブジェクトを呼び出さずにクラスを作成することですが、 C-APIレベルの構造は、両方のアクションのために満たされなければなりません。それを行うための関数のネイティブコード実装を行うか、ctypesでハックすることができます。

+0

説明をありがとう –

関連する問題