Python is an abstract base class

1. said ahead

"Abstract base class" is the word might listen more "profound" that the "base class" is the "parent", "abstract" is "false" means,

"Abstract base class" is "false parent."

Supplement 2. Before yuan class

Yuan said before by grammar class is instantiated class

变量名 = type("类名", ("继承的类",), {"属性名":"属性值"})

Now introduce another method

class 类名(metaclass=元类名):
    ...

for example:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# __author__: kainhuck

# 定义一个元类
class MyMetaClass(type):
    def __new__(cls, name, bases, attrs):
        '''
        :param name: 类名
        :param bases: 继承的基类
        :param attrs: 拥有的属性

        要求必须含有name属性

        '''
        name = attrs.get("name", None)
        if name and not callable(name):
            return type.__new__(cls, name, bases, attrs)
        raise NotImplementedError("必须含有name属性")


# 定义普通类
# class MyClassA(metaclass=MyMetaClass):     # 报错,没有定义name属性
#     pass

# 定义普通类
# class MyClassB(metaclass=MyMetaClass):  # 报错,没有定义name属性
#     def name(self):
#         pass

#
# class MyClassC(metaclass=MyMetaClass):  # 报错,没有定义name属性
#     def __init__(self):
#         self.name = "kainhuck"

#
class MyClassD(metaclass=MyMetaClass):  # 没有报错
    name = "kainhuck"

3. Ducks type

Ducks type: if a thing looks like to a duck and quacks like a duck, then it probably is a duck.

In Python, there are times when we need to have a certain function (for example: a duck call) objects, then we can determine the object is not a duck to detect meets our needs; but think about this some flaws, because we really need is 鸭子叫this method, an object whether it is not a duck as long as he would be called like a duck to be all right.

Words may be some around, let me give you an example

There is such a function:

def func(something):
    print(something[0])

This function will print out the first element of the argument, in fact, this implies a condition - parameter support subscript index to make the code to improve we should do something to modify the function.

Option One.

def func(something):
    if isinstance(something, (list, tuple, set)):   # 这些方法支持下标索引
        print(something[0])
    else:
        print("Error")

Option One drawback:

Write to default to type something define, develop poor

We know that as long as the custom class that implements the __getitem__method can be used to support the subscript index.

Option II.

def func(something):
    if hasattr(something, '__getitem__'):   
        print(something[0])
    else:
        print("Error")

Option Two drawbacks:

Not all realize __getitem__the method can support subscript index, such as 字典type

Such seems to be no solution .. In fact, the abstract base class on the perfect solution to this problem

4. The abstract base class

1. The abstract base class definition:

Abc.ABCMeta implemented by a metaclass is a class abstract base class, such as

class AbstractClass(metaclass=abc.ABCMeta):
    pass

2. register method

Defined by the abstract base class registercan be a method other super class

for example:

import abc

# 定义一个抽象基类
class AbstractClass(metaclass=abc.ABCMeta):
    pass

# 定义一个普通类继承自object
class MyClass(object):
    pass

# 把我们定义的抽象基类注册为MyClass的父类
AbstractClass.register(MyClass)
mc = MyClass()
print(issubclass(MyClass, AbstractClass))  # 输出True
print(isinstance(mc, AbstractClass))  # 输出True

# 将我们定义的抽象基类注册到系统定义的类
AbstractClass.register(list)

print(isinstance([], AbstractClass))    # 输出True

Point: Although the abstract base class can become another class of the parent class, but the other classes will not inherit the abstract base class methods and properties of

3. scheme implemented in the previous example three

third solution.

from abc import ABCMeta

class MySequence(metaclass=ABCMeta):
    pass

MySequence.register(list)   # 注册为列表的父类
MySequence.register(tuple)  # 注册为元组的父类

'''
也可以自定义一个类,将MySequence注册为其父类
'''
def func(something):
    if isinstance(something, AbstractClass):    # AbstractClass的子类
        print(something[0])
    else:
        print("Error")

4. __subclasshook__Magic Method

Read the example above, you would definitely feel that, for each class registered over abstract base class too much trouble, yes Python developers think so too, so __subclasshook__this method appeared

Some explanations:

  1. This method is defined in the abstract base class
  2. The method must be defined as a class method
  3. This method has three return value
    1. True: If the test is considered to be a subclass of class
    2. False: If the test class is not considered a subclass
    3. NotImplemented: The talk behind

Definition of an abstract base class:

import abc

class AbstractDuck(metaclass=abc.ABCMeta):
    @classmethod
    def __subclasshook__(cls, subclass):
        quack = getattr(subclass, 'quack', None)  # 取出subclass的 quack 属性,如果不存在则返回 None
        return callable(quack)  # 返回quack是否可以调用(是否是个方法)

Define two test classes

class Duck(object):
    def quack(self):
        pass


class NotDuck(object):
    quack = "foo"

Determines whether the subclass AbstractDuck

print(issubclass(Duck, AbstractDuck))  # 输出 True
print(issubclass(NotDuck, AbstractDuck))  # 输出 False

Note: __subclasshook__The method of priority higher thanregister

For example explains NotImplementedthe return value

In [6]: import abc                                                                                                                                   

In [7]: class AbstractDuck(metaclass=abc.ABCMeta): 
   ...:     @classmethod 
   ...:     def __subclasshook__(cls, subclass): 
   ...:         quack = getattr(subclass, 'quack', None)  # 取出subclass的 quack 属性,如果不存在则返回 None 
   ...:         if callable(quack): 
   ...:             return True 
   ...:         return NotImplemented 
   ...:                                                                                                                                                                                                                                                                                   

In [8]: class Duck(object): 
   ...:     def quack(self): 
   ...:         pass 
   ...:                                                                                                                                              

In [9]: class NotDuck(object): 
   ...:     quack = "foo" 
   ...:                                                                                                                                                                                                                                                           

In [10]: issubclass(NotDuck, AbstractDuck)                                                                                                           
Out[10]: False

In [11]: AbstractDuck.register(NotDuck)                                                                                                              
Out[11]: __main__.NotDuck

In [12]: issubclass(NotDuck, AbstractDuck)                                                                                                           
Out[12]: True

Guess you like

Origin www.cnblogs.com/kainhuck/p/11220549.html