2012-02-10 3 views
8
class ITestType(object): 
    """ Sample interface type """ 

    __metaclass__ = ABCMeta 

    @abstractmethod 
    def requiredCall(self): 
    return 

class TestType1(object): 
    """ Valid type? """ 
    def requiredCall(self): 
    pass 

class TestType2(ITestType): 
    """ Valid type """ 
    def requiredCall(self): 
    pass 

class TestType3(ITestType): 
    """ Invalid type """ 
    pass 

issubclass(TypeType*, ITestType) ऊपर के उदाहरण 1 और 3पाइथन में डक-टाइप किए गए इंटरफेस को आप कैसे सत्यापित करते हैं?

के लिए 2 के लिए सच और अवास्तविक लौटाते हैं में issubclass उपयोग करने के लिए एक वैकल्पिक तरीका, या इंटरफ़ेस के परीक्षण के लिए एक वैकल्पिक पद्धति है कि अनुमति देगा है 1 और 2 पास करने के लिए, लेकिन 3 अस्वीकार?

यह मेरे लिए बेहद उपयोगी होगा कि मेरे लिए सार तत्वों को स्पष्ट रूप से बाध्यकारी वर्गों के बजाय बतख टाइपिंग का उपयोग करने में सक्षम हो, लेकिन ऑब्जेक्ट जांच की अनुमति दें जब बतख-टाइप की गई वस्तुएं विशेष इंटरफेस से गुजरती हैं।

हां, मुझे पता है कि पाइथन लोगों को इंटरफेस पसंद नहीं है, और मानक पद्धति "इसे विफल करती है और अपवादों में सब कुछ लपेटती है" लेकिन यह भी मेरे प्रश्न के लिए पूरी तरह से अप्रासंगिक है। नहीं, मैं इस परियोजना में इंटरफेस का उपयोग नहीं कर सकता।

संपादित करें:

बिल्कुल सही!

class ITestType(object): 
    """ Sample interface type """ 

    __metaclass__ = ABCMeta 

    @abstractmethod 
    def requiredCall(self): 
    return 

    @classmethod 
    def __subclasshook__(cls, C): 
    required = ["requiredCall"] 
    rtn = True 
    for r in required: 
     if not any(r in B.__dict__ for B in C.__mro__): 
     rtn = NotImplemented 
    return rtn 
+1

'नहीं, मैं इस परियोजना में इंटरफेस का उपयोग नहीं कर सकता।' क्यों? (मैं व्यंग्यात्मक नहीं हूं; वास्तव में उत्सुकता क्या उपयोग केस हो सकता है) –

उत्तर

9

बाहर ABC module की जांच: जो इस सवाल पाता है किसी और के लिए, यहाँ कैसे subclasshook उपयोग करने के लिए का एक उदाहरण है। आप एक अमूर्त बेस क्लास को परिभाषित कर सकते हैं जो __subclasshook__ विधि प्रदान करता है जो परिभाषित करता है कि कोई विशेष वर्ग "आपके उपरोक्त एक्स, वाई और जेड" या किसी भी मानदंड के आधार पर सार आधार वर्ग का "उप-वर्ग" है या नहीं । फिर आप कक्षाओं और उदाहरणों पर इंटरफेस का पता लगाने के लिए issubclass() या isinstance() का उपयोग कर सकते हैं।

1

यहां एक विकल्प है जो अभ्यास में बहुत अच्छी तरह से काम करता है, बिना किसी कक्षा के निर्माण के पूरे शब्दकोष को बोझिल किए बिना।

(py2 और py3 संगत)

उपयोग:

class Bar(): 
    required_property_1 = '' 

    def required_method(self): 
    pass 

# Module compile time check that Foo implements Bar 
@implements(Bar) 
class Foo(UnknownBaseClassUnrelatedToBar): 
    required_property_1 

    def required_method(self): 
    pass 

# Run time check that Foo uses @implements or defines its own __implements() member 
def accepts_bar(self, anything): 
    if not has_api(anything, Bar): 
    raise Exception('Target does not implement Bar') 
    ... 

भी कर सकते हैं कर @implements तरह स्पष्ट बातें (स्ट्रीम, फ़ोल्डर, बार), जब वे सभी एक ही तरीकों के कुछ की आवश्यकता होती है, जो विरासत से व्यावहारिक रूप से यह अधिक उपयोगी बनाता है।

कोड:

import inspect 


