Python class 抽象类

简单的方法是:
  class Sheep(object):
      def get_size(self):
          raise NotImplementedError
  任何从Sheep继承下来的子类必须实现get_size方法。否则就会产生一个错误。但这种实现方法有个缺点。定义的子类只有调用那个方法时才会抛错


抽象基类

要定义抽象基类,需要使用abc模块。该模块定义了一个元类(ABCMeta)和一组装饰器@abstractmethod,@abstractproperty。可以按如下方式使用

from abc import ABCMeta,abstractmethod,abstractproperty

class People:
    __metaclass__ = ABCMeta

    @abstractmethod
    def set_name(self):
        pass

    @abstractproperty
    def pro(self):
        pass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

要定义抽象类,需要将元类设置为ABCMeta。这一步是必须的,因为抽象类的实现离不开元类。在抽象类中,@abstractmethod和@abstractproperty装饰的方法/特性其子类必须实现。

抽象类并不能直接实例化。

f = People()  #TypeError: Can't instantiate abstract class Student with abstract methods pro, set_name
  • 1

这一限制也适用于派生类。如果类Foo1继承了Foo,但是Foo1没有实现Foo中的抽象方法,当创建Foo1的实例时,会生成类似的错误。

class Student(People):
    pass
f = Student() #TypeError: Can't instantiate abstract class Student with abstract methods pro, set_name
  • 1
  • 2
  • 3

尽管抽象类会在实现的方法和特性上强制实施规则,但它不会对参数和返回值进行一致性检查。所以,抽象类不会检查子类是否使用了与抽象方法相同的参数和返回值。

虽然抽象类无法实例化,但是它可以决定子类中必须实现的方法和特性。而且,基类中的抽象方法/特性仍然可以从子类中调用。

class Student(People):
    def set_name(self,name):                #参数个数不同
        print super(Student,self).set_name()#调用基类中的抽象方法
        print 'Student,set_name = %s'%name
        return True                         #返回值不同

    def pro(self,tmp = ''):                 #参数不同,特性->方法也是可以的,因为特性是一种特殊的函数
        print super(Student,self).pro       #调用基类中的特性
        print 'Student,pro,tmp = %s'%tmp    
        return True                         #返回值不同
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
>>> f = Student()
>>> f.set_name('xiaohong')
None
Student,set_name = xiaohong
>>> f.pro()
None
Student,pro,tmp = Null
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

类注册

抽象基类支持对已经存在的类进行注册,使其属于该基类,使用register()进行注册。

如向抽象基类A注册类B,A.register(B) 。

向抽象基类注册某个类时,对于注册类的实例,涉及抽象基类的类型检查操作(isinstance,issubclass)将返回True。

向抽象类注册某个类时,不会检查该类是否实现了抽象方法/特性。这种注册只影响类型检查,它不会向注册的类进行额外的错误检查。

from abc import ABCMeta,abstractmethod,abstractproperty

class People(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def set_name(self):
        pass

class Foo(object):#没有实现抽象方法set_name
    pass

#print People,type(People),type(type(People)),People.__metaclass__
#print Foo,type(Foo),type(type(Foo))
f = Foo()
print isinstance(f,People)     #False
print isinstance(f,Foo)        #True

print issubclass(Foo,People)   #False
print issubclass(Foo,object)   #True
print issubclass(People,object)#True

People.register(Foo)           #向People抽象基类注册,让Foo属于People
print isinstance(f,People)     #True
print isinstance(f,Foo)        #True

print issubclass(Foo,People)   #True
print issubclass(Foo,object)   #True
print issubclass(People,object)#True
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Python的内置类型组织到一个相对扁平的层次结构中。如int,float,可以看到他们直接继承自所有对象的根(object),而不是表示数字的中间基类。因此很难编写程序来根据类型检查和操作对象。抽象类机制解决了这一难题,它允许将已存在的对象组织到用户定义的类型层次结构中。


猜你喜欢

转载自blog.csdn.net/weiqubo/article/details/80192992
今日推荐