24961


普段、開発しているさいにREPL(IPython)を使いながら挙動を確かめているのですが、クラスそれ自体が格納されているような変数を取りあつかう必要が出てきました。

普通、クラスはREPLで以下のような表示になると思われます:

[code]

    In [1]: Test
    Out[1]: __main__.Test
    
[/code]

ですが、以下のようなクラスを定義し:

[code]

    class Test:
        def __repr__(self):
            return "It works!!"
    
[/code]

インスタンスにすると、以下のように、REPL上の表示を変えることができます:

[code]

     In [4]: Test()
     Out[4]: It works!!
    
[/code]

これと同様のことを、クラスそれ自体にも行ないたいのですが、どうすればいいでしょうか？


CC BY-SA 3.0
2016-05-18T05:14:52.987
24960
2016-05-18T05:43:44.290
939
question
python
インスタンスにおける__repr__を利用するような、インタプリタ上の表示の書きかえをクラスでも行ないたい


REPLでの実行はプログラム的には `repr(obj)` によって処理されています。これは内部的には `obj.__repr__()`
に近い動作です（実際はもうすこし処理が挟まります）。

Python3.5での動作を例に説明します。

[code]

    >>> class Foo:
    ...     pass
    ... 
    >>> Foo
    <class '__main__.Foo'>
    
[/code]

このようなFooの表示（repr(Foo)と同等）を制御したい、ということになります。  
しかし、 `Foo.__repr__()` という実行は、__repr__メソッドにインスタンスが渡されないためエラーになります。

[code]

    >>> Foo.__repr__()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: descriptor '__repr__' of 'object' object needs an argument
    
[/code]

classの__repr__メソッドはインスタンスのためのものなので、classのための__repr__メソッドを用意すればいいかな？とアタリをつけます。

classのための__repr__メソッドを用意するために、メタクラスを使います。

[code]

    >>> class Type(type):
    ...     def __repr__(cls):
    ...         return "Hello"
    ... 
    >>> 
    >>> class Foo(metaclass=Type):
    ...     def __repr__(self):
    ...         return "World"
    ... 
    >>> 
    >>> Foo
    Hello
    >>> Foo()
    World
    
[/code]

でも、metaclass使い始めたら自分のコードを疑った方が良い場合が多いので、本当に必要か、をよく考えて使ってください。


CC BY-SA 3.0
2016-05-18T05:43:44.290
24961
2016-05-18T05:43:44.290
806
24960
answer