def implements(*T): 
    def inner(cls): 
    cls.__implements = [] 
    for t in T: 

     # Look for required methods 
     t_methods = inspect.getmembers(t, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)) 
     c_methods = inspect.getmembers(cls, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)) 
     sig = {} 
     for i in t_methods: 
     name = 'method:%s' % i[0] 
     if not name.startswith("method:__"): 
      sig[name] = False 
     for i in c_methods: 
     name = 'method:%s' % i[0] 
     if name in sig.keys(): 
      sig[name] = True 

     # Look for required properties 
     t_props = [i for i in inspect.getmembers(t) if i not in t_methods] 
     c_props = [i for i in inspect.getmembers(cls) if i not in c_methods] 
     for i in t_props: 
     name = 'property:%s' % i[0] 
     if not name.startswith("property:__"): 
      sig[name] = False 
     for i in c_props: 
     name = 'property:%s' % i[0] 
     if name in sig.keys(): 
      sig[name] = True 

     missing = False 
     for i in sig.keys(): 
     if not sig[i]: 
      missing = True 
     if missing: 
     raise ImplementsException(cls, t, sig) 
     cls.__implements.append(t) 
    return cls 
    return inner 


def has_api(instance, T): 
    """ Runtime check for T in type identity """ 
    rtn = False 
    if instance is not None and T is not None: 
    if inspect.isclass(instance): 
     if hasattr(instance, "__implements"): 
     if T in instance.__implements: 
      rtn = True 
    else: 
     if hasattr(instance.__class__, "__implements"): 
     if T in instance.__class__.__implements: 
      rtn = True 
    return rtn 


class ImplementsException(Exception): 
    def __init__(self, cls, T, signature): 
    msg = "Invalid @implements decorator on '%s' for interface '%s': %r" % (cls.__name__, T.__name__, signature) 
    super(ImplementsException, self).__init__(msg) 
    self.signature = signature 
2

इस साल देर से की एक जोड़ी है, लेकिन यहाँ है जिस तरह से मैंने किया: अगर CMetaClass का एक प्रयास किया वर्ग है

import abc 

class MetaClass(object): 
    __metaclass__ = abc.ABCMeta 

    [...] 

    @classmethod 
    def __subclasshook__(cls, C): 
     if C.__abstractmethods__: 
      print C.__abstractmethods__ 
      return False 
     else: 
      return True 

, तो C.__abstractmethods__ खाली ही हो जाएगा यदि C सभी अमूर्त तरीकों को लागू करता है।

जानकारी के लिए यहाँ देखें: https://www.python.org/dev/peps/pep-3119/#the-abc-module-an-abc-support-framework (यह "कार्यान्वयन" के अंतर्गत है, लेकिन __abstractmethods__ के लिए एक खोज सही अनुच्छेद पर आप मिलना चाहिए)

कहाँ यह मेरे लिए काम किया है:

मैं MetaClass बना सकते हैं। मैं SubClass बनाने के लिए BaseClass और MetaClass उपclass कर सकता हूं जिसके लिए कुछ अतिरिक्त कार्यक्षमता की आवश्यकता है।लेकिन मुझे BaseClass विशेषता को बदलकर पर एक उदाहरण डालने की आवश्यकता है क्योंकि मेरे पास BaseClass नहीं है, लेकिन मुझे इसके उदाहरण मिलते हैं जिन्हें मैं नीचे डालना चाहता हूं।

हालांकि, अगर मैं अनुचित तरीके से SubClass लागू, मैं अभी भी नीचे डाल सकता जब तक कि मैंने ऊपर __subclasshook__ का उपयोग करें और बस एक उपवर्ग जांच जोड़ने जब मैं प्रक्रिया नीचे डाली (जो मैं वैसे भी क्या करना चाहिए के बाद से मैं केवल कास्ट करने के लिए कोशिश करना चाहते हैं एक अभिभावक वर्ग नीचे)। अगर कोई अनुरोध करता है, तो मैं इसके लिए एक MWE प्रदान कर सकता हूं।

ईटीए: यहां एक MWE है। मुझे लगता है कि मैं पहले जो सुझाव दे रहा था वह गलत था, इसलिए मेरा इरादा ऐसा करने लगता है।

लक्ष्य BaseClass ऑब्जेक्ट को SubClass और वापस कनवर्ट करने में सक्षम होना है। SubClass से BaseClass से आसान है। लेकिन BaseClass से SubClass से बहुत कुछ नहीं। करने के लिए मानक बात __class__ विशेषता अद्यतन है, लेकिन SubClass वास्तव में उप-वर्ग नहीं है या एक अमूर्त मेटा वर्ग से प्राप्त नहीं होता है, लेकिन यह ठीक से कार्यान्वित नहीं किया जाता है।

