このメタクラスに基づくクラスで定義されたすべてのメソッドがデフォルトでクラス メソッドになるように (つまり、@classmethod
装飾などを必要とせずに) メタクラスを作成する方法はありますか?
ありがとう!
編集: Python 2.7.3 に興味があります。省略はご容赦ください。
このメタクラスに基づくクラスで定義されたすべてのメソッドがデフォルトでクラス メソッドになるように (つまり、@classmethod
装飾などを必要とせずに) メタクラスを作成する方法はありますか?
ありがとう!
編集: Python 2.7.3 に興味があります。省略はご容赦ください。
もちろん。本当の問題は、なぜこれをやりたいのかということです。これは教育のためだけだと思います。実際には、これを使用できるものは何であれ、おそらく明示的に行う方がよいでしょう (つまり、メタクラスを使用せずに を追加します@classmethod
)。
私は 2 つのオプションを認識しています。クラス定義のカスタム名前空間と、__new__
. 前者は非常にクールで、場合によっては (メソッド定義の順序を覚えるなど) 実際には避けられませんが、後者はより単純で柔軟性があり、同じ名前への複数の割り当てを誤って壊すことがなく、Python 2 で使用できます。これは前者を除外しますが、Python 3 を使用できるすべての人のために残します。
カスタム名前空間を提供する__prepare__
には、メタクラスで定義し、辞書のようなオブジェクトを返す必要があります (Ferdinand Beyer はコメントに記載されています: で定義されているマッピング インターフェイスcollections
で十分です)。この場合、__setitem__
値が であるかどうかを確認するために辞書をオーバーライドする必要があります。値が である場合は、格納する前にcallable
ラップします。classmethod
以下のコメントのおかげで、以下のコードが大幅に改善されました。Ferdinand Beyer はそれが誤りであることに気づき、agf はPython 3 との互換性とのcallable(classmethod(...))
矛盾を指摘しました。@classmethod
import types
# Either this, in a dictionary class instanciated in __prepare__
# Again, Python 3 only
def __setitem__(self, name, value):
if isinstance(value, types.FunctionType):
value = classmethod(value)
super().__setitem__(name, value)
# __prepare__ would be: return AutomaticClassMethodNamespace() or something
# Or this in the metaclass
def __new__(mcls, clsname, bases, ns):
for name, value in ns.items():
if isinstance(value, types.FunctionType):
ns[name] = classmethod(value)
# Any other metaclass behaviour
このようなもの (2.7)
def m(name, bases, dct):
for k, v in dct.items():
if type(v) is type(m):
dct[k] = classmethod(v)
return type(name, bases, dct)
class A:
__metaclass__ = m
def foo(self):
print self
A.foo() # <class '__main__.A'>