5

私はプラグイン フレームワークを作成してinterfaceいますが、ユーザー クラスを ABC クラスに変換し、すべてのメソッドを抽象メソッドに置き換えるデコレータを作成できるようにしたいと考えています。問題が間違ったmroに関連していると思いますが、間違っている可能性があります。

私は基本的に書くためにalbeである必要があります:

@interface
class X:
    def test(self):
        pass

x = X() # should fail, because test will be abstract method.

メソッドを抽象バージョンに置き換えるのは簡単です ( func を反復処理して に置き換える必要があります) が、メタクラスabc.abstractmethod(func)になる動的型の作成に問題があります。ABCmeta

今、私は次のようなものを持っています:

from abc import ABCMeta

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    newcls = type(cls.__name__, (Interface, cls), {})
    # substitute all methods with abstract ones
    for name, func in inspect.getmembers(newcls, predicate=inspect.isfunction):
        setattr(newcls, name, abstractmethod(func))
    return newcls

しかし、それは機能しません - クラス X をエラーなしで初期化できます。

Python で ABC を標準的に使用すると、次のように記述できます。

class X(metaclass=ABCMeta):
    @abstractmethod
    def test(self):
        pass

x = X() # it will fail

ABCmetaメタクラスを持つように動作し、すべての関数を抽象関数に置き換えるPython3で動的型を作成するにはどうすればよいですか?

4

1 に答える 1

5

トリックはsetattr、各属性をリセットするために使用するのではなくtype、変更された属性を辞書として関数に渡すことです。

import inspect
from abc import ABCMeta, abstractmethod

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    attrs = {n: abstractmethod(f)
             for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)}

    return type(cls.__name__, (Interface, cls), attrs)

@interface
class X(metaclass=ABCMeta):
    def test(self):
        pass

x = X()
# does fail:
# Traceback (most recent call last):
#   File "test.py", line 19, in <module>
#     x = X() # should fail, because test will be abstract method.
# TypeError: Can't instantiate abstract class X with abstract methods test
于 2013-01-08T16:11:25.620 に答える