在 javascript 中通过原型链继承,可以实现子类继承父类的方法和属性。

function Bird() {
  this.fly = true
}
function Pigeon(){
  this.feather = 'white'
}
Pigeon.prototype = new Bird()
alert(new Pigeon().fly)

其实 Python 也可以通过代理模式实现

在 Python 的类中有个 __getattr__ 专有方法在访问 attribute 不存在的时候被调用,这和 javascript 中访问实例属性不存在时就继续访问原型链很像。

class Bird(object):
    def __init__(self):
        self.fly = True

class Pigeon(object):
    def __init__(self):
        self._a = A()
        self.feather = 'white'

    def __getattr__(self, name):
        return object.__getattribute__(self._a, name)

Pigeon().fly

Pigeon 类继承的是 Bird 类的实例属性

通过这种代理模式+装饰模式,我实现了以下需求:

  1. 多个子类具有相同的方法名,共同继承自父类
  2. 父类中实现接口,调用子类实现具体的业务功能
  3. 父类无需知道实现了哪些子类

情景演示:

class Someone(object):
    def __init__(self):
        self.speak = 'haha'

    def __getattr__(self, name):
        if not name[0].isupper():
            return object.__getattribute__(self, name)

        def __getattr(cls, name):
            return object.__getattribute__(self, name)
        try:
            cls = eval(name)
        except:
            print('No %s' % name)
            raise NotImplementedError
        cls.__getattr__ = __getattr
        instance = cls()
        setattr(self, name, instance)
        return instance

class Tom(object):
    def run(self):
        return 'running Tom'

class Jerry(object):
    def run(self):
        return 'running Jerry'

men = Someone()
print(men.speak)
print(men.Tom.run())
print(men.Jerry.run())

# haha
# running Tom
# running Jerry

子类 TOM 和 Jerry 并没有显式继承 Speaker,而且实例化的是父类 Speaker,调用子类名称空间的时候自动实例化

实际应用时,上面的类可能不在同一个文件中,这时候可以通过动态加载类或包来实现

# -*- coding: utf-8 -*-
import importlib

# someone.py
class Action(object):
    _pkg_base = 'some/path/'

    def __getattr__(self, name):
        pkg = _pkg_base + name
        try:
            module = importlib.import_module(pkg)
            Action = module.Action
        except ImportError:
            Action = object

        def __getattr(cls, name):
            return object.__getattribute__(cls._myself, name)

        Action.__getattr__ = __getattr
        instance = Action()
        instance._myself = self
        setattr(self, name, instance)
        return instance
# tom.py
class Action(object):
    def run(self):
        return 'running Tom'
# jerry.py
class Action(object):
    def run(self):
        return 'running Jerry'