नीचे, रूपांतरण convert विधि में किया गया है जो BaseMetaClass लागू करता है। हालांकि, उस तर्क में, मैं दो चीजों की जांच करता हूं। एक, सबक्लास में कनवर्ट करने के लिए, मैं जांचता हूं कि यह वास्तव में उप-वर्ग है या नहीं। दूसरा, यह देखने के लिए कि क्या यह खाली है, मैं विशेषता __abstractmethods__ विशेषता की जांच करता हूं। यदि यह है, तो यह भी एक उचित ढंग से लागू मेटाक्लास है। विफलता टाइप टाइपर की ओर ले जाती है। अन्यथा वस्तु परिवर्तित हो जाती है।

import abc 


class BaseMetaClass(object): 
    __metaclass__ = abc.ABCMeta 

    @classmethod 
    @abc.abstractmethod 
    def convert(cls, obj): 
     if issubclass(cls, type(obj)): 
      if cls.__abstractmethods__: 
       msg = (
        '{0} not a proper subclass of BaseMetaClass: ' 
        'missing method(s)\n\t' 
       ).format(
        cls.__name__ 
       ) 
       mthd_list = ',\n\t'.join(
        map(
         lambda s: cls.__name__ + '.' + s, 
         sorted(cls.__abstractmethods__) 
        ) 
       ) 
       raise TypeError(msg + mthd_list) 

      else: 
       obj.__class__ = cls 
       return obj 
     else: 
      msg = '{0} not subclass of {1}'.format(
       cls.__name__, 
       type(obj).__name__ 
      ) 
      raise TypeError(msg) 

    @abc.abstractmethod 
    def abstractmethod(self): 
     return 


class BaseClass(object): 

    def __init__(self, x): 
     self.x = x 

    def __str__(self): 
     s0 = "BaseClass:\n" 
     s1 = "x: {0}".format(self.x) 
     return s0 + s1 


class AnotherBaseClass(object): 

    def __init__(self, z): 
     self.z = z 

    def __str__(self): 
     s0 = "AnotherBaseClass:\n" 
     s1 = "z: {0}".format(self.z) 
     return s0 + s1 


class GoodSubClass(BaseMetaClass, BaseClass): 

    def __init__(self, x, y): 
     super(GoodSubClass, self).__init__(x) 
     self.y = y 

    @classmethod 
    def convert(cls, obj, y): 
     super(GoodSubClass, cls).convert(obj) 
     obj.y = y 

    def to_base(self): 
     return BaseClass(self.x) 

    def abstractmethod(self): 
     print "This is the abstract method" 

    def __str__(self): 
     s0 = "SubClass:\n" 
     s1 = "x: {0}\n".format(self.x) 
     s2 = "y: {0}".format(self.y) 
     return s0 + s1 + s2 


class BadSubClass(BaseMetaClass, BaseClass): 

    def __init__(self, x, y): 
     super(BadSubClass, self).__init__(x) 
     self.y = y 

    @classmethod 
    def convert(cls, obj, y): 
     super(BadSubClass, cls).convert(obj) 
     obj.y = y 

    def __str__(self): 
     s0 = "SubClass:\n" 
     s1 = "x: {0}\n".format(self.x) 
     s2 = "y: {0}".format(self.y) 
     return s0 + s1 + s2 


base1 = BaseClass(1) 
print "BaseClass instance" 
print base1 
print 


GoodSubClass.convert(base1, 2) 
print "Successfully casting BaseClass to GoodSubClass" 
print base1 
print 

print "Cannot cast BaseClass to BadSubClass" 
base1 = BaseClass(1) 
try: 
    BadSubClass.convert(base1, 2) 
except TypeError as e: 
    print "TypeError: {0}".format(e.message) 
    print 


print "Cannot cast AnotherBaseCelass to GoodSubClass" 
anotherbase = AnotherBaseClass(5) 
try: 
    GoodSubClass.convert(anotherbase, 2) 
except TypeError as e: 
    print "TypeError: {0}".format(e.message) 
    print 

print "Cannot cast AnotherBaseCelass to BadSubClass" 
anotherbase = AnotherBaseClass(5) 
try: 
    BadSubClass.convert(anotherbase, 2) 
except TypeError as e: 
    print "TypeError: {0}".format(e.message) 
    print 


# BaseClass instance 
# BaseClass: 
# x: 1 

# Successfully casting BaseClass to GoodSubClass 
# SubClass: 
# x: 1 
# y: 2 

# Cannot cast BaseClass to BadSubClass 
# TypeError: BadSubClass not a proper subclass of BaseMetaClass: missing method(s) 
#  BadSubClass.abstractmethod 

# Cannot cast AnotherBaseCelass to GoodSubClass 
# TypeError: GoodSubClass not subclass of AnotherBaseClass 

# Cannot cast AnotherBaseCelass to BadSubClass 
# TypeError: BadSubClass not subclass of AnotherBaseClass 
+0

कृपया, एक उदाहरण प्रदान करें – Konstantin

संबंधित मुद्दे