diff --git a/A 动机与模式/10 跑起来了/1 起点.py b/A 动机与模式/10 跑起来了/1 起点.py index bcffb86..2d67fa5 100644 --- a/A 动机与模式/10 跑起来了/1 起点.py +++ b/A 动机与模式/10 跑起来了/1 起点.py @@ -1,4 +1,5 @@ -# 引入停用词表和测试文件的路径 +# -*- coding: utf-8 -*- + from cppy.cp_util import stopwordfilepath, testfilepath # 准备停用词表 @@ -52,4 +53,6 @@ for tf in word_freqs[:10]: ''' 想到哪里写到哪里,只会Python语言最基础的语法,C语言编程风格 。 +所有逻辑,所有细节一盘大棋摆在面前。 +这样的代码,很难维护。后来的阅读者会进入一个一望无际的泥塘. ''' \ No newline at end of file diff --git a/A 动机与模式/11 封装/1 函数封装/1 全局变量.py b/A 动机与模式/11 封装/1 函数封装/1 全局变量.py index aa37ebe..d28ea9e 100644 --- a/A 动机与模式/11 封装/1 函数封装/1 全局变量.py +++ b/A 动机与模式/11 封装/1 函数封装/1 全局变量.py @@ -1,3 +1,6 @@ +''' +给代码片段命名,打包成函数。用函数名概括问题求解的过程,方便阅读理解。 +''' import string from collections import Counter from cppy.cp_util import * diff --git a/A 动机与模式/11 封装/1 函数封装/2 临时变量传递.py b/A 动机与模式/11 封装/1 函数封装/2 临时变量传递.py index 1059799..51d9b7e 100644 --- a/A 动机与模式/11 封装/1 函数封装/2 临时变量传递.py +++ b/A 动机与模式/11 封装/1 函数封装/2 临时变量传递.py @@ -1,7 +1,13 @@ +''' +消除全局变量,限定函数只有输入输出来和外界打交道。 +如果消除无用的中间变量,那么就是典型的数据处理流水线风格:我要在一个函数中,完成某个操作,然后调用下一个函数进行处理 。 +流水线风格阅读方便、提供栈性能优化的可能 。 +如果需要加参数,那么需要柯里化方法(即Python里面的闭包函数结构) +''' + import re from cppy.cp_util import * - def extractwords(str_data): pattern = re.compile('[\W_]+') word_list = pattern.sub(' ', str_data).lower().split() diff --git a/A 动机与模式/11 封装/1 函数封装/3 常见风格.py b/A 动机与模式/11 封装/1 函数封装/3 常见风格.py index 38bb19c..74c45e9 100644 --- a/A 动机与模式/11 封装/1 函数封装/3 常见风格.py +++ b/A 动机与模式/11 封装/1 函数封装/3 常见风格.py @@ -1,3 +1,8 @@ +''' +把一些公共函数分离出去,保留中间变量来增加代码可读性。 +在 jupyter notebook 做分析常常如此。 +''' + import re from collections import Counter from cppy.cp_util import * diff --git a/A 动机与模式/11 封装/1 函数封装/4 递归.py b/A 动机与模式/11 封装/1 函数封装/4 递归.py index d38efa5..e75ddc6 100644 --- a/A 动机与模式/11 封装/1 函数封装/4 递归.py +++ b/A 动机与模式/11 封装/1 函数封装/4 递归.py @@ -1,3 +1,5 @@ +''' 递归是基础编程思维产生的代码结构 。注意递归深度限制只能解决小规模问题 ''' + from cppy.cp_util import * from collections import Counter diff --git a/A 动机与模式/11 封装/2 对象封装/1 对象封装.py b/A 动机与模式/11 封装/2 对象封装/1 对象封装.py index 4d251b8..e80d8ae 100644 --- a/A 动机与模式/11 封装/2 对象封装/1 对象封装.py +++ b/A 动机与模式/11 封装/2 对象封装/1 对象封装.py @@ -1,3 +1,10 @@ +''' +对象化的视角看待问题是抽象出问题中的实体。 +实体有方法、属性。程序执行过程,就是调动这些实体的交互行为 。 +作为彻底的面向对象的风格,主逻辑常常也写做一个类,init 产生各个工具,run 运行逻辑 。 +本例中实体可理解为几个工具。 +''' + from collections import Counter from cppy.cp_util import * diff --git a/A 动机与模式/11 封装/2 对象封装/2 字典仿真对象.py b/A 动机与模式/11 封装/2 对象封装/2 字典仿真对象.py index ea5a5b1..6f53a3b 100644 --- a/A 动机与模式/11 封装/2 对象封装/2 字典仿真对象.py +++ b/A 动机与模式/11 封装/2 对象封装/2 字典仿真对象.py @@ -1,8 +1,11 @@ from cppy.cp_util import * -# -# 简单使用字典,也能满足对象的一些应用场景。而且更省资源 -# +''' +如果认为基于数据和函数的封装就是对象化编程。那么类并不是必要的,扩展的函数、字典也有这个能力。 +函数利用属性存数据,字典有的value是函数,有的是value是数据 。 +字典进行对象化程序设计,只是缺乏权限控制机制,而继承方面可以是通过一个代理模式包装实现。 +简单使用字典,也能满足对象的一些应用场景。而且更省资源 +''' def extract_words(obj, path_to_file): """ diff --git a/A 动机与模式/11 封装/2 对象封装/3 对象接口/对象接口_标准.py b/A 动机与模式/11 封装/2 对象封装/3 对象接口/对象接口_标准.py index 4115501..9b61b71 100644 --- a/A 动机与模式/11 封装/2 对象封装/3 对象接口/对象接口_标准.py +++ b/A 动机与模式/11 封装/2 对象封装/3 对象接口/对象接口_标准.py @@ -1,9 +1,13 @@ import abc, re from cppy.cp_util import * -# -# 接口 -# +''' +如果在基类层面上进行设计,这样就能获得多个子类同一层面上的抽象操作。 +在一些语言里面,这种模式叫基于接口的编程,接口要求纯抽象类。 +Python 因为对象协议的缘故,所以抽象接口设计不是必须。 +沿用抽象接口设计是为工程性规整 。 +''' + class IDataStorage (metaclass=abc.ABCMeta): @abc.abstractmethod def words(self): diff --git a/A 动机与模式/12 语言特性/2 暂停执行/1 生成器.py b/A 动机与模式/12 语言特性/2 暂停执行/1 生成器.py index 0039fd6..205f34e 100644 --- a/A 动机与模式/12 语言特性/2 暂停执行/1 生成器.py +++ b/A 动机与模式/12 语言特性/2 暂停执行/1 生成器.py @@ -1,7 +1,7 @@ from cppy.cp_util import * # -# 生成器 +# 生成器 是一种简单异步实现 # def non_stop_words(testfilepath): stopwords = get_stopwords() diff --git a/A 动机与模式/12 语言特性/2 暂停执行/2 异步.py b/A 动机与模式/12 语言特性/2 暂停执行/2 异步.py index 0d04460..dea42cd 100644 --- a/A 动机与模式/12 语言特性/2 暂停执行/2 异步.py +++ b/A 动机与模式/12 语言特性/2 暂停执行/2 异步.py @@ -3,10 +3,16 @@ import aiofiles from collections import Counter from cppy.cp_util import * +''' +异步指程序运行期间具有挂起,然后等待唤醒,继续执行的能力。 +典型应用场景如数据 +① 源源不断产生,比如网络监听; +② 太大,可能大于内存; +③ 有连续处理动作,当某一环得到想要结果,立刻终止,后续数据不需要处理 。 + +本例,读文件的Io还是太快,的爬虫 +''' -# -# 协程: 有点复杂; 读文件的Io还是太快,的爬虫 -# async def read_file(file_path): async with aiofiles.open(file_path, 'r', encoding='utf-8') as file: content = await file.read() diff --git a/A 动机与模式/12 语言特性/3 动态读写PyObject/1 内省/1 内省.py b/A 动机与模式/12 语言特性/3 动态读写PyObject/1 内省/1 内省.py index d44cafa..7ef3ed0 100644 --- a/A 动机与模式/12 语言特性/3 动态读写PyObject/1 内省/1 内省.py +++ b/A 动机与模式/12 语言特性/3 动态读写PyObject/1 内省/1 内省.py @@ -1,5 +1,7 @@ from cppy.cp_util import * +# 内省(Introspection)在编程中是指程序在运行时检查对象(变量)类型或属性的能力。 +# 这是一种动态地了解对象的方法,非常有利于调试、优化代码、实现泛型编程等场景。 class Calculator: def frequencies(self,word_list): diff --git a/A 动机与模式/12 语言特性/3 动态读写PyObject/2 反射/反射_函数.py b/A 动机与模式/12 语言特性/3 动态读写PyObject/2 反射/反射_函数.py index beec00e..06976cc 100644 --- a/A 动机与模式/12 语言特性/3 动态读写PyObject/2 反射/反射_函数.py +++ b/A 动机与模式/12 语言特性/3 动态读写PyObject/2 反射/反射_函数.py @@ -1,3 +1,8 @@ +''' +反射是一种动态地访问或修改对象状态和行为的能力,包括其属性、方法等。 +有被 Hacker 攻击的风险。 +''' + import cppy.cp_util as util import operator diff --git a/A 动机与模式/13 工程化考虑/1 复用/函数调用复用.py b/A 动机与模式/13 工程化考虑/1 复用/函数调用复用.py index 8c57113..dcffbdc 100644 --- a/A 动机与模式/13 工程化考虑/1 复用/函数调用复用.py +++ b/A 动机与模式/13 工程化考虑/1 复用/函数调用复用.py @@ -1,7 +1,11 @@ from collections import Counter from cppy.cp_util import * -# 缓存系统,使用字典来存储文件路径和对应的词频结果; 可以存到本地磁盘,就可重复利用计算结果 +''' +如果函数设计干净(没有修改全局变量),那么相同的调用参数就会得到必然相同的结果。 +【缓存】把每次计算输入、输出存起来,如果后面有相同的任务(调用参数相同),就不用重复计算了。 +''' + word_freq_cache = {} def calculate_word_frequency(file_path): diff --git a/A 动机与模式/13 工程化考虑/1 复用/对象复用.py b/A 动机与模式/13 工程化考虑/1 复用/对象复用.py index c70e464..34d4211 100644 --- a/A 动机与模式/13 工程化考虑/1 复用/对象复用.py +++ b/A 动机与模式/13 工程化考虑/1 复用/对象复用.py @@ -1,4 +1,6 @@ # 创建对象是消耗资源的,如果发现对象已经存在,可以返回引用,不创造新对象 。设计模式中这个做法叫享元 +# 可以降低资源需求和提升响应速度。更常见的该模式使用场景是各种资源池。 + from cppy.cp_util import * #享元类 diff --git a/A 动机与模式/13 工程化考虑/2 松耦合/2 插件/plugin.py b/A 动机与模式/13 工程化考虑/2 松耦合/2 插件/plugin.py index d724647..67012d2 100644 --- a/A 动机与模式/13 工程化考虑/2 松耦合/2 插件/plugin.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/2 插件/plugin.py @@ -1,3 +1,7 @@ + +# 插件模式提供一种个别扩展性开发和系统核心开发无关的松耦合结构。 +# 简单说,第三方开发者在没有核心框架源码下也能扩展或者改造系统功能 + import configparser, importlib.machinery from cppy.cp_util import * diff --git a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/restful/app.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/restful/app.py index 661e7de..d4b9b3d 100644 --- a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/restful/app.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/restful/app.py @@ -1,3 +1,7 @@ +''' +REST 风格是把数据资源拓展到了互联网环境,用Web协议访问 。 +组件可以用任何环境任何语言开发, 只需要遵循共同的 rest 协议 。 +''' # -*- coding: utf-8 -*- from flask import Flask, request, jsonify, abort from functools import lru_cache diff --git a/A 动机与模式/17 其它/数据库做中介/ORM/DataQuery.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/DataQuery.py similarity index 100% rename from A 动机与模式/17 其它/数据库做中介/ORM/DataQuery.py rename to A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/DataQuery.py diff --git a/A 动机与模式/17 其它/数据库做中介/ORM/createDb.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/createDb.py similarity index 100% rename from A 动机与模式/17 其它/数据库做中介/ORM/createDb.py rename to A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/createDb.py diff --git a/A 动机与模式/17 其它/数据库做中介/ORM/processData.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/processData.py similarity index 100% rename from A 动机与模式/17 其它/数据库做中介/ORM/processData.py rename to A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/ORM/processData.py diff --git a/A 动机与模式/17 其它/数据库做中介/tf.db b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/tf.db similarity index 100% rename from A 动机与模式/17 其它/数据库做中介/tf.db rename to A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/tf.db diff --git a/A 动机与模式/17 其它/数据库做中介/数据库.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/数据库.py similarity index 80% rename from A 动机与模式/17 其它/数据库做中介/数据库.py rename to A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/数据库.py index 1552144..28d7c1a 100644 --- a/A 动机与模式/17 其它/数据库做中介/数据库.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/数据库/数据库.py @@ -1,3 +1,10 @@ +''' +以查询和独立组件并发操作数据为中心的思路,建数据库,围绕数据库做查询操作。 +现代开发模式中,编程语言很少直接用 SQL 操作数据库了,常常有个隔离具体数据库更方便编程的ORM层 , +用工具把表数据映射为对象(ORM) +createDb 创建数据对象,processData 处理数据,DataQuery 查询输出数据。相对“ 共享内存数据 ” ,它慢一些 +''' + import sqlite3, os.path from cppy.cp_util import testfilepath,db_filename,extract_file_words diff --git a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/1 消息接口.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/1 消息接口.py index 7f609c2..98520ff 100644 --- a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/1 消息接口.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/1 消息接口.py @@ -1,5 +1,8 @@ ################ 待整理 ''' +每个对象只公开一个接受和发送消息的接口。隐藏所有数据和函数。 +适合分布式系统的远程组件之间无法直接调用,只能传递消息。 + 应用场景针对各个组件的 notify 方法发指令来驱动所有工作 这是一个示例性质的原型,具体分布式环境下需要调整 diff --git a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/2 消息队列.py b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/2 消息队列.py index 4f5261a..42ae686 100644 --- a/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/2 消息队列.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/3 进程独立/消息驱动/2 消息队列.py @@ -1,8 +1,14 @@ ''' + +每个对象运行于独立线程,每个对象只暴露一个队伍消息队列的接口。 +这种模式,除了分布式也适合多线程的环境。 + 各个组件完全不能互操作,仅依靠队列发消息进行协作 适合环节多,数据可分块,有IO-计算性能设计考量要求,让各个模块自己适应调整 在某些情况下,可以避免复杂的控制流设计,使代码简洁 + +消息队列来共享数据空间。相比较传统数据库共享方式访问更快 ''' from threading import Thread diff --git a/A 动机与模式/13 工程化考虑/2 松耦合/4 装饰器/2 参数类型检查.py b/A 动机与模式/13 工程化考虑/2 松耦合/4 装饰器/2 参数类型检查.py index 5e86529..affd7bb 100644 --- a/A 动机与模式/13 工程化考虑/2 松耦合/4 装饰器/2 参数类型检查.py +++ b/A 动机与模式/13 工程化考虑/2 松耦合/4 装饰器/2 参数类型检查.py @@ -1,3 +1,6 @@ + +# 自己设计类装饰器,类方法做进行类型申明和检查 + from collections import Counter from cppy.cp_util import * diff --git a/A 动机与模式/13 工程化考虑/3 类型申明/参数类型申明.py b/A 动机与模式/13 工程化考虑/3 类型申明/参数类型申明.py index 6a55900..1b2a63a 100644 --- a/A 动机与模式/13 工程化考虑/3 类型申明/参数类型申明.py +++ b/A 动机与模式/13 工程化考虑/3 类型申明/参数类型申明.py @@ -1,3 +1,7 @@ + +# Python 作为弱类型语言希望拥有强类型语言类似的规范工整工程性的优点,牺牲一些代码的自由度。 +# 可以理解为更好的代码注释和更多的工程约束 。 + import cppy.cp_util as util diff --git a/A 动机与模式/14 函数式风格/readme.md b/A 动机与模式/14 函数式风格/readme.md new file mode 100644 index 0000000..81adb28 --- /dev/null +++ b/A 动机与模式/14 函数式风格/readme.md @@ -0,0 +1 @@ +尾调用方式调用函数做连续的数据处理。代码好读,方便栈资源优化(一些语言已经实现了这种调用方式释放前面的函数栈,但Python当前还没做如此优化)。 \ No newline at end of file diff --git a/A 动机与模式/15 人机交互/1 终端/terminal_menu.py b/A 动机与模式/15 人机交互/1 终端/terminal_menu.py index 7bec56b..19eef78 100644 --- a/A 动机与模式/15 人机交互/1 终端/terminal_menu.py +++ b/A 动机与模式/15 人机交互/1 终端/terminal_menu.py @@ -1,4 +1,6 @@ + # 命令行菜单驱动程序 +# while 循环体中出现一个 case 菜单,每个菜单调用对应函数 import os import cppy.cp_util as util diff --git a/A 动机与模式/15 人机交互/2 视窗/PyQT.py b/A 动机与模式/15 人机交互/2 视窗/PyQT.py index 122a45a..32ca6a0 100644 --- a/A 动机与模式/15 人机交互/2 视窗/PyQT.py +++ b/A 动机与模式/15 人机交互/2 视窗/PyQT.py @@ -1,3 +1,6 @@ + +# 应用基于一个窗口,窗口基于操作系统的消息机制 + import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QTextEdit, QFileDialog import cppy.cp_util as util diff --git a/A 动机与模式/15 人机交互/3 Web/MVC/app.py b/A 动机与模式/15 人机交互/3 Web/MVC/app.py index 8b5d48b..61d5dd2 100644 --- a/A 动机与模式/15 人机交互/3 Web/MVC/app.py +++ b/A 动机与模式/15 人机交互/3 Web/MVC/app.py @@ -1,3 +1,13 @@ +''' + Web的MVC三层结构是互联网最火的应用框架。 + 系统需要切分为模型、视图、控制三层。 + Python 中最简单的 Web服务器是 flask + app.py - Flask应用的主文件,控制器(Controller)。 + models.py - 模型(Model)文件,包含词频统计的逻辑。 + templates/index.html - 视图(View)文件,用于展示结果。 + ''' + + from flask import Flask, render_template, request from models import WordFrequencyModel diff --git a/A 动机与模式/16 异常/readme.md b/A 动机与模式/16 异常/readme.md new file mode 100644 index 0000000..3132b71 --- /dev/null +++ b/A 动机与模式/16 异常/readme.md @@ -0,0 +1 @@ +异常主要发生在参数传递和代码块执行过程。一种原则是:软件不能挂掉。检查参数合理性、检查代码块执行可能的错误,并进行合理结果补齐,保持程序继续运行【 1 软件不能挂掉 】,另外一种情况是发生异常就抛出然后终止程序【 2 时间停止在那一刻 】,或者由上层函数接住,集中统一处理。【 3 预判可能的错误 】。 \ No newline at end of file diff --git a/A 动机与模式/17 其它/状态机.py b/A 动机与模式/17 其它/状态机.py index 762ad0b..6c76fa9 100644 --- a/A 动机与模式/17 其它/状态机.py +++ b/A 动机与模式/17 其它/状态机.py @@ -2,9 +2,12 @@ import cppy.cp_util as util from collections import Counter -# 古老的编码风格:使用状态机来计算词频 -# 这种方法在Python中并不常见,但它展示了如何使用状态机来管理程序的状态和流程 - +''' +状态机是计算机程序运行的基础理论。 +使用状态机的风格来处理文件并计算词频,我们可以将整个过程分解为一系列状态转移。 +每个状态代表处理过程中的一个阶段,比如“读取文件”、“分割单词”和“计算词频”等。 +这种方法在Python中并不常见,但它展示了如何使用状态机来管理程序的状态和流程 +''' class WordFrequencyStateMachine: def __init__(self, file_path): diff --git a/A 动机与模式/readme.MD b/A 动机与模式/readme.MD index 8dd0116..e530971 100644 --- a/A 动机与模式/readme.MD +++ b/A 动机与模式/readme.MD @@ -1,4 +1,9 @@ + ## 任务 -本项目的主要功能任务:做文本文件的分词,过滤常见词,求词频,并排序输出。 \ No newline at end of file +本项目的主要功能任务:对指定文件,读取文本,在停用词过滤后,按降序输出前10个高频词 + +我们研究这个问题的解法在各种情景下的表现形式 + +将 cppy整个目录转移到 anaconda3\Lib\site-packages 下面。里面放了一些共同的代码片段(函数),这样使得模式代码更短小简洁,便于更能集中理解各种模式的核心思想 。 \ No newline at end of file diff --git a/readme.MD b/readme.MD index 15e9f20..aaa15d7 100644 --- a/readme.MD +++ b/readme.MD @@ -1,11 +1,13 @@ ## Python 工程师的代码工具箱 -初学编程者完成一门学校的标准课程学习后,会发现成熟的开源项目代码使用了完全不同课堂教学练习的代码风格。本项目主要用来回答这个问题:
代码为啥要这样写,我要这样写代码
+初学编程者完成一门学校的标准课程学习后,会发现成熟的开源项目代码使用了完全不同课堂教学练习的代码风格。而且总有一些模式(或者叫风格等等)反复出现。这些重复的模式是集体智慧的结晶,工程学上的最佳实践。本代码仓库对此做简单探索,用以提升 “编程思维” 之外的另外一个重要基础编码能力。 + + ### 本项目的模块说明 A 代码模式 用一个简单任务,展示各种软件工程需求(完成任务简单、可读性强、可复用高、维护成本低等)下的代码写法