मुझे हाल ही में एक ही समस्या का सामना करना पड़ा। यही है, मुझे अमूर्त कक्षाओं की आवश्यकता थी लेकिन अन्य परियोजना बाधाओं के कारण पाइथन 3 का उपयोग करने में असमर्थ था। जिस समाधान के साथ मैं आया था वह निम्नलिखित है।
abcExtend.py:
import abc
class instancemethodwrapper(object):
def __init__(self, callable):
self.callable = callable
self.__dontcall__ = False
def __getattr__(self, key):
return getattr(self.callable, key)
def __call__(self, *args, **kwargs):
if self.__dontcall__:
raise TypeError('Attempted to call abstract method.')
return self.callable(*args,**kwargs)
class newclassmethod(classmethod):
def __init__(self, func):
super(newclassmethod, self).__init__(func)
isabstractmethod = getattr(func,'__isabstractmethod__',False)
if isabstractmethod:
self.__isabstractmethod__ = isabstractmethod
def __get__(self, instance, owner):
result = instancemethodwrapper(super(newclassmethod, self).__get__(instance, owner))
isabstractmethod = getattr(self,'__isabstractmethod__',False)
if isabstractmethod:
result.__isabstractmethod__ = isabstractmethod
abstractmethods = getattr(owner,'__abstractmethods__',None)
if abstractmethods and result.__name__ in abstractmethods:
result.__dontcall__ = True
return result
class abstractclassmethod(newclassmethod):
def __init__(self, func):
func = abc.abstractmethod(func)
super(abstractclassmethod,self).__init__(func)
उपयोग:
from abcExtend import abstractclassmethod
class A(object):
__metaclass__ = abc.ABCMeta
@abstractclassmethod
def foo(cls):
return 6
class B(A):
pass
class C(B):
@classmethod
def foo(cls):
return super(C,cls).foo() + 1
try:
a = A()
except TypeError:
print 'Instantiating A raises a TypeError.'
try:
A.foo()
except TypeError:
print 'Calling A.foo raises a TypeError.'
try:
b = B()
except TypeError:
print 'Instantiating B also raises a TypeError because foo was not overridden.'
try:
B.foo()
except TypeError:
print 'As does calling B.foo.'
#But C can be instantiated because C overrides foo
c = C()
#And C.foo can be called
print C.foo()
और यहाँ कुछ pyunit परीक्षण जो एक और अधिक संपूर्ण प्रदर्शन दे रहे हैं।
testAbcExtend.py:
import unittest
import abc
oldclassmethod = classmethod
from abcExtend import newclassmethod as classmethod, abstractclassmethod
class Test(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def testClassmethod(self):
class A(object):
__metaclass__ = abc.ABCMeta
@classmethod
@abc.abstractmethod
def foo(cls):
return 6
class B(A):
@classmethod
def bar(cls):
return 5
class C(B):
@classmethod
def foo(cls):
return super(C,cls).foo() + 1
self.assertRaises(TypeError,A.foo)
self.assertRaises(TypeError,A)
self.assertRaises(TypeError,B)
self.assertRaises(TypeError,B.foo)
self.assertEqual(B.bar(),5)
self.assertEqual(C.bar(),5)
self.assertEqual(C.foo(),7)
def testAbstractclassmethod(self):
class A(object):
__metaclass__ = abc.ABCMeta
@abstractclassmethod
def foo(cls):
return 6
class B(A):
pass
class C(B):
@oldclassmethod
def foo(cls):
return super(C,cls).foo() + 1
self.assertRaises(TypeError,A.foo)
self.assertRaises(TypeError,A)
self.assertRaises(TypeError,B)
self.assertRaises(TypeError,B.foo)
self.assertEqual(C.foo(),7)
c = C()
self.assertEqual(c.foo(),7)
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
मैं मूल्यांकन नहीं किया इस समाधान का प्रदर्शन लागत, लेकिन यह मेरी प्रयोजनों के लिए अब तक काम किया है।
यदि आप abc.abstractclassmethod का उपयोग नहीं कर सकते हैं, तो यह कैसे एक और सजावट के साथ गठबंधन करने का मुद्दा उठता है? – abarnert
सोचें कि आप गलत पढ़ते हैं: abc.abstractclassmethod = abc.abstractmethod + classmethod। पायथन 2.7 में abstractmethod और classmethod है, लेकिन abstractclassmethod नहीं – jchu
मुझे बिल्कुल इसी तरह की समस्या का सामना करना पड़ रहा है! अच्छा प्रश्न! –