zoukankan      html  css  js  c++  java
  • 在Python中定义和使用抽象类的方法

    在Python中定义和使用抽象类的方法

    提起Java的抽象类大家都比较熟悉,Python中我们可以使用abc模块来构建抽象类,这里就为大家讲解在Python中定义和使用抽象类的方法

    像java一样python也可以定义一个抽象类。
    在讲抽象类之前,先说下抽象方法的实现。
    抽象方法是基类中定义的方法,但却没有任何实现。在java中,可以把方法申明成一个接口。而在python中实现一个抽象方法的简单的方法是:    
    class Sheep(object):
      def get_size(self):
        raise NotImplementedError

    任何从Sheep继承下来的子类必须实现get_size方法。否则就会产生一个错误。但这种实现方法有个缺点。定义的子类只有调用那个方法时才会抛错。这里有个简单方法可以在类被实例化后触发它。使用python提供的abc模块。    
    import abc
    class Sheep(object):
      __metaclass__ = abc.ABCMeta
       
      @abc.absractmethod
      def get_size(self):
        return


    这里实例化Sheep类或任意从其继承的子类(未实现get_size)时候都会抛出异常。

    因此,通过定义抽象类,可以定义子类的共同method(强制其实现)。

    如何使用抽象类    
    import abc
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      @abc.abstractmethod
      def load(self, input):
        return
     
      @abc.abstractmethod
      def save(self, output, data):
        return

    通过ABCMeta元类来创建一个抽象类, 使用abstractmethod装饰器来表明抽象方法

    注册具体类
        
    class B(object):
       
      def load(self, input):
        return input.read()
     
      def save(self, output, data):
        return output.write(data)
     
    A.register(B)
     
    if __name__ == '__main__':
      print issubclass(B, A)   # print True
      print isinstance(B(), A)  # print True

    从抽象类注册一个具体的类

    子类化实现
        
    class C(A):
     
      def load(self, input):
        return input.read()
     
      def save(self, output, data):
        return output.write(data)
         
    if __name__ == '__main__':
      print issubclass(C, A)   # print True
      print isinstance(C(), A)  # print True

    可以使用继承抽象类的方法来实现具体类这样可以避免使用register. 但是副作用是可以通过基类找出所有的具体类    
    for sc in A.__subclasses__():
      print sc.__name__
     
    # print C

    如果使用继承的方式会找出所有的具体类,如果使用register的方式则不会被找出

    使用__subclasshook__

    使用__subclasshook__后只要具体类定义了与抽象类相同的方法就认为是他的子类    
    import abc
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      @abc.abstractmethod
      def say(self):
        return 'say yeah'
     
      @classmethod
      def __subclasshook__(cls, C):
        if cls is A:
          if any("say" in B.__dict__ for B in C.__mro__):
            return True
        return NotTmplementd
     
    class B(object):
      def say(self):
        return 'hello'
     
    print issubclass(B, A)   # True
    print isinstance(B(), A)  # True
    print B.__dict__      # {'say': , ...}
    print A.__subclasshook__(B) # True

    不完整的实现    
    class D(A):
      def save(self, output, data):
        return output.write(data)
     
    if __name__ == '__main__':
      print issubclass(D, A)   # print True
      print isinstance(D(), A)  # raise TypeError

    如果构建不完整的具体类会抛出D不能实例化抽象类和抽象方法

    具体类中使用抽象基类    
    import abc
    from cStringIO import StringIO
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      @abc.abstractmethod
      def retrieve_values(self, input):
        pirnt 'base class reading data'
        return input.read()
     
     
    class B(A):
     
      def retrieve_values(self, input):
        base_data = super(B, self).retrieve_values(input)
        print 'subclass sorting data'
        response = sorted(base_data.splitlines())
        return response
     
    input = StringIO("""line one
    line two
    line three
    """)
     
    reader = B()
    print reader.retrieve_values(input)

    打印结果    
    base class reading data
    subclass sorting data
    ['line one', 'line two', 'line three']

    可以使用super来重用抽象基类中的罗辑, 但会迫使子类提供覆盖方法.

    抽象属性    
    import abc
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      @abc.abstractproperty
      def value(self):
        return 'should never get here.'
     
    class B(A):
       
      @property
      def value(self):
        return 'concrete property.'
     
    try:
      a = A()
      print 'A.value', a.value
    except Exception, err:
      print 'Error: ', str(err)
     
    b = B()
    print 'B.value', b.value

    打印结果,A不能被实例化,因为只有一个抽象的property getter method.    
    Error: ...
    print concrete property

    定义抽象的读写属性    
    import abc
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      def value_getter(self):
        return 'Should never see this.'
     
      def value_setter(self, value):
        return
     
      value = abc.abstractproperty(value_getter, value_setter)
     
    class B(A):
       
      @abc.abstractproperty
      def value(self):
        return 'read-only'
     
    class C(A):
      _value = 'default value'
     
      def value_getter(self):
        return self._value
     
      def value_setter(self, value):
        self._value = value
     
      value = property(value_getter, value_setter)
     
    try:
      a = A()
      print a.value
    except Exception, err:
      print str(err)
     
    try:
      b = B()
      print b.value
    except Exception, err:
      print str(err)
     
    c = C()
    print c.value
     
    c.value = 'hello'
    print c.value

    打印结果, 定义具体类的property时必须与抽象的abstract property相同。如果只覆盖其中一个将不会工作.    
    error: ...
    error: ...
    print 'default value'
    print 'hello'

    使用装饰器语法来实现读写的抽象属性, 读和写的方法应该相同.    
    import abc
     
    class A(object):
      __metaclass__ = abc.ABCMeta
     
      @abc.abstractproperty
      def value(self):
        return 'should never see this.'
     
      @value.setter
      def value(self, _value):
        return
     
    class B(A):
      _value = 'default'
     
      @property
      def value(self):
        return self._value
     
      @value.setter
      def value(self, _value):
        self._value = _value
     
    b = B()
    print b.value    # print 'default'
     
    b.value = 'hello'
    print b.value    # print 'hello'

  • 相关阅读:
    Java异常处理和设计
    一次qps测试实践
    Alternate Task UVA
    Just Another Problem UVA
    Lattice Point or Not UVA
    Play with Floor and Ceil UVA
    Exploring Pyramids UVALive
    Cheerleaders UVA
    Triangle Counting UVA
    Square Numbers UVA
  • 原文地址:https://www.cnblogs.com/amengduo/p/9586748.html
Copyright © 2011-2022 走看看