{"id":21497997,"url":"https://github.com/meteorix/python-design-patterns","last_synced_at":"2025-07-15T21:30:41.145Z","repository":{"id":62815672,"uuid":"139655711","full_name":"Meteorix/python-design-patterns","owner":"Meteorix","description":"Python设计模式","archived":false,"fork":false,"pushed_at":"2019-02-05T13:22:27.000Z","size":12,"stargazers_count":53,"open_issues_count":0,"forks_count":14,"subscribers_count":8,"default_branch":"master","last_synced_at":"2023-09-02T09:41:47.725Z","etag":null,"topics":["desing-patterns","python","python-patterns"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Meteorix.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-04T01:56:28.000Z","updated_at":"2023-03-01T04:39:52.000Z","dependencies_parsed_at":"2022-11-07T06:45:39.706Z","dependency_job_id":null,"html_url":"https://github.com/Meteorix/python-design-patterns","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteorix%2Fpython-design-patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteorix%2Fpython-design-patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteorix%2Fpython-design-patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteorix%2Fpython-design-patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Meteorix","download_url":"https://codeload.github.com/Meteorix/python-design-patterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226069253,"owners_count":17568939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["desing-patterns","python","python-patterns"],"created_at":"2024-11-23T16:33:31.636Z","updated_at":"2024-11-23T16:33:32.292Z","avatar_url":"https://github.com/Meteorix.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Python Design Patterns\n=======================\n\n如何写出更好的代码——刘欣 2018.6.20\n\n\u003e \"Design patterns help you learn from others’ successes instead of your own failures\"\n\n断断续续读了好久设计模式，记录此篇总结。设计模式最初发源于C++/Java等静态语言，Python语言本身的很多特性已经覆盖了设计模式，甚至用了都不知道，比如：decorator/metaclass/generator/getattr等。但是写稍微大型的项目时，还是经常力不从心。就如上面引用的那句话，通过设计模式可以学习前人的智慧，写出更好的代码。\n\n所有代码都在[https://github.com/Meteorix/python-design-patterns](https://github.com/Meteorix/python-design-patterns)，python3环境下可以跑通，请跑起来玩玩。代码仅限演示作用，更注重清晰地用python语法展示patterns，而不是完备性，请勿用在生产环境。欢迎提issue和pr : )\n\n## 设计模式六大原则\n\n\n1. 单一职责原则\n    * 一个类只做一件事情，模块化\n\n1. 里氏替换原则\n    * 所有使用父类的地方必须能完全替换为使用其子类\n    * 即：子类可以扩展父类的功能，但不能改变父类原有的功能\n\n1. 依赖倒置原则\n    * 高层模块不应该依赖低层模块，二者都应该依赖其抽象\n    * 抽象不应该依赖实现；实现应该依赖抽象\n    * 面向接口编程，而不是面向实现编程，Duck Type\n\n1. 接口隔离原则\n    * 一个类对另一个类依赖的接口越少越好\n\n1. 最小知识原则\n    * 一个类对另一个类知道得越少越好\n\n1. 开闭原则\n    * 类、模块、函数对扩展开放，对修改关闭\n    * 尽量在不修改源代码的情况下进行扩展\n\n\n\u003e 其实以上的原则不限于类的设计，很多工程上的系统设计也适用。\n\n\n## 常用设计模式\n\n### 创造模式\n#### Singleton\n\n一个类只有一个对象，似乎不太需要解释：）\n\n```python\nclass SingletonMeta(type):\n\n    instance = None\n\n    def __call__(cls, *args, **kwargs):\n        if cls.instance is None:\n            cls.instance = super(SingletonMeta, cls).__call__(*args, **kwargs)\n        return cls.instance\n\n\nclass CurrentUser(object, metaclass=SingletonMeta):\n\n    def __init__(self, name=None):\n        super(CurrentUser, self).__init__()\n        self.name = name\n\n    def __str__(self):\n        return repr(self) + \":\" + repr(self.name)\n\n\nif __name__ == '__main__':\n    u = CurrentUser(\"liu\")\n    print(u)\n    u2 = CurrentUser()\n    u2.name = \"xin\"\n    print(u2)\n    print(u)\n    assert u is u2\n```\n\n这个例子用MetaClass实现，其实Python里还有其他实现方式。但是Python里的MetaClass就是用来实例化Class的，用来实现单例类正好。\n\n\n#### Factory\n\n工厂模式，用于生产一大堆对象。这里用``__subclasses__``来获取子类，这样可以动态扩展子类而不改变factory的代码。\n```python\nclass Shape(object):\n    @classmethod\n    def factory(cls, name, *args, **kwargs):\n        types = {c.__name__: c for c in cls.__subclasses__()}  # 忽略性能:P\n        shape_class = types[name]\n        return shape_class(*args, **kwargs)\n\n\nclass Circle(Shape):\n    pass\n\n\nclass Square(Shape):\n    pass\n\n\nif __name__ == '__main__':\n    shapes = [\"Circle\", \"Square\", \"Square\", \"Circle\"]\n    for i in shapes:\n        s = Shape.factory(i)\n        print(s)\n```\n\n\n### 结构模式\n\n#### MVC\n可能是最有名的设计模式，``数据\u003c-\u003e控制器\u003c-\u003e视图``。数据和视图分离，还可以同一份数据渲染多个视图。MVC做的最好的应该是各种Web框架和GUI框架。\n```python\nclass Model(object):\n    products = {\n        'milk': {'price': 1.50, 'quantity': 10},\n        'eggs': {'price': 0.20, 'quantity': 100},\n        'cheese': {'price': 2.00, 'quantity': 10}\n    }\n\n    def get(self, name):\n        return self.products.get(name)\n\n\nclass View(object):\n    def show_item_list(self, item_list):\n        print('-' * 20)\n        for item in item_list:\n            print(\"* Name: %s\" % item)\n        print('-' * 20)\n\n    def show_item_info(self, name, item_info):\n        print(\"Name: %s Price: %s Quantity: %s\" % (name, item_info['price'], item_info['quantity']))\n        print('-' * 20)\n\n    def show_empty(self, name):\n        print(\"Name: %s not found\" % name)\n        print('-' * 20)\n\n\nclass Controller(object):\n    def __init__(self, model, view):\n        self.model = model\n        self.view = view\n\n    def show_items(self):\n        items = self.model.products.keys()\n        self.view.show_item_list(items)\n\n    def show_item_info(self, item):\n        item_info = self.model.get(item)\n        if item_info:\n            self.view.show_item_info(item, item_info)\n        else:\n            self.view.show_empty(item)\n\n\nif __name__ == '__main__':\n    model = Model()\n    view = View()\n    controller = Controller(model, view)\n    controller.show_items()\n    controller.show_item_info('cheese')\n    controller.show_item_info('apple')\n```\n上面的例子还只演示了数据到视图的渲染，其实MVC还包括通过视图修改数据。\n\n#### Proxy\n不直接调用一个类，而是通过一个代理来访问。这样做的好处有：可以切换底层实现、权限控制、安全检查等。当然最有用的是可以实现远程代理，jsonrpc就是一种。\n```python\nclass Implementation(object):\n    def add(self, x, y):\n        return x + y\n\n    def minus(self, x, y):\n        return x - y\n\n\nclass Proxy(object):\n    def __init__(self, impl):\n        self._impl = impl\n\n    def __getattr__(self, name):\n        return getattr(self._impl, name)\n\n\nif __name__ == '__main__':\n    p = Proxy(Implementation())\n    print(p.add(1, 2))\n    print(p.minus(1, 2))\n```\n\n#### Decorator\n\n装饰器，似乎不太需要解释，Python自带的语法，可以用来做很多事情，几个简单例子：\n\n*   路由\n\n```python\nfrom flask import Flask\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n    return 'Hello, World'\n\n@app.route('/home')\ndef home():\n    return 'Welcome Home'\n```\n\n*   权限控制\n\n```python\nfrom django.contrib.auth.decorators import login_required\n\n@login_required\ndef my_view(request):\n    ...\n```\n\n*   输入输出\n\n```python\nfrom functools import wraps\n\n\ndef debug(f):\n    @wraps(f)\n    def debug_function(*args, **kwargs):\n        print('call: ', f.__name__, args, kwargs)\n        ret = f(*args, **kwargs)\n        print('return: ', ret)\n    return debug_function\n\n\n@debug\ndef foo(a, b, c=None):\n    print(a, b, c)\n    return True\n\n\nif __name__ == '__main__':\n    foo(1, 2, 3)\n```\n\n\n\n\n### 行为模式\n\n#### Template\n\n基类作为模板，定义好接口，子类来实现功能，最好的例子就是Qt里的各种QWidget。\n\n```python\nclass ApplicateFramework(object):\n    def __init__(self):\n        self.setup()\n        self.show()\n\n    def setup(self):\n        pass\n\n    def show(self):\n        pass\n\n    def close(self):\n        pass\n\n\nclass MyApplication(ApplicateFramework):\n    def setup(self):\n        print(\"setup\", self)\n\n    def show(self):\n        print(\"show\", self)\n\n    def close(self):\n        print(\"close\", self)\n\n\nif __name__ == '__main__':\n    app = MyApplication()\n    app.close()\n```\n\n#### State Machine\n状态机，`当前状态 + 操作 =\u003e 下一个状态`，似乎也不用怎么解释。如下例子实现的状态机，可以自定义状态、操作和转换规则。扩展的时候无需修改状态机代码，符合**开闭原则**。\n\n```python\nclass StateMachine(object):\n\n    def __init__(self, init_state):\n        self.current_state = init_state\n        self.current_state.run()\n\n    def step(self, action):\n        self.current_state = self.current_state.next(action)\n        self.current_state.run()\n\n\nclass State(object):\n    def __init__(self, name):\n        self.name = name\n\n    def __str__(self):\n        return \"\u003cState '%s'\u003e\" % self.name\n\n    def next(self, action):\n        if (self, action) in mapping:\n            next_state = mapping[(self, action)]\n        else:\n            next_state = self\n        print(\"%s + %s =\u003e %s\" % (self, action, next_state))\n        return next_state\n\n    def run(self):\n        print(self, \"is current state\")\n\n\nclass Action(object):\n    def __init__(self, name):\n        self.name = name\n\n    def __str__(self):\n        return \"\u003cAction '%s'\u003e\" % self.name\n\n\nState.Running = State(\"Running\")\nState.Stopped = State(\"Stopped\")\nState.Paused = State(\"Paused\")\n\nAction.start = Action(\"start\")\nAction.stop = Action(\"stop\")\nAction.pause = Action(\"pause\")\nAction.resume = Action(\"resume\")\n\n\nmapping = {\n    (State.Stopped, Action.start): State.Running,\n    (State.Running, Action.stop): State.Stopped,\n    (State.Running, Action.pause): State.Paused,\n    (State.Paused, Action.resume): State.Running,\n    (State.Paused, Action.stop): State.Stopped,\n}\n\n\nif __name__ == '__main__':\n    state_machine = StateMachine(State.Stopped)\n    state_machine.step(Action.start)\n    state_machine.step(Action.pause)\n    state_machine.step(Action.resume)\n    state_machine.step(Action.stop)\n```\n\n#### Iterator\n\n迭代器，在Python中也不需要怎么解释，使用起来好像理所应当一样。实际上迭代器的一大优势是无需关心数据类型，一样的``for``语法。另一大优势是无需事先计算好所有元素，而是在迭代到的时候才计算。如下例子是Python中使用`yield`语法产生生成器`generator`来实现的迭代器，优势一目了然。\n```python\ndef fibonacci(count=100):\n    a, b = 1, 2\n    yield a\n    yield b\n    while count:\n        a, b = b, a + b\n        count -= 1\n        yield b\n\n\nfor i in fibonacci():\n    print(i)\n```\n\n#### Command\n\nCommand封装了一个原子操作，在类外面实现，个人认为最大的作用是实现``redo/undo``。\n```python\nfrom collections import deque\n\n\nclass Document(object):\n    value = \"\"\n    cmd_stack = deque()\n\n    @classmethod\n    def execute(cls, cmd):\n        cmd.redo()\n        cls.cmd_stack.append(cmd)\n\n    @classmethod\n    def undo(cls):\n        cmd = cls.cmd_stack.pop()\n        cmd.undo()\n\n\nclass AddTextCommand(object):\n    def __init__(self, text):\n        self.text = text\n\n    def redo(self):\n        Document.value += self.text\n\n    def undo(self):\n        Document.value = Document.value[:-len(self.text)]\n\n\nif __name__ == '__main__':\n    cmds = [AddTextCommand(\"liu\"), AddTextCommand(\"xin\"), AddTextCommand(\"heihei\")]\n    for cmd in cmds:\n        Document.execute(cmd)\n        print(Document.value)\n\n    for i in range(len(cmds)):\n        Document.undo()\n        print(Document.value)\n```\n\n#### Chain Of Responsibility\n链式Handler处理请求，某一个处理成功就返回。用Chain来动态构造Handler序列。\n```python\nclass Handler(object):\n\n    def __init__(self):\n        self.successor = None\n\n    def handle(self, data):\n        res = self._handle(data)\n        if res:\n            return res\n        if self.successor:\n            return self.successor.handle(data)\n\n    def _handle(self, data):\n        raise NotImplementedError\n\n    def link(self, handler):\n        self.successor = handler\n        return handler\n\n\nclass DictHandler(Handler):\n    def _handle(self, data):\n        if isinstance(data, dict):\n            print(\"handled by %s\" % self)\n            return True\n\n\nclass ListHandler(Handler):\n    def _handle(self, data):\n        if isinstance(data, list):\n            print(\"handled by %s\" % self)\n            return True\n\n\nif __name__ == '__main__':\n    h = DictHandler()\n    h.link(ListHandler()).link(Handler())\n    ret = h.handle([1, 2, 3])\n    ret = h.handle({1: 2})\n```\n\n\n#### Chaining Method\n\n链式反应，就这样一直点下去。很多Query构造函数是这样，API更好用。\n\n```python\nclass Player(object):\n    def __init__(self, name):\n        self.pos = (0, 0)\n\n    def move(self, pos):\n        self.pos = pos\n        print(\"move to %s, %s\" % self.pos)\n        return self\n\n    def say(self, text):\n        print(text)\n        return self\n\n    def home(self):\n        self.pos = (0, 0)\n        print(\"I am home\")\n        return self\n\n\nif __name__ == '__main__':\n    p = Player('liuxin')\n    p.move((1, 1)).say(\"haha\").move((2, 3)).home().say(\"go to sleep\")\n```\n\n#### Visitor\nVisitor模式的目的是不改变原来的类，用另一个类来实现一些接口。下面的例子用Visitor模式实现了两种节点遍历的方法。\n```python\nclass Node(object):\n    def __init__(self, name, children=()):\n        self.name = name\n        self.children = list(children)\n\n    def __str__(self):\n        return '\u003cNode %s\u003e' % self.name\n\n\nclass Visitor(object):\n\n    @classmethod\n    def visit(cls, node):\n        yield node\n        for child in node.children:\n            yield child\n\n    @classmethod\n    def visit2(cls, node):\n        for child in node.children:\n            yield child\n        yield node\n\n\nif __name__ == '__main__':\n    root = Node('root', (Node('a'), Node('b')))\n    visitor = Visitor()\n    for node in visitor.visit(root):\n        print(node)\n    for node in visitor.visit2(root):\n        print(node)\n```\n\n#### Observer\n当一个对象发生状态变化时，需要更新其他对象，用观察者模式来解耦这些对象，最小知识原则。\n```python\nclass Observable(object):\n\n    def __init__(self):\n        self._observers = []\n\n    def attach(self, observer):\n        if observer not in self._observers:\n            self._observers.append(observer)\n\n    def detach(self, observer):\n        self._observers.remove(observer)\n\n    def notify(self):\n        for observer in self._observers:\n            observer.update(self)\n\n\nclass Observer(object):\n    def update(self, observable):\n        print('updating %s by %s' % (self, observable))\n\n\nif __name__ == '__main__':\n    clock = Observable()\n    user1 = Observer()\n    user2 = Observer()\n    clock.attach(user1)\n    clock.attach(user2)\n    clock.notify()\n```\n\n上面的例子演示了最简单的实现，通常在实际程序中观察者模式会在不同线程中，要注意线程安全的问题。\n\n## 参考链接\n*   [python-patterns](https://github.com/faif/python-patterns)\n*   [python-3-patterns-idioms](http://python-3-patterns-idioms-test.readthedocs.io/en/latest/index.html)\n*   [设计模式六大原则](http://www.uml.org.cn/sjms/201211023.asp)\n*   [设计模式一句话总结](https://zhuanlan.zhihu.com/p/28737945)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteorix%2Fpython-design-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeteorix%2Fpython-design-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteorix%2Fpython-design-patterns/lists"}