Я знаю, что эта тема действительно старая, но ... Это действительно хороший вопрос.
Это не работает, потому что abc может проверять абстрактные методы только во время определения типов, то есть, когда работает type('Derived', (FooClass,), {})
. Любой setattr, сделанный после этого, не доступен из abc
Итак, setattr не будет работать, buuut ...
Ваша проблема обращения к имени класса, который не был ранее объявлен или определен, выглядит решаемой:
Я написал небольшой метакласс, который позволяет использовать заполнитель «clazz» для доступа к любому классу, который в конечном итоге получит метод, который вы пишете, вне определения класса.
Таким образом, вы больше не получите TypeError от abc, так как теперь вы можете определить свой метод ДО установления типа, а затем передать его типу в аргументе dict. Тогда abc увидит это как правильное переопределение метода.
Aaand, с новым метаклассом вы можете ссылаться на объект класса во время этого метода.
И это супер, потому что теперь вы можете использовать супер! = Р
Я думаю, вы тоже волновались об этом ...
Взгляните:
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()
Вывод:
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...