私はこのトピックが本当に古いことを知っていますが...それは本当に素敵な質問です。
abcはタイプの起動中、つまりtype('Derived', (FooClass,), {})
が実行されているときにのみ抽象メソッドをチェックできるため、機能しません。それ以降に行われるsetattrはabcからアクセスできません。だから、
、SETATTR文句を言わない仕事、buuut ...以前に宣言または定義されていないクラスの名前に対処する あなたの問題を解決可能になります。
私はあなたが、プレースホルダを使用することができます少しメタクラスを書きました最終的にクラス定義の外で作成しているメソッドを取得するクラスにアクセスするための "clazz"
このようにしてabcからTypeErrorを得ることはもうできません。あなたの型を定義する前にメソッドを定義してから、dict引数で型に渡すことができるようになりました。それから、abcはそれを適切なメソッドオーバーライドとみなします。
新しいメタクラスでは、そのメソッド中にクラスオブジェクトを参照できます。 これはスーパーです、今あなたはスーパーを使用することができます!
import abc
import inspect
clazz = type('clazz', (object,), {})()
def clazzRef(func_obj):
func_obj.__hasclazzref__ = True
return func_obj
class MetaClazzRef(type):
"""Makes the clazz placeholder work.
Checks which of your functions or methods use the decorator clazzRef
and swaps its global reference so that "clazz" resolves to the
desired class, that is, the one where the method is set or defined.
"""
methods = {}
def __new__(mcs, name, bases, dict):
ret = super(MetaClazzRef, mcs).__new__(mcs, name, bases, dict)
for (k,f) in dict.items():
if getattr(f, '__hasclazzref__', False):
if inspect.ismethod(f):
f = f.im_func
if inspect.isfunction(f):
for (var,value) in f.func_globals.items():
if value is clazz:
f.func_globals[var] = ret
return ret
class MetaMix(abc.ABCMeta, MetaClazzRef):
pass
class FooClass(object):
__metaclass__ = MetaMix
@abc.abstractmethod
def FooMethod(self):
print 'Ooops...'
#raise NotImplementedError()
def main():
@clazzRef
def BarOverride(self):
print "Hello, world! I'm a %s but this method is from class %s!" % (type(self), clazz)
super(clazz, self).FooMethod() # Now I have SUPER!!!
derived_type = type('Derived', (FooClass,), {'FooMethod': BarOverride})
instance = derived_type()
instance.FooMethod()
class derivedDerived(derived_type):
def FooMethod(self):
print 'I inherit from derived.'
super(derivedDerived,self).FooMethod()
instance = derivedDerived()
instance.FooMethod()
main()
出力は次のとおりです:= P 私は
を見てみましょう...あなたもそのことについて心配していた推測することができます
Hello, world! I'm a <class 'clazz.Derived'> but this method is from class <class 'clazz.Derived'>!
Ooops...
I inherit from derived.
Hello, world! I'm a <class 'clazz.derivedDerived'> but this method is from class <class 'clazz.Derived'>!
Ooops...
クラスの抽象クラスの構築中に決定される
。クラスを作成するときに辞書に 'FooMethod'を入れるだけでいいのですか? –
@SvenMarnach:実際の例の 'BarOverride'は、それにバインドされた派生クラスを持つ必要があります。後でこの関数を作成するのが最も簡単な方法です。 – Thanatos
私はその点を知りません。 「派生クラスをバインドする必要がある」とはどういう意味ですか? –