├── .gitignore ├── README.md ├── courses ├── images │ ├── background.jpg │ ├── class22-01.png │ ├── class22-02.png │ ├── class22-03.png │ ├── class22-04.png │ ├── class22-05.png │ ├── class22-06.png │ ├── class22-07.png │ ├── class30-01.png │ ├── class30-02.png │ ├── class31.png │ ├── class33-01.png │ ├── class35-01.png │ ├── class41-01.png │ ├── class41-02.png │ ├── class41-03.png │ ├── class42-01.png │ ├── class43-01.png │ ├── class43-02.png │ ├── class43-03.png │ └── class43-04.png ├── python01.md ├── python02.md ├── python03.md ├── python04.md ├── python05.md ├── python06.md ├── python07.md ├── python08.md ├── python09.md ├── python10.md ├── python11.md ├── python12.md ├── python13.md ├── python14.md ├── python15.md ├── python16.md ├── python17.md ├── python18.md ├── python19.md ├── python20.md ├── python21.md ├── python22.md ├── python23.md ├── python24.md ├── python25.md ├── python26.md ├── python27.md ├── python28.md ├── python29.md ├── python30.md ├── python31.md ├── python32.md ├── python33.md ├── python34.md ├── python35.md ├── python36.md ├── python37.md ├── python38.md ├── python39.md ├── python40.md ├── python41.md ├── python42.md ├── python43.md ├── python44.md ├── python45.md ├── python46.md ├── python47.md ├── python48.md ├── python49.md ├── python50.md ├── python51.md ├── python52.md ├── python53.md └── python54.md ├── slides └── README.md └── src └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevOpsGirls 2 | 3 | 一起设计和完善Python程序媛课程。 4 | 5 | DevOpsGirls(Python程序媛)培养计划 (2019版) 6 | 7 | (ps:本课程内容也适合男同学,男生若有兴趣也可一起参与学习和设计。) 8 | 9 | ### 本课程的初衷和目标 10 | 11 | 帮助更多女性学习编程和IT技能,让她们在技术世界里找到更多自信与尊严! 12 | 13 | ### 网络上对DevOpsGirls程序媛培养计划的声音 14 | 15 | 大家对我们推出的DevOpsGirls程序媛培养计划还是[支持和认可的](https://www.v2ex.com/t/534240),我们会更加努力! 16 | 17 | ### 人生苦短,为什么我要用Python? 18 | 19 | 随着机器学习的兴起,Python逐步成为了最受欢迎的语言。 20 | 21 | ### 2018 人工智能、大数据、Python从业者薪资表 22 | 23 | 了解薪资情况,现在正是进入人工智能领域学习就业/转业和学习Python的最佳时机。 24 | 25 | ![python薪资](https://wiki.huihoo.com/images/5/56/Python-salary.jpeg) 26 | 27 | 课程大纲和简介 28 | 29 | ## 第一阶段:Python入门篇 30 | 31 | [第1课:Python历史、版本、安装](courses/python01.md) 32 | 33 | [第2课:快速熟悉Python](courses/python02.md) 34 | 35 | [第3课:数据类型(一)](courses/python03.md) 36 | 37 | [第4课:数据类型(二)](courses/python04.md) 38 | 39 | [第5课:条件](courses/python05.md) 40 | 41 | [第6课:循环](courses/python06.md) 42 | 43 | [第7课:文件、目录](courses/python07.md) 44 | 45 | [第8课:错误、异常](courses/python08.md) 46 | 47 | ## 第二阶段:Python语言篇 48 | 49 | [第9课:语法(Syntax)、语义(Semantics)、词法(Lexical)(一)](courses/python09.md) 50 | 51 | [第10课:语法(Syntax)、语义(Semantics)、词法(Lexical)(二)](courses/python10.md) 52 | 53 | [第11课:操作符(Operators)](courses/python11.md) 54 | 55 | [第12课:程序结构(Program structure)](courses/python12.md) 56 | 57 | [第13课:函数(Function)](courses/python13.md) 58 | 59 | [第14课:面向对象(Object orientation)(一)](courses/python14.md) 60 | 61 | [第15课:面向对象(Object orientation)(二)](courses/python15.md) 62 | 63 | [第16课:模块/库(Module/Library)(一)](courses/python16.md) 64 | 65 | [第17课:模块/库(Module/Library)(二)](courses/python17.md) 66 | 67 | [第18课:接口(Interface)](courses/python18.md) 68 | 69 | [第19课:闭包(Closures)](courses/python19.md) 70 | 71 | [第20课:元编程(Metaprogramming)](courses/python20.md) 72 | 73 | [第21课:测试(Testing)(一)](courses/python21.md) 74 | 75 | [第22课:测试(Testing)(二)](courses/python22.md) 76 | 77 | [第23课:设计模式(Design patterns)](courses/python23.md) 78 | 79 | [第24课:领域特定语言(Domain-specific language,DSL)](courses/python24.md) 80 | 81 | ## 第三阶段:Django框架篇 82 | 83 | [第25课:Django web框架概述](courses/python25.md) 84 | 85 | [第26课:入门 - 请求和响应(一)](courses/python26.md) 86 | 87 | [第27课:入门 - 模型和管理后台(二)](courses/python27.md) 88 | 89 | [第28课:入门 - 视图和模板(三)](courses/python28.md) 90 | 91 | [第29课:入门 - 表单和通用视图(四)](courses/python29.md) 92 | 93 | [第30课:入门 - 完善管理后台(五)](courses/python30.md) 94 | 95 | [第31课:入门 - 样式风格(六)](courses/python31.md) 96 | 97 | [第32课:入门 - 测试(七)](courses/python32.md) 98 | 99 | [第33课:模型(一)](courses/python33.md) 100 | 101 | [第34课:模型(二)](courses/python34.md) 102 | 103 | [第35课:视图(一)](courses/python35.md) 104 | 105 | [第36课:视图(二)](courses/python36.md) 106 | 107 | [第37课:模板(一)](courses/python37.md) 108 | 109 | [第38课:模板(二)](courses/python38.md) 110 | 111 | [第39课:表单(一)](courses/python39.md) 112 | 113 | [第40课:表单(二)](courses/python40.md) 114 | 115 | ## 第四阶段:Django常用功能和安全篇 116 | 117 | [第41课:认证](courses/python41.md) 118 | 119 | [第42课:会话](courses/python42.md) 120 | 121 | [第43课:分页](courses/python43.md) 122 | 123 | [第44课:验证](courses/python44.md) 124 | 125 | [第45课:序列化](courses/python45.md) 126 | 127 | [第46课:缓存](courses/python46.md) 128 | 129 | [第47课:日志](courses/python47.md) 130 | 131 | [第48课:安全概览](courses/python48.md) 132 | 133 | [第49课:加密签名](courses/python49.md) 134 | 135 | [第50课:中间件](courses/python50.md) 136 | 137 | 138 | ## 第五阶段:Python小结 139 | 140 | [第51课:知识回顾](courses/python51.md) 141 | 142 | [第52课:难点强化](courses/python52.md) 143 | 144 | [第53课:Python进阶](courses/python53.md) 145 | 146 | [第54课:Python面试](courses/python54.md) 147 | 148 | ## 许可方式 License 149 | 150 | courses和slides采用CC 151 | 152 | [![CC](http://wiki.huihoo.com/images/4/4e/CC-BY-SA_3.0-88x31.png)](http://wiki.huihoo.com/wiki/CC-BY-SA_3.0) 153 | 154 | src采用Apache v2 155 | 156 | ## 赞助与支持 157 | 若这份教程对你有帮助,你可以通过赞助的方式鼓励我们并成为灰狐的朋友们。 158 | 159 | ![灰狐会员](http://wiki.huihoo.com/images/2/25/Zsxq.jpg) 160 | 161 | [灰狐的朋友们更多权益](https://wiki.huihoo.com/wiki/%E7%81%B0%E7%8B%90%E4%BC%9A%E5%91%98) 162 | -------------------------------------------------------------------------------- /courses/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/background.jpg -------------------------------------------------------------------------------- /courses/images/class22-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-01.png -------------------------------------------------------------------------------- /courses/images/class22-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-02.png -------------------------------------------------------------------------------- /courses/images/class22-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-03.png -------------------------------------------------------------------------------- /courses/images/class22-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-04.png -------------------------------------------------------------------------------- /courses/images/class22-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-05.png -------------------------------------------------------------------------------- /courses/images/class22-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-06.png -------------------------------------------------------------------------------- /courses/images/class22-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class22-07.png -------------------------------------------------------------------------------- /courses/images/class30-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class30-01.png -------------------------------------------------------------------------------- /courses/images/class30-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class30-02.png -------------------------------------------------------------------------------- /courses/images/class31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class31.png -------------------------------------------------------------------------------- /courses/images/class33-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class33-01.png -------------------------------------------------------------------------------- /courses/images/class35-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class35-01.png -------------------------------------------------------------------------------- /courses/images/class41-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class41-01.png -------------------------------------------------------------------------------- /courses/images/class41-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class41-02.png -------------------------------------------------------------------------------- /courses/images/class41-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class41-03.png -------------------------------------------------------------------------------- /courses/images/class42-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class42-01.png -------------------------------------------------------------------------------- /courses/images/class43-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class43-01.png -------------------------------------------------------------------------------- /courses/images/class43-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class43-02.png -------------------------------------------------------------------------------- /courses/images/class43-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class43-03.png -------------------------------------------------------------------------------- /courses/images/class43-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/courses/images/class43-04.png -------------------------------------------------------------------------------- /courses/python01.md: -------------------------------------------------------------------------------- 1 | 2 | # 第1课:Python历史、版本、安装 3 | 4 | ### 1、了解Python语言和历史 5 | 认识Python之父,Guido von Rossum,荷兰人,数学和计算机双硕士。除了解决常规问题,Python也是处理数学问题的好帮手,在大数据分析、金融数据分析里,都能看到Python在回归、积分、符号计算、统计、随机数、金融衍生品方面的应用,后续课程都会有所涉及。 6 | 7 | ![Python之父](https://wiki.huihoo.com/images/a/ac/Guido-von-Rossum.jpg) 8 | 9 | Python语言以对象为核心组织代码(Everything is object),支持多种编程范式(multi-paradigm),采用动态类型(dynamic typing),自动进行内存回收(garbage collection)。支持解释运行(interpret),并能调用C库进行拓展,解决性能问题。Python有强大的标准库 (battery included,开箱即用)。由于标准库的体系已经稳定,所以Python开始拓展到第三方包和框架,如Django、Flask、Web.py、WxPython、Numpy、Matplotlib、PIL 和大量人工智能机器学习库,Python已变成极富生命力的生态系统。 10 | 11 | 著名的口号:人生苦短,我用Python。 12 | 13 | 参考读物: [Python简史](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html) 14 | 15 | ### 2、Python版本 16 | Python两大版本:Python3和Python2,若没有历史遗留问题就直接使用Python3,有关Python3和Python2的更多细节,请看知乎。 17 | 18 | [应该学习最新版本的 Python 3 还是旧版本的 Python 2?](https://www.zhihu.com/question/24549965) 19 | 20 | 总之,Python3才是Python的未来,大家现在都没有历史包袱,所以Python3。 21 | 22 | ### 3、Python安装 23 | Python的安装有多种方式,这里主要介绍两种:直接安装、Anaconda安装包(建议使用,因升级和安装其它Python包都很方便,我们的课程使用Anaconda) 24 | 25 | [下载Anaconda](https://www.anaconda.com/download/) 26 | 27 | 为了验证Python是否安装正确,我们跑一个简单区块链应用。 28 | 29 | [blockchain-python](https://github.com/Carlos-Zen/blockchain-python) 30 | 31 | 可直接下载压缩包或安装[Git](https://git-scm.com/) 32 | 33 | ![python-blockchain-01](https://wiki.huihoo.com/images/thumb/3/31/Python-blockchain-01.png/1076px-Python-blockchain-01.png) 34 | 35 | ![python-blockchain-02](https://wiki.huihoo.com/images/thumb/9/95/Python-blockchain-02.png/1076px-Python-blockchain-02.png) 36 | 37 | 完成了以上三个小任务,写点你对Python的认识并截图运行起来的区块链应用的同学就可以提交作业了。 38 | 39 | 在整个学习过程中若有任何疑问都可提出来交流,期待大家的积极参与。 40 | 41 | ![配图1](https://wiki.huihoo.com/images/7/70/Devopsgirls01.png) -------------------------------------------------------------------------------- /courses/python02.md: -------------------------------------------------------------------------------- 1 | 2 | # 第2课:快速熟悉Python 3 | 4 | * 一行Python代码,Hello World 5 | * 了解整数、浮点数、字符串、布尔值 6 | * 了解变量、关键字、变量命名规范 7 | 8 | 运行Anaconda下的Jupyter,完成以下的一些操作: 9 | 10 | ### (1)hello world 11 | `print “Hello World” ` 12 | 13 | 能运行吗?若不行,请搜索并完成正确print打印。 14 | 注意:我们现在使用的是Python3。 15 | 16 | ### (2)数据类型 17 | ``` 18 | counter = 100 # 整型变量 19 | miles = 100.0 # 浮点型变量 20 | a, b = 1, 2 # 多个变量赋值 21 | name = “Python” # 字符串 22 | 23 | True, False # 布尔值 24 | 25 | print (counter) 26 | print (miles) 27 | print (name) 28 | 29 | print(type(name)) 30 | isinstance(name, str) 31 | ``` 32 | 33 | ### (3)类型转换 34 | ``` 35 | 整数 -> 浮点数 36 | a = 12 37 | b = float(a) 38 | a 39 | b 40 | 41 | 浮点数 -> 整数 42 | c = 12.0 43 | d = int(c) 44 | c 45 | d 46 | ``` 47 | 48 | 扩展练习:其它类型的相互转换。 49 | 50 | ### (4)关键字 51 | 关键字即保留字,我们不能把它们用作任何标识符命名。 52 | 53 | Python关键字有哪些? 54 | ``` 55 | import keyword 56 | keyword.kwlist 57 | ``` 58 | 然后记住它们 59 | 60 | ### (5)一些命名规范: 61 | * a、必须以一个字母或一个下划线字符开头; 62 | * b、字母可以是大小写,但大小写是不同的,如:Ax不同于aX; 63 | * c、数字可以是从0到9的任意数字。 64 | 65 | 合法变量名: 66 | * my_answer 67 | * answer12 68 | * answer_12 69 | * YourAnswer 70 | 71 | 不合法变量名: 72 | * 12answer(不能以数字开头) 73 | * your-answer(不允许连字符) 74 | * my answer (不允许有空格) 75 | 76 | ### (6) 77 | 作业2:type()和isinstance()的区别 78 | 79 | 运行下看系统给出的一些信息: 80 | ``` 81 | a = 100 82 | print(type(a) 83 | 84 | b = 101 85 | isinstance(b, int) 86 | ``` 87 | 搜索整理出区别点和关系。 88 | 89 | 最后,可小结和总结下(1-5) 知识点和Jupyter操作截图 + (6)的作业一起提交作业。 90 | 91 | 配图来自Twitter:@MacciattoS2 92 | 93 | ![配图2](https://wiki.huihoo.com/images/e/e8/Devopsgirls02.jpg) 94 | -------------------------------------------------------------------------------- /courses/python03.md: -------------------------------------------------------------------------------- 1 | # 第3课:数据类型(一) 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,可存档附件到作业后面。 4 | 5 | Python3 的六个标准数据类型中: 6 | * 不可变数据(3个):Number(数字)、String(字符串)、Tuple(元组); 7 | * 可变数据(3个):List(列表)、Dictionary(字典)、Set(集合)。 8 | 9 | ps:集合有可变集合(set())和不可变集合(frozenset)两种。 10 | 11 | 接下来我们分两次课介绍列表、元组、集合和字典 12 | 13 | 列表 []、元组 ()、集合 {}、字典 {key: value} 14 | 15 | 首先了解下Number:整数(int)、浮点数(float)、复数(complex) 16 | 17 | 也可以使用十六进制和八进制来代表整数 18 | 19 | ``` 20 | >>> number = 0xB0F # 十六进制 21 | >>> number 22 | 2831 23 | >>> number=0o27 # 八进制 24 | >>> number 25 | 23 26 | ``` 27 | 类型转换 28 | 29 | 如:浮点数转整数 30 | ``` 31 | >>> a = 3.3 32 | >>> int(a) 33 | 3 34 | ``` 35 | 内置的数学函数、随机数函数、三角函数、数学常量 36 | 37 | 依此举例: 38 | ``` 39 | >>>abs(-3) 40 | >>>import random 41 | >>>random.randint(1,99) 42 | 57 43 | 44 | >>> math.sin(100) 45 | -0.5063656411097588 46 | 47 | >>> math.pi 48 | 3.141592653589793 49 | 50 | >>> math.e 51 | 2.718281828459045 52 | ``` 53 | 54 | 大家去去找到这些内容完整介绍,并试试其它一些函数。 55 | 56 | Python3的列表和元组很类似,区别是元组的元素不可变。 57 | 58 | 列表用[],元组用(),如: 59 | ``` 60 | >>>list1 = [1, 2, 3, 4, 5] 61 | >>>list1[0] = 10 # 合法 62 | >>>tup1 = (1, 2, 3, 4, 5) 63 | >>>tup1[0] = 10 # 非法 64 | ``` 65 | 注意:其实,通过逗号分隔元素也可创建元组。()是可选的,但没有()容易造成歧义,所以建议大家还是用(),这样也好记。 66 | ``` 67 | >>> tuple_1 = 1, 2, 3, 4, 5 68 | >>> print(tuple_1) 69 | (1, 2, 3, 4, 5) 70 | ``` 71 | 72 | 配图来自:Twitter 73 | 74 | ![配图3](https://wiki.huihoo.com/images/thumb/b/b9/Devopsgirls03.jpg/1280px-Devopsgirls03.jpg) 75 | -------------------------------------------------------------------------------- /courses/python04.md: -------------------------------------------------------------------------------- 1 | # 第4课:数据类型(二) 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,可存档附件到作业后面。 4 | 5 | 上节课我们学习了列表[]和元组(),接下来学习集合 {}、字典 {key: value} 6 | 7 | ### Set & Dict 8 | 集合(set)是一个无序不重复元素的序列,如: 9 | ``` 10 | >>>set1 = set() # 空集合用set() 11 | >>>set2 = {'a', 'b', 'c', 'd'} 12 | >>>set2.add(“e”) 13 | ``` 14 | 15 | 字典可存储任意类型对象,列表是有序的对象集合,字典是无序的对象集合。 16 | ``` 17 | >>> dict1 = {'Name': 'Allen', 'Age': 44} 18 | >>> dict1['Age'] = 34 19 | ``` 20 | 21 | 接着,我们展开这些内容。 22 | 23 | 集合操作:添加元素、移除元素、集合个数、是否存在、清空集合 24 | 25 | 1、添加元素 26 | ``` 27 | >>>set2.add(‘f’) 或 set2.update(‘f’) # 注意:无序 28 | ``` 29 | 30 | 2、移除元素 31 | ``` 32 | >>>set2.remove(‘f’) 或 set2.discard('f') 或 set2.pop() 33 | ``` 34 | 35 | 3、集合个数 36 | ``` 37 | >>>len(set2) 38 | ``` 39 | 40 | 4、是否存在 41 | ``` 42 | >>>'a' in set2 43 | ``` 44 | 45 | 5、清空集合 46 | ``` 47 | >>>set2.clear() 48 | ``` 49 | 50 | 字典操作:访问、修改、个数、删除 51 | 52 | 1、访问 53 | ``` 54 | >>> dict1['Name'] 55 | ``` 56 | 57 | 2、修改 58 | ``` 59 | >>> dict1['Name'] = "Python" 60 | ``` 61 | 62 | 4、个数 63 | ``` 64 | >>> len(dict1) 65 | ``` 66 | 67 | 4、删除 68 | ``` 69 | >>> del dict1['Name'] # 删除键 70 | >>> dict1.clear() # 清空字典,空字典还在 71 | >>> del dict1 # 删除字典,没了 72 | ``` 73 | 74 | 还有些其它字典内置函数&方法,自己可找找学习下。 75 | 76 | 最后,做一个循环输出字典键或字典值的练习,提示:for循环、keys、values。 77 | 78 | ``` 79 | >>> dict = {1: "C", 2: "C++", 3: "Java", 4: "Python"} 80 | ``` 81 | 82 | ### 数据类 83 | Python 3.7 引入了新的库模块:dataclasses: [PEP 557 -- 数据类](https://docs.python.org/zh-cn/3/whatsnew/3.7.html#whatsnew37-pep557) 大家可了解下。 84 | 85 | dataclasses 可简单理解为是一个适合于存储数据对象(data object)或者说数据(data)的 Python 类。 86 | 87 | Data Classes can be thought of as "mutable namedtuples with defaults"(数据类可以被认为是“具有默认值的可变命名元组”)大家可思考下?Tuple(元组)是不可变数据类型。 88 | 89 | ``` 90 | >>> from dataclasses import dataclass 91 | >>> @dataclass 92 | ... class Point: 93 | ... x: float 94 | ... y: float 95 | ... z: float = 0.0 96 | ... 97 | >>> p = Point(1.5, 2.5) 98 | >>> print(p) 99 | Point(x=1.5, y=2.5, z=0.0) 100 | ``` 101 | 102 | 新的 dataclass() 装饰器(decorator)提供了一种声明数据类的方法。数据类使用类变量注释(annotations)来描述其属性。它的构造函数和其他魔法方法(magic methods),如:`__repr__()`、`__eq__()` 和 `__hash__()` 会自动生成。 103 | 104 | 所谓魔法方法(magic methods)是 Python 的一种高级语法,格式为`__aaa__`,这些方法可以给 Python 类提供特殊功能,如 __init__ 方法可以对实例属性进行初始化。 105 | 106 | ``` 107 | >>> dir(dataclass) 108 | ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] 109 | ``` 110 | 111 | 数据类的扩展阅读: 112 | * [Understanding Python Dataclasses — Part 1](https://medium.com/mindorks/understanding-python-dataclasses-part-1-c3ccd4355c34) 113 | * [Understanding Python Dataclasses — Part 2](https://medium.com/mindorks/understanding-python-dataclasses-part-2-660ecc11c9b8) 114 | 115 | 好了,我要交作业啦 奖励自己一根雪糕 :) 116 | 117 | 配图来自Twitter:@makadamixa 118 | 119 | ![配图4](https://wiki.huihoo.com/images/thumb/9/9a/Devopsgirls04.jpg/1255px-Devopsgirls04.jpg) -------------------------------------------------------------------------------- /courses/python05.md: -------------------------------------------------------------------------------- 1 | # 第5课:条件 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,可存档附件到作业后面。 4 | 5 | 条件:if - elif - else,每个后面跟冒号: 6 | 注意:python没有switch – case语句 7 | 8 | 常用的操作符 9 | ``` 10 | < 小于 11 | <= 小于或等于 12 | > 大于 13 | >= 大于或等于 14 | == 等于 15 | != 不等于 16 | ``` 17 | 18 | 创建 test05.py 19 | ``` 20 | #!/anaconda3/bin/python3 21 | import random 22 | 23 | x = random.choice(range(10)) 24 | y = random.choice(range(20)) 25 | 26 | if x > y: 27 | print('x:', x) 28 | elif x == y: 29 | print('x = y =', x) 30 | else: 31 | print('y:', y) 32 | ``` 33 | 34 | python3 test05.py 35 | ``` 36 | if - elif - else可嵌套,类似这样: 37 | if 条件1: 38 | 语句 39 | if 条件2: 40 | 语句 41 | elif 条件3: 42 | 语句 43 | else: 44 | 语句 45 | elif 条件4: 46 | 语句 47 | else: 48 | ``` 49 | 一组有趣的例子:条件为真或为假 50 | 51 | 1、条件为真:不为0、为True、为”None” 52 | ``` 53 | >>> a = 1 54 | >>> if a: 55 | ... print("True") 56 | ... else: 57 | ... print("False") 58 | ... 59 | True 60 | 61 | >>> a = "None" 62 | >>> if a: 63 | ... print("True") 64 | ... else: 65 | ... print("False") 66 | ... 67 | True 68 | ``` 69 | 2、条件为假:为0、为False、为None 70 | ``` 71 | >>> a = 0 72 | >>> if a: 73 | ... print("True") 74 | ... else: 75 | ... print("False") 76 | ... 77 | False 78 | 79 | >>> a = None 80 | >>> if a: 81 | ... print("True") 82 | ... else: 83 | ... print("False") 84 | ... 85 | False 86 | ``` 87 | 你再试试 a = True 或 False的情况。 88 | 89 | 有点困了,该睡觉了。月亮 90 | 91 | 配图来自Twitter:@atikix 92 | 93 | ![配图](https://wiki.huihoo.com/images/f/fe/Devopsgirls05.jpg) -------------------------------------------------------------------------------- /courses/python06.md: -------------------------------------------------------------------------------- 1 | # 第6课:循环 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,并保存.ipynb。 4 | 5 | 循环:for 和 while 6 | 7 | while循环语句 8 | ``` 9 | >>> i = 0 10 | >>> while i < 6: 11 | ... print(i) 12 | ... i = i + 1 13 | ``` 14 | 15 | break语句 16 | ``` 17 | >>> i = 0 18 | >>> while i < 6: 19 | ... print(i) 20 | ... i = i + 1 21 | ... if i == 5: 22 | ... break 23 | ``` 24 | 25 | continue语句 26 | ``` 27 | >>> i = 0 28 | >>> while i < 6: 29 | ... print(i) 30 | ... i = i + 1 31 | ... if i < 5: 32 | ... continue 33 | ``` 34 | 35 | 无限循环 36 | ``` 37 | >>>while True: 38 | print(‘Hello World!’) 39 | ``` 40 | 41 | for循环和range()函数 42 | 43 | 可以通过range()函数遍历数字序列 44 | ``` 45 | >>> for i in range(6): 46 | ... print(i) 47 | ``` 48 | 49 | range()开始、结束、步长 50 | ``` 51 | >>> for i in range(0, 10, 2): 52 | ... print(i) 53 | 54 | >>> for i in range(10, -2, -2): 55 | ... print(i) 56 | ``` 57 | 58 | 可以有几种方式: 59 | 60 | 方式一:for循环 61 | ``` 62 | >>> sum = 0 63 | >>> for num in range(101): 64 | ... sum = sum + num 65 | ... 66 | >>> print(sum) 67 | ``` 68 | 69 | 方式二:while循环 70 | ``` 71 | >>> sum = 0 72 | >>> n = 1 73 | >>> while n < 101: 74 | ... sum = sum + n 75 | ... n+=1 76 | ... 77 | >>> print(sum) 78 | ``` 79 | 80 | 方式三:导入reduce函数 81 | ``` 82 | >>> def sum(x, y): 83 | ... return x + y 84 | ... 85 | >>> from functools import reduce 86 | >>> print(reduce(sum ,range(1, 101))) 87 | ``` 88 | 89 | 扩展练习: 90 | * 1-100的奇数相加之和 91 | * 1-100的偶数相加之和 92 | 93 | 天气有些热,喝杯冰红茶。 94 | 95 | 配图来自Twitter:@atikix 96 | 97 | ![配图6](https://wiki.huihoo.com/images/e/e6/Devopsgirls06.jpg) -------------------------------------------------------------------------------- /courses/python07.md: -------------------------------------------------------------------------------- 1 | # 第7课:文件、目录 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,并保存.ipynb。 4 | 5 | touch text.txt 6 | * 列举目录文件 7 | * 写文件 8 | * 读文件 9 | 10 | 本节课主要学习目录操作和文件读写。 11 | 12 | ``` 13 | #目录操作 14 | >>> import os 15 | >>> os.getcwd() 16 | 17 | #改变Linux/macOS目录 18 | >>> os.chdir('/Users/huihoo/Software') 19 | 20 | #改变Windows目录 21 | >>> os.chdir('C:\\Windows\System32') 22 | 23 | #继续试试创建目录:makedirs 24 | 25 | #列举目录文件 26 | >>> from pathlib import Path 27 | >>> p = Path('.') 28 | >>> list(p.glob('*.*')) 29 | or 30 | >>> for child in p.iterdir(): child 31 | 32 | #写文件 33 | with open('test.txt', 'w', encoding='utf-8') as f: 34 | f.write('test') 35 | f.close() 36 | ``` 37 | 38 | 注意:一定要close()关闭文件,否则你做得修改没有保存到文件里,但写入的内容会覆盖以前的文件内容。 39 | 40 | 所以,我们想追加写入文件,我们使用’a’追加模式 41 | ``` 42 | with open('test.txt', 'a', encoding='utf-8') as f: 43 | f.write(‘\n输入中文’) 44 | f.close() 45 | 46 | #读文件 47 | with open('test.txt', 'r', encoding='utf-8') as f: 48 | f.readlines() 49 | ``` 50 | 51 | 还有很多文件目录操作的模块和函数,大家都去了解下。 52 | 53 | 扩展学习:文件目录的相关模块和函数,大家可搜索网络完成一些文件目录扩展练习。 54 | ``` 55 | >>> help() 56 | help> modules 57 | pathlib, os.path, tempfile, filecmp, fileinput, shutil, zipfile 58 | 59 | #os模块:提供了与系统、目录操作相关的函数 60 | >>>import os 61 | >>>dir(os) 62 | 63 | #pathlib模块:其提供的Path类可以创建path路径对象, 属于比os.path更高抽象级别的对象。 64 | >>> import pathlib 65 | >>> dir(pathlib) 66 | 阅读:Python 3的pathlib模块:驯服文件系统 67 | 68 | #os.path模块:包含许多与文件名和文件路径相关的函数 69 | >>> import os.path 70 | >>> dir(os.path) 71 | 72 | #tempfile模块:临时文件和目录处理 73 | >>> import tempfile 74 | >>> dir(tempfile) 75 | 76 | #filecmp模块:用于比较文件及文件夹的内容 77 | >>> import filecmp 78 | >>> dir(flecmp) 79 | 80 | #fileinput模块:可以对一个或多个文件中的内容进行迭代、遍历等操作,其input()函数有点类似文件 81 | #readlines()方法,区别在于前者是一个迭代对象,需要用for循环迭代,后者是一次性读取所有行。 82 | >>>import fileinput 83 | >>>dir(fileinput) 84 | 85 | #shutil模块:复制、移动、改名和删除文件 86 | >>> import shutil, os 87 | >>> dir(shutil) 88 | 89 | #zipfile模块:压缩文件 90 | >>> import zipfile, os 91 | >>> dir(zipfile) 92 | ``` 93 | 94 | 配图来自Twitter:@momoco_haru 95 | 96 | ![配图7](https://wiki.huihoo.com/images/b/b5/Devopsgirls07.jpg) -------------------------------------------------------------------------------- /courses/python08.md: -------------------------------------------------------------------------------- 1 | # 第8课:错误、异常 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,并保存.ipynb。 4 | 5 | 本节课涉及一些概念:语法错误、异常、异常处理、抛出异常、自定义异常、Finally始终执行、反向跟踪 6 | 7 | 注意:错误和异常的区别: 8 | 错误(语法错误、解析时) 9 | 异常(运行时) 10 | 11 | 1、语法错误 12 | ``` 13 | >>> print (Hello World) 14 | File "", line 1 15 | print (Hello World) 16 | ^ 17 | SyntaxError: invalid syntax 18 | ``` 19 | 20 | 2、异常(运行时) 21 | 常见的异常类型:ZeroDivisionError,NameError 和 TypeError 22 | ``` 23 | >>>1/0 24 | ``` 25 | 26 | 3、异常处理(try … except) 27 | ``` 28 | >>> def zero_fails(): 29 | ... x = 1/0 30 | ... 31 | >>> try: 32 | ... zero_fails() 33 | ... except ZeroDivisionError as err: 34 | ... print('处理运行时错误', err) 35 | ``` 36 | 37 | Python抛出异常相当于:“停止运行这个函数中的代码,将程序执行转到except语句。 38 | 39 | raise语句包含以下部分: 40 | * raise关键字; 41 | * 对Exception函数的调用; 42 | * 传递给Exception函数的字符串,包含有用的出错信息。 43 | 44 | 4、抛出异常(raise) 45 | ``` 46 | >>> raise Exception('这是一个错误信息') 47 | >>> raise ZeroDivisionError('ZeroFails') 48 | Traceback (most recent call last): 49 | File "", line 1, in 50 | ZeroDivisionError: ZeroFails 51 | ``` 52 | 53 | 5、自定义异常,继承自 Exception 类 54 | ``` 55 | >>>class MyError(Exception): 56 | def __init__(self, value): 57 | self.value = value 58 | 59 | 类 Exception 默认的 __init__() 被覆盖 60 | ``` 61 | 62 | 6、Finally 63 | ``` 64 | >>> try: 65 | ... raise ZeroDivisionError 66 | ... finally: 67 | ... print("始终执行") 68 | ``` 69 | 70 | 7、traceback 71 | 72 | 只要抛出的异常没有被处理,Python就会显示反向跟踪,你可将反向跟踪信息写入一个日志文件,让程序继续运行,稍后检查日志文件进行分析。 73 | ``` 74 | >>> import traceback 75 | >>> try: 76 | ... raise Exception('这是一个错误信息.') 77 | ... except: 78 | ... errorFile = open('errorInfo.txt', 'w') 79 | ... errorFile.write(traceback.format_exc()) 80 | ... errorFile.close() 81 | ... print('反向跟踪信息写入errorInfo.txt.') 82 | ``` 83 | 84 | 其实本课程也包含调试、调试器、断言、断点、日志等内容,我们会在之后的进阶课程逐步展开。 85 | 86 | 这块有些复杂,多去理解,多看看一些项目里这部分的处理方式。 87 | 88 | 大部分项目对错误和异常处理都格外重视,会有独立的异常处理模块,如:odoo.exceptions 89 | Search · Exception · GitHub 90 | 91 | OK,程序完成调试。 92 | 93 | 配图来自Twitter:@momoco_haru 94 | 95 | ![配图8](https://wiki.huihoo.com/images/1/13/Devopsgirls08.png) -------------------------------------------------------------------------------- /courses/python09.md: -------------------------------------------------------------------------------- 1 | # 第9课:语法(Syntax)、语义(Semantics)、词汇(Lexical)(一) 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,并保存.ipynb。 4 | 5 | 这节课我们从以下几点入手,更多了解Python语言的一些基本原理,它们容易理解和掌握,不会很枯燥。 6 | 7 | * 语法(Syntax) 8 | * 语义(Semantics) 9 | * 词汇(Lexical) 10 | 11 | 这是编程语言都会涉及的几个概念,它们定义了Python语言的规范,大家需了解下。 12 | 13 | 如: AST(Abstract Syntax Trees)抽象语法树,词法分析(标识符、关键字)。在学习时可对应英语的语法、语义、句法想想,能帮助理解它们大致的意思。 14 | 15 | 这里先给大家引出两个概念:编译时(Compile time)和运行时(Runtime) 16 | 17 | 一个现代编译器的主要工作流程如下: 源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标代码(object code)→ 链接器(Linker)→ 可执行文件(executables) 18 |  19 | 20 | ![donnet](https://wiki.huihoo.com/images/thumb/e/e8/Common-Language-Runtime.png/1280px-Common-Language-Runtime.png) 21 | 22 | 此图是C#的编译过程,其思路也适用于Python语言,Python语法、语义、词汇等概念也贯穿于其中。 23 | 24 | 通过 Python Language Services 和 Python Runtime Services 标准库服务 25 | 26 | Python完成源码的语法解析、抽象语法树处理、访问编译器符号表、编译器编译.py源码成字节码、交由虚拟机运行。和现代编译器的主要工作流程类似。 27 | 28 | 这里:解释器(interpreter)由字节码编译器和虚拟机组成,虚拟机起着类似运行时的作用。 29 | 30 | 简单讲就是:字节码编译器、字节码虚拟机。 31 | 32 | ![python](https://wiki.huihoo.com/images/5/5b/Python-interpreter.png) 33 |  34 | Python虚拟机是Python的核心,在.py源代码被字节码编译器编译为字节码指令序列后,将由字节码虚拟机接手,依次读入每一条字节码指令,并在当前的上下文环境中执行这条字节码指令。 35 | 36 | 参考资料: 37 | * [Python Language Reference](https://docs.python.org/3/reference/index.html) 描述了Python的语法和核心语义。 38 | 39 | 这节课的主要目的就是大家理解下Python的编译原理和解释过程,下节课我们实际操作下编译过程。 40 | 41 | 配图来自Twitter:@MacciattoS2 42 | 43 | ![配图9](https://wiki.huihoo.com/images/thumb/9/9b/Devopsgirls09.png/731px-Devopsgirls09.png) -------------------------------------------------------------------------------- /courses/python10.md: -------------------------------------------------------------------------------- 1 | # 第10课:语法(Syntax)、语义(Semantics)、词法(Lexical)(二) 2 | 3 | 将以下内容以Jupyter Notebook的方式做练习和自己总结,并保存.ipynb。 4 | 5 | Python的编译执行过程其实和Java和C#是类似的,也涉及字节码和虚拟机两个主要概念,这个我们在第9课中有描述。 6 | 7 | 这节课我们实践操作下如何把Python源文件.py编译成可执行文件的过程。 8 | 9 | 注意:这里和本系列课程都使用Python3.6进行实验和学习,Python3和Python2两版本有非常大的差异,这里有些环节(pyc和pyo的生成过程)使用了Python2(Python2.7)。 10 | 11 | 创建helloworld.py文件 12 | ``` 13 | #!/anaconda3/bin/python 14 | print ("Hello World!") 15 | ``` 16 | 17 | ### pyc文件 18 | pyc是由py文件经过编译后生成的二进制文件,是一种跨平台的byte code,再由python虚拟机执行。 19 | 20 | 需要 py_compile 模块 21 | 22 | ``` 23 | python2 -m py_compile helloworld.py 24 | 生成了 helloworld.pyc 或 25 | >>> import py_compile 26 | >>> py_compile.compile('helloworld.py') 27 | '__pycache__/helloworld.cpython-36.pyc' 28 | ``` 29 | 30 | ### pyo文件 31 | pyo是优化编译后的文件 32 | ``` 33 | python2 -O -m py_compile helloworld.py 34 | 注意:这里使用python2生成pyo 35 | helloworld.pyo 36 | ``` 37 | 38 | ### so文件 39 | so是python的动态链接库 40 | 41 | 创建setup.py 42 | ``` 43 | from distutils.core import setup 44 | from Cython.Build import cythonize 45 | 46 | setup( 47 | ext_modules = cythonize("helloworld.py"), 48 | ) 49 | ``` 50 | python setup.py build_ext --inplace 51 | 52 | 先将py转换为c代码,然后编译c为so文件。 53 | ``` 54 | build/temp.macosx-10.7-x86_64-3.6/helloworld.o 55 | helloworld.c 56 | helloworld.cpython-36m-darwin.so 57 | 58 | ``` 59 | ### dis 60 | dis是Python字节码的反汇编程序(Disassembler) 61 | 62 | 我们使用dis对python字节码进行解析 63 | 64 | ``` 65 | >>> s = open('helloworld.py').read() 66 | >>> co = compile(s, 'helloworld.py', 'exec') 67 | >>> dis.dis(co) 68 | 1 0 LOAD_NAME 0 (print) 69 | 2 LOAD_CONST 0 ('Hello World!') 70 | 4 CALL_FUNCTION 1 71 | 6 POP_TOP 72 | 8 LOAD_CONST 1 (None) 73 | 10 RETURN_VALUE 74 | ``` 75 | 获得dis帮助 76 | ``` 77 | >>> help(dis) 78 | ``` 79 | 80 | 再完成一个操作 81 | ``` 82 | >>> def myfunc(alist): 83 | ... return len(alist) 84 | ... 85 | >>> bytecode = dis.Bytecode(myfunc) 86 | >>> for instr in bytecode: 87 | ... print(instr.opname) 88 | ... 89 | LOAD_GLOBAL 90 | LOAD_FAST 91 | CALL_FUNCTION 92 | RETURN_VALUE 93 | >>> 94 | ``` 95 | 配图来自Twitter:@neku_draw 96 | 97 | ![配图10](https://wiki.huihoo.com/images/thumb/3/3c/Devopsgirls10.png/682px-Devopsgirls10.png) 98 | -------------------------------------------------------------------------------- /courses/python11.md: -------------------------------------------------------------------------------- 1 | # 第11课:操作符(Operators) 2 | 3 | 先看看Python有哪些常用操作符: 4 | ``` 5 | + - * ** / // % @ 6 | << >> & | ^ ~ 7 | < > <= >= == != 8 | ``` 9 | 10 | ### 算术操作符 11 | +, -, *, / , %, // , **, _ 分别为加、减、乘、浮点除、取余数(返回除法的余数)、整数除(返回商的整数部分)、幂运算(x的y次幂)、上个表达式结果的值。 12 | ``` 13 | >>> a = 2 14 | >>> b = 6 15 | >>> a + b 16 | 8 17 | >>> a - b 18 | -4 19 | >>> a * b 20 | 12 21 | >>> a/b 22 | 0.3333333333333333 23 | >>> a % b 24 | 2 25 | >>> b % a 26 | 0 27 | >>> a ** b 28 | 64 29 | >>> a // b 30 | 0 31 | >>> b // a 32 | 3 33 | >>> _ 34 | 3 35 | ``` 36 | 37 | ### 比较操作符 38 | ==, !=, <, >=, <= 分别为相等、不等于、大于、小于、大于等于、小于等于。 39 | ``` 40 | >>> (a == b) 41 | False 42 | >>> (a != b) 43 | True 44 | >>> (a > b) 45 | False 46 | >>> (a < b) 47 | True 48 | >>> (a >= b) 49 | False 50 | >>> (a <= b) 51 | True 52 | ``` 53 | 54 | ### 位操作符 55 | 按位运算符是把数字看作二进制来进行计算,数字加上前缀 '0b' 表示是二进制数字。 56 | 57 | &, |, ^, ~, << , >> 分别为按位与、或、异或、取反、左移、右移。 58 | 59 | 自己用2和4的二进制数做按位运算,并理解其结果。 60 | ``` 61 | >>> bin(2);bin(4) 62 | '0b10' 63 | '0b100' 64 | >>> (0b10 & 0b100) 65 | 0 66 | >>> (0b10 | 0b100) 67 | 6 68 | >>> bin(6) 69 | '0b110' 70 | >>> (0b10 ^ 0b100) 71 | 6 72 | >>> (0b10 << 2) 73 | 8 74 | >>> bin(8) 75 | '0b1000' 76 | >>> (0b10 >> 2) 77 | 0 78 | >>> bin(0) 79 | '0b0' 80 | >>> 81 | ``` 82 | 83 | ### 逻辑操作符 84 | and, or, not 分别为与、或、非。 85 | ``` 86 | >>> (a and b) 87 | 10 88 | >>> (a or b) 89 | 21 90 | >>> not(a and b) 91 | False 92 | ``` 93 | 94 | ### 成员操作符 95 | in, not in 分别为是成员、不是成员。 96 | ``` 97 | >>> a = 1; b = 2 98 | >>> list = [1, 2, 3, 4, 5] 99 | >>> (a in list) 100 | True 101 | >>> (c not in list) 102 | True 103 | >>> (b not in list) 104 | False 105 | ``` 106 | 107 | ### 身份运算符 108 | is, is not 分别为同一对象、不是同一对象。 109 | ``` 110 | >>> a = 1; b = 2 111 | >>> (a is b) 112 | False 113 | >>> (a is not b) 114 | True 115 | ``` 116 | 117 | ### 赋值操作符 118 | 把算术运算符和=组合起来使用。 119 | ``` 120 | >>> c = a + b 121 | >>> c 122 | 8 123 | >>> c += a 124 | >>> c 125 | 10 126 | >>> c -= a 127 | >>> c 128 | 8 129 | >>> c *= a 130 | >>> c 131 | 16 132 | >>> c /= a 133 | >>> c 134 | 8.0 135 | >>> c %= a 136 | >>> c 137 | 0.0 138 | >>> c **= a 139 | >>> c 140 | 0.0 141 | >>> c //= a 142 | >>> c 143 | 0.0 144 | ``` 145 | 146 | ### 运算符优先级 147 | ``` 148 | >>> a = 10; b = 6; c = 3; d = 0 149 | >>> a = 10; b = 6; c = 3; d = 2 150 | >>> ((a + b) * c) / d 151 | 24.0 152 | >>> a * b ** c 153 | 2160 154 | >>> a * (b ** c) 155 | 2160 156 | ``` 157 | 158 | 配图来自Twitter 159 | 160 | ![配图11](https://wiki.huihoo.com/images/e/ef/Devopsgirls11.jpg) 161 | -------------------------------------------------------------------------------- /courses/python12.md: -------------------------------------------------------------------------------- 1 | # 第12课:程序结构(Program structure) 2 | 3 | Python程序由包、模块(即一个Python文件.py)和函数组成,包是由一系列模块组成的集合,模块是处理某一类问题的函数和类的集合。 4 | 5 | ![python程序结构](https://wiki.huihoo.com/images/b/b6/Python-program-structur.png) 6 | 7 | (图片来自:w3cschool.cn) 8 | 9 | 包中必须至少含有一个__init__.py文件,该文件的内容可以为空。用于标识当前文件夹是一个包。 10 | 11 | ### 物理设计 12 | 13 | * 组件与类 14 | 15 | * 依赖关系 16 | 17 | * 层次化 18 | 19 | * 包 20 | 21 | ### 逻辑设计 22 | 23 | * 构建一个组件 24 | 25 | * 设计一个函数 26 | 27 | * 实现一个对象 28 | 29 | ### Web项目结构 30 | 一个非常简单的Web站点目录结构: 31 | ``` 32 | mysite/ 33 | manage.py 34 | mysite/ 35 | __init__.py 36 | settings.py 37 | urls.py 38 | wsgi.py 39 | ``` 40 | 41 | ### 网站架构 42 | 组成 Web 网站的核心主要包括模型(数据)、视图(显示)、模版(渲染)、表单(交互)、安全等。 43 | 44 | 网站支撑软件包括:web server、database等。 45 | 46 | ### 脚手架 47 | 我们将采用 Django 框架,它提供了方便的管理工具,能自动创建项目、应用的目录和初始化文件。 48 | 49 | ``` 50 | 创建项目 51 | $ django-admin startproject mysite 52 | 53 | 创建应用 54 | $ python manage.py startapp polls 55 | 56 | 一个项目可包含多个应用 57 | ``` 58 | 配图来自Twitter 59 | 60 | ![配图12](https://wiki.huihoo.com/images/thumb/e/e8/Devopsgirls12.jpg/1280px-Devopsgirls12.jpg) 61 | -------------------------------------------------------------------------------- /courses/python13.md: -------------------------------------------------------------------------------- 1 | # 第13课:函数(Function) 2 | 3 | ### def 4 | 我们来写一个最简单的函数 5 | ``` 6 | >>> def hello(): 7 | ... print ("Hello World!") 8 | ... 9 | >>> hello() 10 | Hello World! 11 | ``` 12 | 13 | ### lambda 14 | lambda表达式是一行函数,它和普通函数完全一样,它在其它语言中叫匿名函数。 15 | 16 | Python使用lambda来创建匿名函数,匿名就是不用像def那样定义函数。 17 | 18 | lambda是表达式,它不是代码块。 19 | 20 | lambda原型 21 | ``` 22 | lambda 参数 : 操作(参数) 23 | 24 | >>> add = lambda x, y : x + y 25 | >>> print(add(1, 2)) 26 | ``` 27 | 28 | 写一个简单的Lambda表达式 29 | ``` 30 | >>> hello = lambda x, y : x*2+y*2 31 | >>> hello(2,3) 32 | 10 33 | ``` 34 | 35 | 来一个复杂点的:列表排序 36 | ``` 37 | >>> sl = [(2, 3), (4, 2), (11, -2)] 38 | >>> sl.sort(key=lambda x: x[1]) 39 | >>> print(sl) 40 | [(11, -2), (4, 2), (2, 3)] 41 | 42 | >>> sl = [(2, 1, 3), (4, 3, 2), (11, 9, -2)] 43 | >>> sl.sort(key=lambda x: x[1]) 44 | >>> print(sl) 45 | [(2, 1, 3), (4, 3, 2), (11, 9, -2)] 46 | ``` 47 | 48 | 思考下def和lambda有哪些联系和不同? 49 | 50 | 配图来自Twitter:@neku_draw 51 | 52 | ![配图13](https://wiki.huihoo.com/images/thumb/7/77/Devopsgirls13.png/717px-Devopsgirls13.png) 53 | -------------------------------------------------------------------------------- /courses/python14.md: -------------------------------------------------------------------------------- 1 | # 第14课:面向对象(Object orientation)(一) 2 | 3 | Python设计之初就是一门面向对象编程语言。对象是Python最核心的概念,在Python的世界里,一切都是对象,一个整数是对象,一个字符串是对象,一个字典是对象。 4 | 5 | 在Python中,已预先定义了一些常见类型对象,如:int类型、str类型、list类型等。这些类型对象通过实例化,可以创建相应的实例对象,如:int对象、str对象、list对象等。 6 | 7 | 对象 = 属性(attribute) + 方法(method) 8 | 9 | 如:球(ball) 10 | 11 | 属性有: 12 | * ball.color 13 | * ball.size 14 | 15 | 方法有: 16 | * ball.kick() 17 | * ball.throw() 18 | 19 | ``` 20 | >>> help(int) 21 | class int(object) 22 | | int(x=0) -> integer 23 | | int(x, base=10) -> integer 24 | >>> help(str) 25 | class str(object) 26 | | str(object='') -> str 27 | | str(bytes_or_buffer[, encoding[, errors]]) -> str 28 | >>> help(list) 29 | class list(object) 30 | | list() -> new empty list 31 | | list(iterable) -> new list initialized from iterable's items 32 | ``` 33 | 34 | 此外,Python也允许通过class a(object)这样的表达式定义自己的类型对象。 35 | 36 | Python的对象系统庞大而复杂,核心使用C语言实现。 37 | 38 | PS:Python语言核心:类型系统、对象系统。这也几乎是所有OO语言的核心,也是构建大规模Python应用的基础,所以掌握类型系统和对象系统是学习掌握一门新语言的关键。 39 | 40 | ### 一些面向对象概念 41 | * 类(class) 42 | 具有相同属性和方法的对象的集合。 43 | * 对象(object) 44 | 对象是类的实例。 45 | * 属性(attribute) 46 | 属性并不属于类,它属于各个实例。属性引用:obj.name 47 | * 方法(method) 48 | 类中定义的函数。 49 | * 实例化(instantiation) 50 | 创建类的具体对象。 51 | * 数据成员(data member) 52 | 类变量或者实例变量。 53 | * 类变量(class variable) 54 | 类变量定义在类中且在函数体之外,在整个实例化的对象中是公用的。 55 | * 实例变量(instance variable) 56 | 定义在方法中的变量,只作用于当前实例的类。 57 | * 继承(inheritance):基类(base class)、派生类(derived class) 58 | * 多态(polymorphism) 59 | 同一个方法,不同的行为。不同的类可以有同名的两个或多个方法。 60 | * 方法重载(override) 61 | 若从父类继承的方法不能满足子类的需求,可以对其进行改写(重写). 62 | 63 | ### 公共私有 64 | * 公共方法 65 | * 私有方法 66 | __private_method:两个下划线开头,只能在类的内部调用。self.__private_methods 67 | * 公共属性 68 | * 私有属性 69 | __private_attrs:两个下划线开头,只能在类内部的方法中使用。self.__private_attrs 70 | 71 | ### 创建类 72 | ``` 73 | >>> class Ball: 74 | ... def bounce(self): 75 | ... if self.direction == "down": 76 | ... self.direction = "up" 77 | ... 78 | >>> 79 | ``` 80 | ### 实例化 81 | ``` 82 | 创建类的一个实例,并设置一些属性 83 | >>> myBall = Ball() 84 | >>> myBall.direction = "down" 85 | >>> myBall.color = "red" 86 | >>> myBall.size = "big" 87 | 使用一个方法 88 | >>> myBall.bounce() 89 | ``` 90 | 91 | 配图来自Twitter:@chengr28 92 | 93 | ![配图14](https://wiki.huihoo.com/images/f/f8/Devopsgirls14.jpg) 94 | -------------------------------------------------------------------------------- /courses/python15.md: -------------------------------------------------------------------------------- 1 | # 第15课:面向对象(Object orientation)(二) 2 | 3 | ### 继承 4 | 若没有继承,它也不能称为"类"。想想父类、子类,父母、儿女。 5 | 6 | 在面向对象编程中,类通过从其它类继承属性、方法,这样就形成了一个“家族”,整个“家族”里的每个类共享相同的属性和方法。而每次向“家族”增加新成员时也不必从头开始。 7 | 8 | ### 方法重载 9 | Python 的方法重载或者函数重载这块,一直都存在一些争议。对于 C++ 这类静态语言,函数重载很自然、也很推崇。 10 | 11 | 如 C++ 中,函数 EatApple、EatOrange、EatBanana 可以用同一个函数名 Eat 表示,而用不同的类型参数加以区别: 12 | ``` 13 | void EatApple(...); 可改为 void Eat(Apple ...); 14 | void EatOrange(...); 可改为 void Eat(Orange ...); 15 | void EatBanana(...); 可改为 void Eat(Banana ...); 16 | ``` 17 | 这样,函数名被重载,便于记忆,也提高了函数的易用性。 18 | 19 | 而 Python 这类动态语言,是否需要重载,大家各执己见。有兴趣的同学可参考知乎上的讨论:[为什么 Python 不支持函数重载?其他函数大部分都支持的?](https://www.zhihu.com/question/20053359) 并自己展开。 20 | 21 | 另外,Python 中的函数(function)和方法(method)是有一定区别的,简单记忆,方法随类而出现。 22 | * 与类和实例无绑定(unbound)关系的 def 属于函数(function),是在 class 外部定义的函数。 23 | * 与类和实例有绑定关系(bound)的 def 属于方法(method),是在 class 内部定义的函数。 24 | 25 | ### 类专有方法 26 | Python 有很多类似 `__init__` 、`__del__ `、` __add__`、` __sub__` 这样的特殊方法(也叫魔法方法),如: 27 | 28 | * `__init__` : 构造函数,对象创建时调用 29 | * `__del__` : 析构函数,对象收回时调用 30 | * `__add__`: 加运算 31 | * `__sub__`: 减运算 32 | * `__mul__`: 乘运算 33 | * `__div__`: 除运算 34 | * `__mod__`: 取余运算 35 | * `__pow__`: 乘方 36 | * `__or__`:或运算 37 | * `__repr__`/`__str__` : 打印,转换 38 | * `__call__`:函数调用 39 | * `__getattr__`:属性引用 40 | * `__setattr__`:属性赋值 41 | * `__getitem__`: 索引运算 42 | * `__setitem__` : 索引赋值 43 | * `__len__`: 长度 44 | * `__cmp__`: 比较运算 45 | 46 | ### 运算符重载 47 | 对已有的运算符进行重新定义,实现新的功能。 48 | 49 | 如:构造函数和析构函数:`__init__` 、`__del__ ` 50 | 51 | 它们的主要作用是对象的创建和回收,当实例创建时,就会调用__init__构造方法。当实例对象收回时,析构函数__del__会被执行。 52 | 53 | ``` 54 | >>> class Person(): 55 | ... def __init__(self, n): 56 | ... self.name = n 57 | ... print("__init__", self.name) 58 | ... def __del__(self): 59 | ... print("__del__") 60 | ... 61 | >>> p = Person('Allen') 62 | __init__ Allen 63 | >>> p = 'Peter' 64 | __del__ 65 | ``` 66 | 67 | ### 自省 68 | 对人来讲,自省(introspection)就是对自身思想、情绪、动机和行为的审视,能帮助我们更好的认识和改善自己。同理,Python自省能帮助开发者更深入了解和洞察Python对象所包含或隐藏的各种细节。 69 | 70 | Python包含了很多内置函数和模块可帮助到我们。 71 | 72 | #### dir函数 73 | dir是用于自省一个重要的函数,它返回一个对象所拥有的属性和方法。 74 | ``` 75 | 当前作用域 76 | >>> dir() 77 | ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'add', 'keyword', 'sl', 'sys'] 78 | 79 | 之前第13课定义的sl 80 | >>> dir(sl) 81 | ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 82 | ... 83 | ``` 84 | 85 | #### sys模块 86 | sys模块的属性 87 | ``` 88 | >>> import sys 89 | >>> dir(sys) 90 | ['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', 91 | ... 92 | ``` 93 | 94 | #### keyword模块 95 | keyword模块的关键字列表 96 | ``` 97 | >>> import keyword 98 | >>> keyword.kwlist 99 | ['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] 100 | ``` 101 | 102 | keyword模块的属性 103 | ``` 104 | >>> import keyword 105 | >>> dir(keyword) 106 | ['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'iskeyword', 'kwlist', 'main'] 107 | ``` 108 | 109 | #### inspect模块 110 | ``` 111 | >>> import inspect 112 | >>> print(inspect.getmembers(sl)) 113 | >>> print(inspect.getmembers(str)) 114 | ``` 115 | 116 | #### type和id 117 | type()和id()返回对象类型和对象id 118 | ``` 119 | >>> print(type(sl)) 120 | 121 | >>> print(type(9)) 122 | 123 | >>> name = "python" 124 | >>> print(id(name)) 125 | 4552783720 126 | ``` 127 | 128 | 配图来自Twitter:@chengr28 129 | 130 | ![配图15](https://wiki.huihoo.com/images/a/a0/Devopsgirls15.jpg) 131 | -------------------------------------------------------------------------------- /courses/python16.md: -------------------------------------------------------------------------------- 1 | # 第16课:模块/库(Module/Library)(一) 2 | 3 | 先抛出一个简单python web应用的例子的目录结构: 4 | 5 | ``` 6 | mysite/ 7 | manage.py 8 | mysite/ 9 | __init__.py 10 | settings.py 11 | urls.py 12 | wsgi.py 13 | polls/ 14 | __init__.py 15 | admin.py 16 | migrations/ 17 | __init__.py 18 | 0001_initial.py 19 | models.py 20 | static/ 21 | polls/ 22 | images/ 23 | background.gif 24 | style.css 25 | templates/ 26 | polls/ 27 | detail.html 28 | index.html 29 | results.html 30 | tests.py 31 | urls.py 32 | views.py 33 | templates/ 34 | admin/ 35 | base_site.html 36 | ``` 37 | 你可以执行以下import语句引入 38 | * import mysite.polls.tests 39 | * from mysite.polls import urls 40 | * import mysite.pools.views as views 41 | 42 | ### 命名空间(namespace)和作用域(scope) 43 | python最大特点也是最核心思想就是: 一切皆对象。 44 | 45 | 命名空间是名字和对象的映射,可以把一个namespace理解为一个字典。 46 | 47 | 命名空间的作用:程序在直接访问变量时,会在当前的命名空间内查找,并会从内到外依次访问所有的作用域直到找到。 48 | 49 | 命名空间可以分为三类: 50 | * 函数的局部命名空间 51 | * 模块的全局命名空间 52 | * 内置命名空间 53 | 54 | 作用域就是一个Python程序可以直接访问命名空间的区域,可以具体分为以下四个作用域: 55 | * Local(innermost) 最里面的局部作用域 56 | * Enclosing 外层函数的局部作用域 57 | * Global(next-to-last) 模块的全局作用域 58 | * Built-in(outtermost) 包含Python内置对象的最外层作用域 59 | 60 | ``` 61 | def scope_test(): 62 | def do_local(): 63 | variable = "local variable" 64 | 65 | def do_nonlocal(): 66 | nonlocal variable 67 | variable = "nonlocal variable" 68 | 69 | def do_global(): 70 | global variable 71 | variable = "global variable" 72 | 73 | variable = "test variable" 74 | do_local() 75 | print("After local assignment:", variable) 76 | do_nonlocal() 77 | print("After nonlocal assignment:", variable) 78 | do_global() 79 | print("After global assignment:", variable) 80 | 81 | scope_test() 82 | print("In global scope:", variable) 83 | ``` 84 | 85 | ### 模块 86 | 模块即一个Python文件.py 87 | 88 | ### 包 89 | 包是由一系列模块组成的集合,包中必须至少含有一个__init__.py文件,该文件的内容可以为空,用于标识当前文件夹是一个包。 90 | 91 | 上面例子包含了三个包:mysite、polls、migrations 92 | 93 | ### 标准模块 94 | Python内置了非常多的模块,大部分是纯Python的,也有一些用C编写的模块。熟练使用这些模块,能帮助你解决日常编程中出现的许多问题,所以大家很有必要熟悉这些标准库模块。 95 | 96 | 这里简单介绍下以下常用模块的使用方法: 97 | #### error 98 | 捕获各种异常,并做特殊处理。 99 | 100 | ``` 101 | >>>import os 102 | >>>os.kill(123, 0) 103 | >>>os.strerror(3) 104 | ``` 105 | #### subprocess 106 | subprocess模块允许你生成新进程,连接到它们的input/output/error管道,并获取它们的返回代码, 该模块旨在替换几个较旧的模块和功能:os.system、os.spawn*、os.popen*等 107 | ``` 108 | >>> import subprocess 109 | >>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE) 110 | CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, stdout=b'crw-rw-rw- 1 root wheel 3, 2 2 5 17:52 /dev/null\n') 111 | ``` 112 | 113 | #### contextlib 114 | Python程序通过上下文管理能让代码的可读性更强并且错误更少。 115 | ``` 116 | from contextlib import contextmanager 117 | 118 | @contextmanager 119 | def tag(name): 120 | print("<%s>" % name) 121 | yield 122 | print("" % name) 123 | 124 | with tag("h1"): 125 | print("python") 126 | ``` 127 | 128 | #### glob 129 | glob是用来匹配UNIX风格路径名的模块,支持 '*'、'?'、'[]'三种通配符。 130 | ``` 131 | $ ls 132 | 1.txt 2.txt a1.txt a2.txt b1.txt b2.txt 133 | 134 | >>> import glob 135 | >>> glob.glob('./*.txt') 136 | ['./a1.txt', './a2.txt', './b2.txt', './2.txt', './b1.txt', './1.txt'] 137 | >>> glob.glob('./a?.txt') 138 | ['./a1.txt', './a2.txt'] 139 | >>> glob.glob('./b?.txt') 140 | ['./b2.txt', './b1.txt'] 141 | >>> glob.glob('./[0-9].*') 142 | ['./2.txt', './1.txt'] 143 | >>> glob.glob('./a[0-9].*') 144 | ['./a1.txt', './a2.txt'] 145 | >>> glob.glob('./b[0-9].*') 146 | ['./b2.txt', './b1.txt'] 147 | ``` 148 | 149 | #### operator 150 | 标准运算符作为函数,如求和我们可以使用sum,乘积可结合operator和reduce模块来实现。 151 | 152 | ``` 153 | >>> import operator 154 | >>> from functools import reduce 155 | >>> reduce(operator.mul, (5, 4, 3, 2, 1)) 156 | 120 157 | ``` 158 | 159 | #### functools 160 | functools模块用于高阶函数,包含了一系列操作其它函数的工具。 161 | ``` 162 | >>> from functools import partial 163 | >>> basetwo = partial(int, base=2) 164 | >>> basetwo.__doc__ = '将base 2字符串转换为整数' 165 | >>> basetwo('10010') 166 | 18 167 | >>> basetwo('11111') 168 | 31 169 | ``` 170 | 171 | #### collections 172 | 回忆一下之前提到的标准数据类型中包含的:dict, list, set, tuple。 173 | 174 | collections模块实现了专门的容器数据类型: 175 | * namedtuple:能创建可以通过属性访问元素内容的扩展元祖。 176 | * deque:一个双端队列,能够在队列两端添加或删除队列元素。 177 | * ChainMap: 178 | * Counter:一个方便、快速计算的计时器工具。 179 | * OrderedDict:Python的dict是无序的,而OrderedDict保证字典健值对的顺序。 180 | * defaultdict:简化了处理不存在键的场景。 181 | * UserDict: 182 | * UserList: 183 | * UserString: 184 | 185 | 举一个Counter的例子 186 | ``` 187 | >>> import collections 188 | >>> words = ['a', 'b', 'a', 'c', 'd', 'c', 'e', 'b'] 189 | >>> cnt = collections.Counter(words) 190 | >>> cnt.most_common(5) 191 | [('a', 2), ('b', 2), ('c', 2), ('d', 1), ('e', 1)] 192 | ``` 193 | 194 | ### 标准库思维导图 195 | 7张Python[常见标准库思维导图](https://woaielf.github.io/2018/04/15/python2/): 196 | * 1、标准库概述 197 | ![标准库概述](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/1.png) 198 | * 2、正则表达式 199 | ![正则表达式](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/2.png) 200 | * 3、日期 & 时间 201 | ![日期 & 时间](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/3.png) 202 | * 4、系统 & 文件 203 | ![系统 & 文件](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/4.png) 204 | * 5、进程 & 线程 205 | ![进程 & 线程](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/5.png) 206 | * 6、数据库操作 207 | ![数据库操作](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/6.png) 208 | * 7、数学运算 & 数据结构 209 | ![数学运算 & 数据结构](https://raw.githubusercontent.com/woaielf/woaielf.github.io/master/_posts/media/15237087901003/7.png) 210 | 211 | 配图来自Twitter:@chengr28 212 | 213 | ![配图16](https://wiki.huihoo.com/images/b/b9/Devopsgirls16.png) 214 | -------------------------------------------------------------------------------- /courses/python17.md: -------------------------------------------------------------------------------- 1 | # 第17课:模块/库(Module/Library)(二) 2 | 3 | ### 编写自己的模块 4 | 写一个简单的模块文件,包含两个类,每个类有一个函数。 5 | 6 | ``` 7 | # mymodule.py 8 | class A: 9 | def python(self): 10 | print('A.python') 11 | 12 | class B(A): 13 | def julia(self): 14 | print('B.julia') 15 | ``` 16 | 17 | 运行mymodule 18 | 19 | ``` 20 | >>> import mymodule 21 | >>> a = mymodule.A() 22 | >>> a.python() 23 | A.python 24 | >>> b = mymodule.B() 25 | >>> b.julia() 26 | B.julia 27 | ``` 28 | ### 对这个模块文件进行分解 29 | 用mymodule目录来替换文件 mymodule.py,创建 a.py、b.py和__init__.py文件。 30 | 31 | ``` 32 | mymodule/ 33 | __init__.py 34 | a.py 35 | b.py 36 | ``` 37 | 38 | a.py文件内容 39 | ``` 40 | # a.py 41 | class A: 42 | def python(self): 43 | print('A.python') 44 | ``` 45 | 46 | b.py文件内容 47 | ``` 48 | # b.py 49 | from .a import A 50 | class B(A): 51 | def julia(self): 52 | print('B.julia') 53 | ``` 54 | 55 | __init__.py文件内容 56 | ``` 57 | # __init__.py 58 | from .a import A 59 | from .b import B 60 | ``` 61 | 62 | 然后你也试试调用模块与函数。 63 | 64 | 真正的模块化设计和开发可没这么简单,这里只是让大家先有一个基本的概念。 65 | 66 | 好吧,今天就先到这,可以放学了 :) 67 | 68 | 配图来自Twitter:@chengr28 69 | 70 | ![配图17](https://wiki.huihoo.com/images/6/68/Devopsgirls17.jpg) 71 | -------------------------------------------------------------------------------- /courses/python18.md: -------------------------------------------------------------------------------- 1 | # 第18课:接口(Interface) 2 | 3 | ### 什么是接口 4 | 接口只是定义了一组方法,而没有具体实现。 5 | 6 | Python的接口由抽象类和抽象方法去实现,接口不能被实例化,只能被别的类继承去实现相应的功能。 7 | 8 | ### 实现方法 9 | Python 使用 abc(Abstract Base Classes)模块可以轻松的定义抽象基类,抽象类的目的就是让别的类继承它并实现特定的抽象方法。 10 | 11 | ### 用抽象类和抽象方法实现接口 12 | 1、定义抽象基类 13 | ``` 14 | from abc import ABCMeta,abstractmethod 15 | 16 | class interface(object): 17 | __metaclass__ = ABCMeta #抽象类 18 | @abstractmethod #抽象方法 19 | def python(self): 20 | pass 21 | 22 | def rust(self): 23 | pass 24 | ``` 25 | 2、继承基类并实现具体的抽象方法 26 | ``` 27 | class ImplementationInterfacePython(interface): 28 | def __init__(self): 29 | print ('这是接口实现') 30 | def python(self): 31 | print ('实现python方法') 32 | def rust(self): 33 | pass 34 | 35 | class ImplementationInterfaceRust(interface): 36 | def __init__(self): 37 | print ('这是接口实现') 38 | def python(self): 39 | pass 40 | def rust(self): 41 | print ("实现rust方法") 42 | 43 | >>> obj = ImplementationInterfacePython() 44 | 这是接口实现 45 | >>> obj.python() 46 | 实现python方法 47 | >>> obj = ImplementationInterfaceRust() 48 | 这是接口实现 49 | >>> obj.rust() 50 | 实现rust方法 51 | 52 | ``` 53 | ### 用普通类实现接口 54 | 1、定义接口 55 | ``` 56 | class interface(object): 57 | def python(self): 58 | pass 59 | 60 | def rust(self): 61 | pass 62 | 63 | ``` 64 | 65 | 2、实现接口 66 | ``` 67 | class ImplementationInterfacePython(interface): 68 | def __init__(self): 69 | pass 70 | def python(self): 71 | print ("实现接口中的python方法") 72 | 73 | 74 | class ImplementationInterfaceRust(interface): 75 | def __init__(self): 76 | pass 77 | def rust(self): 78 | print ("实现接口中的rust方法") 79 | 80 | 81 | >>> obj = ImplementationInterfacePython() 82 | >>> obj.python() 83 | 实现接口中的python方法 84 | >>> obj = ImplementationInterfaceRust() 85 | >>> obj.rust() 86 | 实现接口中的rust方法 87 | ``` 88 | 89 | ### zope.interface 90 | 此项目提供了Python对象接口的参考实现,大家可通过此项目扩展学习。 91 | 92 | https://pypi.org/project/zope.interface/ 93 | 94 | 配图来自Twitter:@chengr28 95 | 96 | ![配图18](https://wiki.huihoo.com/images/6/6e/Devopsgirls18.jpg) 97 | -------------------------------------------------------------------------------- /courses/python19.md: -------------------------------------------------------------------------------- 1 | # 第19课:闭包(Closures) 2 | 3 | ### 什么是闭包 4 | 维基百科介绍 5 | 6 | 在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。 7 | 8 | 闭包,就好比一个封闭的包裹,里面包裹着自由变量,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。 9 | 10 | ### 为什么要使用闭包 11 | 闭包避免了全局变量的使用,闭包允许将函数与其所操作的相关数据和环境关连起来。 12 | 13 | ### 如何使用闭包 14 | 一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包,你在调用函数A的时候传递的参数就是自由变量。 15 | ``` 16 | >>> def func(name): 17 | ... def inner_func(age): 18 | ... print ('name:', name, 'age:', age) 19 | ... return inner_func 20 | ... 21 | >>> hello = func('huihoo') 22 | >>> hello(18) 23 | name: huihoo age: 18 24 | ``` 25 | 26 | 调用func的时候就产生了一个闭包inner_func,该闭包也包含name自由变量。当func生命周期结束了,name自由变量依然存在,因为它被闭包引用,所以不会被回收。 27 | 28 | 配图来自Twitter:@MacciattoS2 29 | 30 | ![配图19](https://wiki.huihoo.com/images/a/af/Devopsgirls19.jpg) 31 | -------------------------------------------------------------------------------- /courses/python20.md: -------------------------------------------------------------------------------- 1 | # 第20课:元编程(Metaprogramming) 2 | 软件开发领域中最经典的口头禅就是“don’t repeat yourself”。 也就是说,任何时候当你的程序中存在很多重复的代码时,我们都应该想想是否有更好的解决方案。在Python当中,通常都可以通过元编程来解决这类问题,主要技术是使用装饰器、类装饰器和元类。 3 | 4 | ## 在函数上添加包装器 5 | 6 | 1、定义一个装饰器,增加额外的操作处理(如日志、计时、计数等),也可定义多个装饰器。 7 | 8 | 此装饰器是通过@wraps来实现的。 9 | 10 | ``` 11 | import time 12 | from functools import wraps 13 | 14 | def timethis(func): 15 | ''' 16 | 装饰器报告执行时间 17 | ''' 18 | @wraps(func) 19 | def wrapper(*args, **kwargs): 20 | start = time.time() 21 | result = func(*args, **kwargs) 22 | end = time.time() 23 | print(func.__name__, end-start) 24 | return result 25 | return wrapper 26 | ``` 27 | 28 | 2、使用装饰器 29 | ``` 30 | >>> @timethis 31 | ... def countdown(n): 32 | ... ''' 33 | ... 计数 34 | ... ''' 35 | ... while n > 0: 36 | ... n -= 1 37 | ... 38 | >>> countdown(1000) 39 | countdown 5.602836608886719e-05 40 | >>> countdown(10000) 41 | ``` 42 | 3、解除装饰器 43 | 使用__wrapped__解除装饰器 44 | ``` 45 | >>> countdown.__wrapped__(1000) 46 | >>> countdown.__wrapped__(10000) 47 | ``` 48 | 这时就没打印时间信息了 49 | 50 | 注意:并不是所有的装饰器都使用了 @wraps,如内置的装饰器 @staticmethod 和 @classmethod 就没有遵循这个约定 (它们把原始函数存储在属性 __func__ 中)。 51 | 52 | 嗯,有点累了,带狗狗出去散下步。 53 | 54 | 配图来自Twitter:@chengr28 55 | 56 | ![配图20](https://wiki.huihoo.com/images/5/5a/Devopsgirls20.jpg) 57 | -------------------------------------------------------------------------------- /courses/python21.md: -------------------------------------------------------------------------------- 1 | # 第21课:测试(Testing)(一) 2 | 3 | 其实,这块包含软件测试、自动化、软件质量等内容,但这里我们主要学习讨论Python测试的一些入门知识。 4 | 5 | 先回顾一下[第8课:错误、异常](python08.md)的内容 6 | 7 | ### unittest 8 | unittest是Python用于单元测试的标准模块。 9 | 10 | 先运行一个简单的单元测试,感受下: 11 | ``` 12 | >>> import unittest 13 | >>> 14 | >>> class MyTest(unittest.TestCase): 15 | ... pass 16 | ... 17 | >>> if __name__ == '__main__': 18 | ... unittest.main() 19 | ... 20 | 21 | ---------------------------------------------------------------------- 22 | Ran 0 tests in 0.000s 23 | ``` 24 | 再来一个复杂点的单元测试,运行5个小测试:可忽略、标记、或按照预期运行失败。 25 | 26 | unittest模块中的装饰器可用来控制对指定测试方法的处理,如:skip、skipIf、skipUnless、expectedFailure等。 27 | 28 | 如在macOS上运行以下测试,touch unittestsample.py 29 | ``` 30 | import unittest 31 | import os 32 | import platform 33 | 34 | class Tests(unittest.TestCase): 35 | def test_0(self): 36 | self.assertTrue(True) 37 | 38 | @unittest.skip('skipped test') 39 | def test_1(self): 40 | self.fail('should have failed!') 41 | 42 | @unittest.skipIf(os.name=='posix', 'Not supported on Unix') 43 | def test_2(self): 44 | import winreg 45 | 46 | @unittest.skipUnless(platform.system() == 'Darwin', 'Mac specific test') 47 | def test_3(self): 48 | self.assertTrue(True) 49 | 50 | @unittest.expectedFailure 51 | def test_4(self): 52 | self.assertEqual(2+2, 5) 53 | 54 | if __name__ == '__main__': 55 | unittest.main() 56 | ``` 57 | 58 | 运行这个例子: 59 | ``` 60 | (venv2) gougou:python huihoo$ python unittestsample.py -v 61 | test_0 (__main__.Tests) ... ok 62 | test_1 (__main__.Tests) ... skipped 'skipped test' 63 | test_2 (__main__.Tests) ... skipped 'Not supported on Unix' 64 | test_3 (__main__.Tests) ... ok 65 | test_4 (__main__.Tests) ... expected failure 66 | 67 | ---------------------------------------------------------------------- 68 | Ran 5 tests in 0.001s 69 | 70 | OK (skipped=2, expected failures=1) 71 | ``` 72 | ### doctest 73 | doctest模块会搜索那些看起来像是python交互式会话中的代码片段,然后尝试执行并验证结果。 74 | 75 | 运行一个简单的doctext,先感受下: 76 | ``` 77 | >>> if __name__ == "__main__": 78 | ... import doctest 79 | ... doctest.testmod() 80 | ... 81 | TestResults(failed=0, attempted=0) 82 | ``` 83 | 再来一个稍微复杂点的例子,创建一个doctestsample.py文件,有两个测试用例,包含以下内容: 84 | ``` 85 | def add(a, b): 86 | """ 87 | >>> add(1, 2) 88 | 3 89 | >>> add('python ', 'rust') 90 | 'python rust' 91 | """ 92 | return a + b 93 | if __name__=='__main__': 94 | import doctest 95 | doctest.testmod() 96 | ``` 97 | 98 | 运行这个例子: 99 | ``` 100 | python -m doctest -v doctestsample.py # -m 表示引用一个模块,-v 等价于 verbose=True 101 | python doctestsample.py -v 102 | 103 | 运行结果: 104 | Trying: 105 | add(1, 2) 106 | Expecting: 107 | 3 108 | ok 109 | Trying: 110 | add('python ', 'rust') 111 | Expecting: 112 | 'python rust' 113 | ok 114 | 1 items had no tests: 115 | __main__ 116 | 1 items passed all tests: 117 | 2 tests in __main__.add 118 | 2 tests in 2 items. 119 | 2 passed and 0 failed. 120 | Test passed. 121 | 122 | ``` 123 | 124 | ### py.test 125 | 安装 pip install pytest 126 | 127 | 创建pytestsample.py文件,包含: 128 | ``` 129 | def inc(x): 130 | return x + 1 131 | 132 | def test_answer(): 133 | assert inc(3) == 5 134 | ``` 135 | 136 | 运行测试: 137 | ``` 138 | $ pytest pytestsample.py 139 | ================================= test session starts ====================================== 140 | platform darwin -- Python 3.7.1, pytest-4.2.0, py-1.7.0, pluggy-0.8.1 141 | rootdir: /private/tmp/python, inifile: 142 | collected 1 item 143 | pytestsample.py F [100%] 144 | 145 | ================================= FAILURES =================================== 146 | _________________________________ test_answer ___________________________________ 147 | 148 | def test_answer(): 149 | > assert inc(3) == 5 150 | E assert 4 == 5 151 | E + where 4 = inc(3) 152 | 153 | pytestsample.py:5: AssertionError 154 | ================================ 1 failed in 0.45 seconds ======================================== 155 | 156 | ``` 157 | ### mock 158 | 在单元测试中,模拟对象可以模拟复杂的、真实的(非模拟)对象的行为, 如果真实的对象无法放入单元测试中,使用模拟对象就很有帮助。 159 | 160 | 为什么要用mock? 161 | 162 | 在下面的情形,可能需要使用模拟对象来代替真实对象: 163 | 164 | * 真实对象的行为是不确定的(例如,当前的时间或当前的温度); 165 | * 真实对象很难搭建起来; 166 | * 真实对象的行为很难触发(例如,网络错误); 167 | * 真实对象速度很慢(例如,一个完整的数据库,在测试之前可能需要初始化); 168 | * 真实的对象是用户界面,或包括用户界面在内; 169 | * 真实的对象使用了回调机制; 170 | * 真实对象可能还不存在; 171 | * 真实对象可能包含不能用作测试(而不是为实际工作)的信息和方法。 172 | 173 | 从Python 3.3开始,mock模块已经被合并到标准库中,被命名为unittest.mock 174 | 175 | from unittest import mock 176 | 177 | 在Python 3.3以前版本,需要安装,pip install mock 178 | 179 | import mock 180 | 181 | 先感受下mock 182 | ``` 183 | >>> from unittest.mock import MagicMock 184 | >>> mock = MagicMock(side_effect=[1, 2, 3]) 185 | >>> mock() 186 | 1 187 | >>> mock() 188 | 2 189 | >>> mock() 190 | 3 191 | ``` 192 | 193 | Mock这块内容会比较多,以后再深入展开。 194 | 195 | 今天是大年初三,顺祝大家2019,新年快乐! 196 | 197 | 配图来自Twitter:@chengr28 198 | 199 | ![配图21](https://wiki.huihoo.com/images/4/4e/Devopsgirls21.jpg) 200 | -------------------------------------------------------------------------------- /courses/python22.md: -------------------------------------------------------------------------------- 1 | # 第22课:测试(Testing)(二) 2 | 3 | ### 持续集成 4 | 5 | 常用的CI服务器有:Jenkins、Travis CI、GitLab CI、Buildbot等。 6 | 7 | 这里,我们使用Buildbot做持续集成服务器。 8 | 9 | Buildbot 是一个软件项目编译、测试的自动化系统,它的架构如下: 10 | 11 | ![buildbot](images/class22-05.png) 12 | 13 | 主要包含:Master、Worker 14 | 15 | ### Python Buildbot 16 | Python 也采用 Buildbot 作为自己的构建、测试和持续集成的基础设施,我们先[感受下](https://www.python.org/dev/buildbot/)。 17 | 18 | ![class22-01](images/class22-01.png) 最近的构建 19 | 20 | ![class22-02](images/class22-02.png) 构建成功 21 | 22 | ![class22-03](images/class22-03.png) 构建失败 23 | 24 | ### 安装 25 | 以 [virtualenv](https://pypi.python.org/pypi/virtualenv) 的方式安装和运行 Buildbot,virtualenv大家也同时了解下。 26 | ``` 27 | (1)安装 master 28 | $ mkdir -p ~/tmp/bb-master 29 | $ cd ~/tmp/bb-master 30 | $ python3 -m venv sandbox 31 | $ source sandbox/bin/activate 32 | 33 | $ pip install --upgrade pip 34 | $ pip install 'buildbot[bundle]' 35 | 36 | (2)创建并启动 master 37 | $ buildbot create-master master 38 | $ mv master/master.cfg.sample master/master.cfg 39 | $ buildbot start master 40 | 41 | (3)安装 worker 42 | 打开另一个终端 43 | $ mkdir -p ~/tmp/bb-worker 44 | $ cd ~/tmp/bb-worker 45 | $ python3 -m venv sandbox 46 | $ source sandbox/bin/activate 47 | 48 | $ pip install --upgrade pip 49 | $ pip install buildbot-worker 50 | $ pip install setuptools-trial 51 | 52 | (4)创建并启动 worker 53 | $ buildbot-worker create-worker worker localhost example-worker pass 54 | $ cat ../bb-master/master/master.cfg 55 | $ buildbot-worker start worker 56 | ``` 57 | http://localhost:8010 58 | 59 | ![class22-04](images/class22-04.png) 60 | 61 | ### Hello World 62 | 使用这个测试用例 https://github.com/buildbot/hello-world 63 | 64 | ``` 65 | $ cd ~/tmp/bb-master 66 | $ source sandbox/bin/activate 67 | $ 看一看这个文件 master/master.cfg,应包含 68 | c['title'] = "Hello World CI" 69 | c['titleURL'] = "https://buildbot.github.io/hello-world/" 70 | 71 | 打开 Builders 页,点击 runtests 链接,点击右上角 “force” 按钮,然后 Start Build。 72 | ``` 73 | ![class22-06](images/class22-06.png) 74 | 75 | 开心,构建成功 :) 76 | 77 | ![class22-07](images/class22-07.png) 78 | 79 | 配图来自Twitter:@neku_draw 80 | 81 | ![配图22](https://wiki.huihoo.com/images/thumb/6/69/Devopsgirls22.jpg/713px-Devopsgirls22.jpg) 82 | -------------------------------------------------------------------------------- /courses/python23.md: -------------------------------------------------------------------------------- 1 | # 第23课:设计模式(Design patterns) 2 | 在这里放出设计模式,好像不是特别合适,但直觉是早一点了解些设计模式,对之后的提高是很有帮助的。 3 | 4 | ### 设计模式 5 | 在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。 6 | 7 | ![设计模式](https://wiki.huihoo.com/images/thumb/a/a2/Design-pattern.png/1280px-Design-pattern.png) 8 | [点击下载大图](https://wiki.huihoo.com/images/a/a2/Design-pattern.png) 9 | 10 | 图片来自[icemoon1987](http://www.cnblogs.com/icemoon1987/p/3349415.html) 11 | 12 | 经典的《设计模式:可复用面向对象软件的基础》包含23个设计模式,这本书是软件工程领域有关软件设计的一本重要的书,提出和总结了对于一些常见软件设计问题的标准解决方案,称为软件设计模式。该书作者为:埃里希·伽玛(Erich Gamma), Richard Helm , Ralph Johnson,John Vlissides,后以“四人帮”(Gang of Four,GoF)著称。 13 | 14 | 先这23个设计模式罗列一下,以后需要的可继续深入下去。 15 | 16 | ### 创建范例 17 | 创建范例全部是关于如何创建实例的。这组范例可以被划分为两组:类创建范例及对象创建范例。类创建实例在实例化过程中有效的使用类之间的继承关系,对象创建范例则使用代理来完成其任务。 18 | 19 | * 抽象工厂 (Abstract Factory pattern) 20 | * 构造器 (Builder pattern) 21 | * 工厂方法 (Factory Method pattern) 22 | * 原型 (Prototype pattern) 23 | * 单例模式 (Singleton pattern) 24 | 25 | ### 结构范例 26 | 这组范例都是关于类及对象复合关系的。 27 | 28 | * 适配器(Adapter pattern) 29 | * 桥接(Bridge pattern) 30 | * 组合(Composite pattern) 31 | * 装饰(Decorator pattern) 32 | * 外观(Façade pattern) 33 | * 享元(Flyweight pattern) 34 | * 代理(Proxy pattern) 35 | 36 | ### 行为范例 37 | 这组范例都是关于对象之间如何通讯的。 38 | 39 | * 职责链(Chain-of-responsibility pattern) 40 | * 命令(Command pattern) 41 | * 解释器(Interpreter pattern) 42 | * 迭代器(Iterator pattern) 43 | * 中介者(Mediator pattern) 44 | * 备忘录(Memento pattern) 45 | * 观察者(Observer pattern) 46 | * 状态机(State pattern) 47 | * 策略(Strategy pattern) 48 | * 模板方法(Template method pattern) 49 | * 访问者(Visitor pattern) 50 | 51 | ### 例子 52 | 53 | ### python-patterns 54 | https://github.com/faif/python-patterns 55 | 56 | 通过这个项目来介绍一下设计模式 57 | 58 | 这块内容有点多,以后单独深入展开。 59 | 60 | ### 参考 61 | * [Design Patterns](https://sourcemaking.com/design_patterns) 62 | 63 | 配图来自Twitter:@chengr28 64 | 65 | ![配图23](https://wiki.huihoo.com/images/2/26/Devopsgirls23.jpg) 66 | -------------------------------------------------------------------------------- /courses/python24.md: -------------------------------------------------------------------------------- 1 | # 第24课:领域特定语言(Domain-specific language,DSL) 2 | 3 | 领域特定语言(domain-specific language、DSL)指的是专注于某个应用程序领域的计算机语言,如SQL语言,正则表达式。 4 | 5 | DSL分为两类: 6 | * 内部DSL(Internal DSL),DSL和宿主语言是相同的语言。 7 | * 外部DSL(External DSL),DSL和宿主语言不同,需要自己写解释器。 8 | 9 | 抛个问题先:世界上最强大的 DSL 实现语言,不是 Haskell 或者 Scala,而应该是 Scheme? 10 | 11 | 看不懂没关系,留在以后思考。 12 | 13 | ### 为什么有DSL 14 | 通用语言在解决某些特定领域的问题有时会显得有些吃力,这时候DSL似乎就有了用武之地。 15 | 16 | 个人感觉,若能在某些特定领域拥有比其它同学更简单、更高效的解决方法和手段,也是自己的一个加分项和优势。 17 | 18 | ### Python DSL 19 | Python是一门通用、灵活、高效的语言,它在解决某些特定领域问题时会比较擅长。 20 | 21 | 目前,Python是数据科学和机器学习领域的明星语言,这些也都源于它所具有的语言特性和优势。 22 | 23 | ### 参考例子 24 | 一个简单的Internal DSL for SQL DDL。 25 | ``` 26 | from contextlib import contextmanager 27 | 28 | class Table(object): 29 | def __init__(self, table_name): 30 | self.table_name = table_name 31 | self.fields = {} 32 | 33 | def __getattr__(self, name): 34 | def f(**kvs): 35 | self.fields[name] = kvs 36 | return f 37 | 38 | def execute(self): 39 | print ("Creating table %s with fields %s"%(self.table_name, self.fields)) 40 | 41 | @contextmanager 42 | def create_table(table_name): 43 | table = Table(table_name) 44 | yield table 45 | table.execute() 46 | 47 | with create_table('User') as t: 48 | t.first_name(type='char', length=30) 49 | t.last_name(type='char', length=30) 50 | t.age(type='int') 51 | 52 | 运行结果: 53 | Creating table User with fields {'first_name': {'type': 'char', 'length': 30}, 'last_name': {'type': 'char', 'length': 30}, 'age': {'type': 'int'}} 54 | 55 | ``` 56 | 57 | ### 参考 58 | * [王垠《聊聊 DSL》](http://www.yinwang.org/blog-cn/2017/05/25/dsl) 59 | * [Creating Domain Specific Languages in Python](https://www.slideshare.net/Siddhi/creating-domain-specific-languages-in-python) 60 | * [Domain-specific languages to Manycore and GPU: Building High-Performance Tools with Python](https://github.com/inducer/languages-and-codegen-tutorial) 61 | * [Writing a Domain Specific Language (DSL) in Python](https://dbader.org/blog/writing-a-dsl-with-python) 62 | 63 | 配图来自Twitter:@makadamixa 64 | 65 | ![配图24](https://wiki.huihoo.com/images/thumb/8/8e/Devopsgirls24.jpg/800px-Devopsgirls24.jpg) 66 | -------------------------------------------------------------------------------- /courses/python25.md: -------------------------------------------------------------------------------- 1 | # 第25课:Django web框架概述 2 | 3 | 4 | ### 简介 5 | 简单讲,Django 是一个模型-模板-视图(model-template-view,MTV)框架。 6 | 7 | $ pip install django 8 | 9 | ``` 10 | $ python -m django --version 或 11 | >>> import django 12 | >>> print(django.get_version()) 13 | 2.1.5 14 | ``` 15 | 16 | ### 运行第一个项目 17 | $ django-admin startproject mysite 18 | 19 | 看看创建了什么 20 | ``` 21 | mysite/ 22 | manage.py # 一个让你用各种方式管理Django项目的命令行工具 23 | mysite/ 24 | __init__.py # 一个空文件,告诉Python这个目录应该被认为是一个Python包 25 | settings.py # Django项目的配置文件 26 | urls.py # URL声明,就是网站的目录 27 | wsgi.py # 运行在WSGI兼容的Web服务器上的入口 28 | ``` 29 | $ python manage.py runserver 30 | 31 | http://127.0.0.1:8000 32 | 33 | ### Why Django 34 | 用来构建Web项目的框架很多,为什么选择Django,因为个人觉得Django包含了你构建Web应用需要的所有功能,你不需要太多挑选和各种评估(这个其实是需要很多经验和实践的)而对于大多数开发者,TA们的核心工作就是开发业务和应用系统,快速搭建产品原型和持续迭代。而不用花太多时间去选择,我想这也是我推荐Django的原因。 35 | 36 | [DjangoSites](https://www.djangosites.org/) 提供一个不断增长的使用 Django 搭建的网站的列表,有很多开源的网站可直接拿来用。 37 | 38 | ### PostgreSQL 39 | 先安装并启动PostgreSQL,后面的应用都会使用到它。 40 | 41 | 使用[pgAdmin](https://www.pgadmin.org/)连接和管理PostgreSQL。 42 | 43 | 安装Psycopgs适配器 44 | 45 | $ pip install psycopg2-binary 46 | ``` 47 | >>> import psycopg2 48 | >>> conn = psycopg2.connect("dbname=test user=postgres password=postgres") 49 | >>> cur = conn.cursor() 50 | >>> cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);") 51 | >>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (10, "python")) 52 | >>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (11, "rust")) 53 | >>> cur.execute("SELECT * FROM test;") 54 | >>> cur.fetchall() 55 | [(8, 10, 'python'), (9, 11, 'rust')] 56 | >>> conn.commit() # 写入数据库,打开数据库看插入了两条记录 57 | >>> cur.close() 58 | >>> conn.close() 59 | ``` 60 | 配图来自Twitter:@neku_draw 61 | 62 | ![配图25](https://wiki.huihoo.com/images/3/3c/Devopsgirls25.jpg) 63 | -------------------------------------------------------------------------------- /courses/python26.md: -------------------------------------------------------------------------------- 1 | # 第26课:入门 - 请求和响应(一) 2 | 3 | ### 创建第一个Django应用 4 | 注意这里是创建应用而不是创建项目: 5 | * 应用是一个专门做某件事的网络应用程序——比如博客系统,或者简单的投票程序。 6 | * 项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。 7 | 8 | 进入上一节课创建的 mysite 目录,然后运行: 9 | 10 | $ python manage.py startapp polls 11 | ``` 12 | polls/ 13 | __init__.py 14 | admin.py 15 | apps.py 16 | migrations/ 17 | __init__.py 18 | models.py 19 | tests.py 20 | views.py 21 | ``` 22 | 23 | ### 编写第一个视图 24 | 打开 polls/views.py,加入以下代码: 25 | ``` 26 | from django.http import HttpResponse 27 | 28 | def index(request): 29 | return HttpResponse("Hello Polls") 30 | ``` 31 | 32 | ### 创建URLconf 33 | 新建urls.py,加入以下代码: 34 | ``` 35 | from django.urls import path 36 | 37 | from . import views 38 | 39 | urlpatterns = [ 40 | path('', views.index, name='index'), 41 | ] 42 | ``` 43 | 44 | ### 修改根URLconf 45 | 打开 mysite/urls.py,插入一个include(): 46 | ``` 47 | from django.contrib import admin 48 | from django.urls import path 49 | from django.conf.urls import include 50 | 51 | urlpatterns = [ 52 | path('polls/', include('polls.urls')), 53 | path('admin/', admin.site.urls), 54 | ] 55 | ``` 56 | 57 | ### 运行应用 58 | $ python manage.py runserver 59 | 60 | http://localhost:8000/polls/ 61 | 62 | 浏览器返回:Hello Polls 63 | 64 | 好了,我们完成了第一个应用创建和请求与响应。 65 | 66 | 配图来自Twitter:@DSmile9 67 | 68 | ![配图26](https://wiki.huihoo.com/images/3/30/Devopsgirls26.png) 69 | -------------------------------------------------------------------------------- /courses/python27.md: -------------------------------------------------------------------------------- 1 | # 第27课:入门 - 模型和管理后台(二) 2 | 3 | 涉及到模型,就要使用到数据库。 4 | 5 | ### 配置数据库 6 | 打开 mysite/settings.py 7 | 8 | 先创建数据库:mysite 9 | ``` 10 | DATABASES = { 11 | 'default': { 12 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 13 | 'NAME': 'mysite', 14 | 'USER': 'postgres', 15 | 'PASSWORD': 'postgres', 16 | 'HOST': 'localhost', 17 | 'PORT': '5432', 18 | } 19 | } 20 | ``` 21 | $ python manage.py migrate 22 | ``` 23 | Operations to perform: 24 | Apply all migrations: admin, auth, contenttypes, sessions 25 | Running migrations: 26 | Applying contenttypes.0001_initial... OK 27 | Applying auth.0001_initial... OK 28 | Applying admin.0001_initial... OK 29 | Applying admin.0002_logentry_remove_auto_add... OK 30 | Applying admin.0003_logentry_add_action_flag_choices... OK 31 | Applying contenttypes.0002_remove_content_type_name... OK 32 | Applying auth.0002_alter_permission_name_max_length... OK 33 | Applying auth.0003_alter_user_email_max_length... OK 34 | Applying auth.0004_alter_user_username_opts... OK 35 | Applying auth.0005_alter_user_last_login_null... OK 36 | Applying auth.0006_require_contenttypes_0002... OK 37 | Applying auth.0007_alter_validators_add_error_messages... OK 38 | Applying auth.0008_alter_user_username_max_length... OK 39 | Applying auth.0009_alter_user_last_name_max_length... OK 40 | Applying sessions.0001_initial... OK 41 | ``` 42 | 43 | 默认启用以下应用并创建相关数据库表,这些应用给常规项目提供方便: 44 | 45 | * django.contrib.admin -- 管理员站点, 你很快就会使用它。 46 | * django.contrib.auth -- 认证授权系统。 47 | * django.contrib.contenttypes -- 内容类型框架。 48 | * django.contrib.sessions -- 会话框架。 49 | * django.contrib.messages -- 消息框架。 50 | * django.contrib.staticfiles -- 管理静态文件的框架。 51 | 52 | ### 创建模型 53 | 定义模型也就是数据库结构设计,数据库和表会从从模型自动生成。Django的迁移代码是由你的模型文件自动生成,它本质上是个历史记录,Django可以用它来进行数据库的滚动更新,通过这种方式使其能够和当前的模型匹配。 54 | 55 | 编辑 polls/models.py 56 | ``` 57 | from django.db import models 58 | 59 | class Question(models.Model): 60 | question_text = models.CharField(max_length=200) 61 | pub_date = models.DateTimeField('date published') 62 | 63 | class Choice(models.Model): 64 | question = models.ForeignKey(Question, on_delete=models.CASCADE) 65 | choice_text = models.CharField(max_length=200) 66 | votes = models.IntegerField(default=0) 67 | ``` 68 | 新增Question和Choice两个模型,每个模型被表示为 django.db.models.Model 类的子类。每个模型有一些类变量,它们都表示模型里的一个数据库字段。 69 | 70 | 使用 ForeignKey 定义了一个关系,每个 Choice 对象都关联到一个 Question 对象。 71 | 72 | 73 | ### 激活模型 74 | 修改 mysite/settings.py,增加polls.apps.PollsConfig 75 | ``` 76 | INSTALLED_APPS = [ 77 | 'polls.apps.PollsConfig', 78 | ... 79 | ] 80 | ``` 81 | $ python manage.py makemigrations polls 82 | ``` 83 | Migrations for 'polls': 84 | polls/migrations/0001_initial.py 85 | - Create model Choice 86 | - Create model Question 87 | - Add field question to choice 88 | ``` 89 | 然后执行migrate自动执行数据库迁移并同步管理你的数据库结构。 90 | 91 | $ python manage.py sqlmigrate polls 0001 92 | ``` 93 | BEGIN; 94 | -- 95 | -- Create model Choice 96 | -- 97 | CREATE TABLE "polls_choice" ("id" serial NOT NULL PRIMARY KEY, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL); 98 | -- 99 | -- Create model Question 100 | -- 101 | CREATE TABLE "polls_question" ("id" serial NOT NULL PRIMARY KEY, "question_text" varchar(200) NOT NULL, "pub_date" timestamp with time zone NOT NULL); 102 | -- 103 | -- Add field question to choice 104 | -- 105 | ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL; 106 | CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id"); 107 | ALTER TABLE "polls_choice" ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id" FOREIGN KEY ("question_id") REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED; 108 | COMMIT; 109 | ``` 110 | 最后,再次运行 migrate 命令,在数据库里创建新定义的模型的数据表,这时就新建了这两张表。 111 | 112 | $ python manage.py migrate 113 | ``` 114 | Operations to perform: 115 | Apply all migrations: admin, auth, contenttypes, polls, sessions 116 | Running migrations: 117 | Applying polls.0001_initial... OK 118 | ``` 119 | 所以,改变模型需要这三步: 120 | * 编辑 models.py 文件,改变模型。 121 | * 运行 python manage.py makemigrations 为模型的改变生成迁移文件。 122 | * 运行 python manage.py migrate 来应用数据库迁移。 123 | 124 | ### Django管理后台 125 | Django会根据模型自动地创建后台界面。 126 | 127 | 创建一个管理员账号: 128 | ``` 129 | $ python manage.py createsuperuser 130 | $ python manage.py runserver 131 | http://127.0.0.1:8000/admin/ 132 | admin/adminadmin 133 | ``` 134 | 135 | ### 将polls应用加入管理 136 | 编辑 polls/admin.py 137 | ``` 138 | from django.contrib import admin 139 | from .models import Question 140 | 141 | admin.site.register(Question) 142 | ``` 143 | 以后其它应用加入管理也采用类似方法,这样就可以在后台统一管理这些应用了。 144 | 145 | 配图来自Twitter:@atikix 146 | 147 | ![配图27](https://wiki.huihoo.com/images/8/82/Devopsgirls27.jpg) 148 | -------------------------------------------------------------------------------- /courses/python28.md: -------------------------------------------------------------------------------- 1 | # 第28课:入门 - 视图和模板(三) 2 | 3 | ### 视图 4 | Django 中的视图的概念是一类具有相同功能和模板的网页的集合,如大家熟悉的博客会包含以下视图: 5 | * 博客首页:展示最近的几条博客 6 | * 详情页 7 | * 评论 8 | * 归档页:以年、月、日为单位的归档博客 9 | 10 | 在我们的投票(Polls)应用中,需要以下视图: 11 | * 问题索引页:显示最近的几个投票问题。 12 | * 问题详情页:显示某个投票的问题和不带结果的选项列表。 13 | * 问题结果页:显示某个投票的结果。 14 | * 投票处理器:用于响应用户为某个问题的特定选项投票的操作。 15 | 16 | 为了将 URL 和视图关联起来,Django 使用了 'URLconfs' 来配置,URLconf 将 URL模式(urlpatterns)映射到视图。 17 | 18 | 现在我们往 polls/views.py 里添加以下新视图: 19 | ``` 20 | def detail(request, question_id): 21 | return HttpResponse("你看到的问题是 %s." % question_id) 22 | 23 | def results(request, question_id): 24 | response = "你看到的问题结果是 %s." 25 | return HttpResponse(response % question_id) 26 | 27 | def vote(request, question_id): 28 | return HttpResponse("你在此问题上的投票 %s." % question_id) 29 | ``` 30 | 31 | 编辑 polls/urls.py,添加几个 url() 函数调用: 32 | ``` 33 | from django.urls import path 34 | 35 | from . import views 36 | 37 | urlpatterns = [ 38 | # ex: /polls/ 39 | path('', views.index, name='index'), 40 | # ex: /polls/5/ 41 | path('/', views.detail, name='detail'), 42 | # ex: /polls/5/results/ 43 | path('/results/', views.results, name='results'), 44 | # ex: /polls/5/vote/ 45 | path('/vote/', views.vote, name='vote'), 46 | ] 47 | ``` 48 | 49 | ### 模版 50 | 使用模版,我们可以不用把页面的设计写死在视图函数的代码里,而是将页面的设计从代码中分离出来,方便今后的维护。 51 | 52 | 我们创建 polls/templates/polls 目录,然后创建 index.html,因为这样 Django 能找到对应的 app_directories,这样使用 polls/index.html 就可以引用此模版了,把模版放到各自的命名空间下是个好习惯。 53 | 54 | 编辑 polls/templates/polls/index.html 55 | ``` 56 | {% if latest_question_list %} 57 | 62 | {% else %} 63 |

没有投票

64 | {% endif %} 65 | ``` 66 | 更新一下 polls/views.py 里的 index 视图来使用此模板,使用 render() 重写 index() 视图,而不是使用HttpResponse() : 67 | ``` 68 | from django.http import HttpResponse 69 | from django.shortcuts import render 70 | from .models import Question 71 | 72 | def index(request): 73 | latest_question_list = Question.objects.order_by('-pub_date')[:5] 74 | context = {'latest_question_list': latest_question_list} 75 | return render(request, 'polls/index.html', context) 76 | ``` 77 | 78 | $ python manage.py runserver 79 | 80 | 打开 http://localhost:8000/admin/ 添加几个问题: 81 | * 问题一 82 | * 问题二 83 | * 问题三 84 | 85 | 再打开 http://localhost:8000/polls/ 你应该可以看见刚创建的三个问题 :) 86 | 87 | 这样,我们就初步学习了视图创建和模版使用的基础知识了。 88 | 89 | 配图来自Twitter:@atikix 90 | 91 | ![配图28](https://wiki.huihoo.com/images/3/30/Devopsgirls28.jpg) 92 | -------------------------------------------------------------------------------- /courses/python29.md: -------------------------------------------------------------------------------- 1 | # 第29课:入门 - 表单和通用视图(四) 2 | 3 | ### 一个简单的表单 4 | 编写 polls/templates/polls/detail.html,包含一个 HTML `
` 元素: 5 | 6 | 在 Question 的每个 Choice 前添加一个单选按钮 7 | ``` 8 |

{{ question.question_text }}

9 | 10 | {% if error_message %}

{{ error_message }}

{% endif %} 11 | 12 | 13 | {% csrf_token %} 14 | {% for choice in question.choice_set.all %} 15 | 16 |
17 | {% endfor %} 18 | 19 |
20 | ``` 21 | 编辑 polls/views.py,添加以下代码: 22 | ``` 23 | from django.http import HttpResponse, HttpResponseRedirect 24 | from django.shortcuts import get_object_or_404, render 25 | from django.urls import reverse 26 | from .models import Choice, Question 27 | 28 | def vote(request, question_id): 29 | question = get_object_or_404(Question, pk=question_id) 30 | try: 31 | selected_choice = question.choice_set.get(pk=request.POST['choice']) 32 | except (KeyError, Choice.DoesNotExist): 33 | return render(request, 'polls/detail.html', { 34 | 'question': question, 35 | 'error_message': "你没有选择", 36 | }) 37 | else: 38 | selected_choice.votes += 1 39 | selected_choice.save() 40 | return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) 41 | ``` 42 | 43 | 编写 polls/views.py,把 results 修改下: 44 | ``` 45 | def results(request, question_id): 46 | question = get_object_or_404(Question, pk=question_id) 47 | return render(request, 'polls/results.html', {'question': question}) 48 | ``` 49 | 50 | 好了,现在创建 polls/templates/polls/results.html 模版文件,包含以下内容: 51 | 52 | ``` 53 |

{{ question.question_text }}

54 | 55 |
    56 | {% for choice in question.choice_set.all %} 57 |
  • {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
  • 58 | {% endfor %} 59 |
60 | 61 | 重新投票? 62 | ``` 63 | 64 | ### 使用通用视图 65 | 使用通用视图系统,这样我们可以删除许多多余的代码。其实,这是代码重构的过程。 66 | 67 | 先修改 polls/urls.py,把 `` 改为 ``: 68 | ``` 69 | from django.urls import path 70 | 71 | from . import views 72 | 73 | app_name = 'polls' 74 | urlpatterns = [ 75 | path('', views.IndexView.as_view(), name='index'), 76 | path('/', views.DetailView.as_view(), name='detail'), 77 | path('/results/', views.ResultsView.as_view(), name='results'), 78 | path('/vote/', views.vote, name='vote'), 79 | ] 80 | ``` 81 | 82 | 再修改 polls/views.py,删除旧的 index, detail, 和 results 视图,并用通用视图代替: 83 | 84 | 两个通用视图: ListView 和 DetailView,vote不变保持原样: 85 | ``` 86 | from django.http import HttpResponseRedirect 87 | from django.shortcuts import get_object_or_404, render 88 | from django.urls import reverse 89 | from django.views import generic 90 | from .models import Choice, Question 91 | 92 | class IndexView(generic.ListView): 93 | template_name = 'polls/index.html' 94 | context_object_name = 'latest_question_list' 95 | 96 | def get_queryset(self): 97 | """Return the last five published questions.""" 98 | return Question.objects.order_by('-pub_date')[:5] 99 | 100 | class DetailView(generic.DetailView): 101 | model = Question 102 | template_name = 'polls/detail.html' 103 | 104 | 105 | class ResultsView(generic.DetailView): 106 | model = Question 107 | template_name = 'polls/results.html' 108 | 109 | def vote ...保持不变... 110 | ``` 111 | 112 | 现在使用新的应用 $ python manage.py runserver 113 | 114 | 配图来自Twitter:@atikix 115 | 116 | ![配图29](https://wiki.huihoo.com/images/7/76/Devopsgirls29.jpg) 117 | -------------------------------------------------------------------------------- /courses/python30.md: -------------------------------------------------------------------------------- 1 | # 第30课:入门 - 完善管理后台(五) 2 | 3 | ### 增加选项 4 | 在之前的课程中,我们通过管理后台创建了三个问题,但它们都还没有选项,现在我们就把这些选项添加上。 5 | 6 | 通过 admin.site.register(Question) 注册 Question 模型,Django 能够构建一个默认的表单用于展示。 7 | 8 | 编辑 polls/admin.py,提供3个选项(Choice)字段: 9 | ``` 10 | from django.contrib import admin 11 | from .models import Choice, Question 12 | 13 | class ChoiceInline(admin.TabularInline): 14 | model = Choice 15 | extra = 3 16 | 17 | class QuestionAdmin(admin.ModelAdmin): 18 | fieldsets = [ 19 | (None, {'fields': ['question_text']}), 20 | ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), 21 | ] 22 | inlines = [ChoiceInline] 23 | 24 | admin.site.register(Question, QuestionAdmin) 25 | ``` 26 | 27 | 编辑 mysite/settings.py,将 templates 加入 DIRS 选项会带来更多便利。 28 | ``` 29 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 30 | ``` 31 | 32 | 运行下:$ python manage.py runserver 33 | 34 | 通过管理后台:http://localhost:8000/admin 创建三个问题的选项,每个问题可有三个选项: 35 | 36 | 可以这样创建: 37 | ``` 38 | 问题一: 39 | 1A 40 | 1B 41 | 1C 42 | 问题二: 43 | 2A 44 | 2B 45 | 2C 46 | 问题三: 47 | 3A 48 | 3B 49 | 3C 50 | ``` 51 | ![image30](images/class30-01.png) 52 | 53 | 好了,问题和每个问题的选项都创建好了,现在通过 http://localhost:8000/polls/ 去给每个问题的选项投票。 54 | 55 | ![image30](images/class30-02.png) 56 | 57 | 这个例子算是比较完整的跑起来了,管理后台可调整和完善的地方还有很多,你可以一点点去试试。 58 | 59 | 配图来自Twitter:@atikix 60 | 61 | ![配图30](https://wiki.huihoo.com/images/thumb/6/6c/Devopsgirls30.jpg/701px-Devopsgirls30.jpg) 62 | -------------------------------------------------------------------------------- /courses/python31.md: -------------------------------------------------------------------------------- 1 | # 第31课:入门 - 样式风格(六) 2 | 3 | 一个 Web 应用除了动态语言外,还有图片、样式表等所谓的静态文件,django.contrib.staticfiles 就是干这事的。它将各个应用的静态文件统一收集起来,这样一来,在生产环境中,就会有一个集中便于分发的地方。 4 | 5 | ### 加个样式表 6 | 创建 polls/static/polls/style.css,并添加: 7 | ``` 8 | li a { 9 | color: green; 10 | } 11 | ``` 12 | 然后,在 polls/templates/polls/index.html 的文件中添加以下内容: 13 | ``` 14 | {% load static %} 15 | 16 | 17 | ``` 18 | 19 | ### 加个背景 20 | 将图片放在 polls/static/polls/images/ 目录下, 21 | 22 | 然后在样式表 polls/static/polls/style.css 中添加: 23 | ``` 24 | body { 25 | background: white url("images/background.jpg") no-repeat; 26 | } 27 | ``` 28 | 好了,看下效果。 http://localhost:8000/polls/ 29 | 30 | ![class31](images/class31.png) 31 | 32 | 有背景了,问题的链接变绿了 :) 33 | 34 | 有关样式表的内容比较多,这块你就自己展开学习了。 35 | 36 | 配图来自Twitter:@atikix 37 | 38 | ![配图31](https://wiki.huihoo.com/images/4/40/Devopsgirls31.jpg) 39 | -------------------------------------------------------------------------------- /courses/python32.md: -------------------------------------------------------------------------------- 1 | # 第32课:入门 - 测试(七) 2 | 3 | 先回顾下前面两节测试课程: 4 | * [第21课:测试(Testing)(一)](python21.md) 5 | * [第22课:测试(Testing)(二)](python22.md) 6 | 7 | 在这里,我们将对投票应用进行测试。 8 | 9 | 配图来自Twitter:@atikix 10 | 11 | ![配图32](https://wiki.huihoo.com/images/8/8e/Devopsgirls32.jpg) 12 | -------------------------------------------------------------------------------- /courses/python33.md: -------------------------------------------------------------------------------- 1 | # 第33课:模型(一) 2 | 3 | ### 模型定义 4 | 一般来说,每一个模型都映射一个数据库表。 5 | * 每个模型都是一个 Python 类,这些类继承 django.db.models.Model 6 | * 模型类的每个属性都相当于一个数据库的字段 7 | * Django 自动生成访问数据库的 API 8 | 9 | ### 创建模型 10 | 为了方便,我们直接使用之前创建的polls应用。 11 | 12 | 定义了一个 Person 模型, 包含 first_name 和 last_name,将以下内容加入 mysite/polls/models.py: 13 | ``` 14 | class Person(models.Model): 15 | first_name = models.CharField(max_length=30) 16 | last_name = models.CharField(max_length=30) 17 | ``` 18 | 1、运行:$ python manage.py makemigrations polls 19 | ``` 20 | Migrations for 'polls': 21 | polls/migrations/0002_person.py 22 | - Create model Person 23 | ``` 24 | 2、检查:$ python manage.py sqlmigrate polls 0002 25 | 26 | 3、迁移:$ python manage.py migrate 27 | 28 | 这时,这个模型会自动在数据库中生成一张新表: 29 | ``` 30 | CREATE TABLE polls_person ( 31 | "id" serial NOT NULL PRIMARY KEY, 32 | "first_name" varchar(30) NOT NULL, 33 | "last_name" varchar(30) NOT NULL 34 | ); 35 | ``` 36 | 37 | ### 初始化数据 38 | 数据库表创建好后,可通过 python manage.py loaddata `` 的方式初始化数据库,数据文件格式可以是 JSON 或 YAML。 39 | 40 | 创建 polls-person.json 文件: 41 | ``` 42 | [ 43 | { 44 | "model": "polls.person", 45 | "pk": 1, 46 | "fields": { 47 | "first_name": "Allen", 48 | "last_name": "Long" 49 | } 50 | }, 51 | { 52 | "model": "polls.person", 53 | "pk": 2, 54 | "fields": { 55 | "first_name": "Peter", 56 | "last_name": "Chen" 57 | } 58 | } 59 | ] 60 | ``` 61 | 运行 $ python manage.py loaddata polls-person.json 62 | 63 | Installed 2 object(s) from 1 fixture(s) 64 | 65 | 这时 polls_person 新建了两条记录,你可以通过这种方式初始化数据库,或把其它系统的数据导出再导入新系统。 66 | 67 | ![class33-01](images/class33-01.png) 68 | 69 | ### 使用模型 70 | 你可以通过以下的方式使用模型(数据库表),进行增删改查等操作。 71 | ``` 72 | >>> import psycopg2 73 | >>> conn = psycopg2.connect("dbname=mysite user=postgres password=postgres") 74 | >>> cur = conn.cursor() 75 | >>> cur.execute("SELECT * FROM polls_person;") 76 | >>> cur.fetchall() 77 | [(1, 'Allen', 'Long'), (2, 'Peter', 'Chen')] 78 | ``` 79 | 80 | $ python manage.py shell 81 | ``` 82 | >>> from polls.models import Person 83 | >>> Person.objects.count() 84 | 2 85 | >>> Person.objects.all() 86 | , ]> 87 | ``` 88 | 89 | 配图来自Twitter:@kagachi_SK 90 | 91 | ![配图33](https://wiki.huihoo.com/images/f/f0/Devopsgirls33.jpg) 92 | -------------------------------------------------------------------------------- /courses/python34.md: -------------------------------------------------------------------------------- 1 | # 第34课:模型(二) 2 | 3 | ### 管理员 4 | Manager是为Django模型提供的数据库查询接口,Django应用中的每个模型都至少存在一个Manager。 5 | 6 | $ python manage.py shell 7 | ``` 8 | >>> from polls.models import Person 9 | >>> Person.objects 10 | 11 | >>> Person.objects.all() 12 | , ]> 13 | ``` 14 | 我们使用Person模型上的Manager构造QuerySet从数据库检索对象。 15 | 16 | ### 数据库事务 17 | 事务是指具有原子性的一系列数据库操作。即使是程序崩溃,数据库也会确保这些操作要么全部完成(commit)要么全部都未执行(rollback)。 18 | 19 | Django 默认的事务行为是自动提交。 20 | 21 | 工作原理:将每个HTTP请求封装在一个事务中,配置中的参数 ATOMIC_REQUESTS 设置为 True(默认为 False)。在调用试图方法前,Django 先生成一个事务。如果响应能正常生成,Django 会提交该事务。而如果视图出现异常,Django 则会回滚该事务。 22 | 23 | 你还可以在视图代码中执行子事务,会使用 atomic。 24 | 25 | 先了解这些概念,以后再深入这块。 26 | 27 | ### 迁移 28 | Web应用的开发就是一个持续的过程,其数据库表结构也处于不断增删改的迭代过程中,一套完整的数据库维护机制显得非常重要,Django 为此提供了数据库迁移功能很好的应对这项工作。 29 | 30 | 主要的命令有: 31 | ``` 32 | $ python manage.py makemigrations polls # 生成迁移文件,如:0001_initial.py 33 | $ python manage.py sqlmigrate polls 0001 # 生成SQL,可看看是不是自己想要的结果 34 | $ python manage.py migrate # 执行迁移,完成创建新表等任务 35 | ``` 36 | 37 | ### 数据库函数 38 | Django提供了以下几类数据库函数: 39 | * 比较和转换函数:如Cast、Coalesce、Greatest、Least 40 | * 日期函数:如Now ... 41 | * 文本函数:如Length、Lower、Upper ... 42 | * Window函数:如Rank ... 43 | 44 | ``` 45 | >>> from datetime import datetime 46 | >>> dt = datetime(2019, 2, 10) 47 | >>> (dt.isoweekday() % 7) + 1 48 | 1 49 | ``` 50 | 1 for Sunday, 2 for Monday, through 7 for Saturday. 51 | 52 | 配图来自Twitter:@kagachi_SK 53 | 54 | ![配图34](https://wiki.huihoo.com/images/c/cf/Devopsgirls34.jpg) 55 | -------------------------------------------------------------------------------- /courses/python35.md: -------------------------------------------------------------------------------- 1 | # 第35课:视图(一) 2 | 视图简单讲就是负责处理用户的请求并返回响应。 3 | 4 | ### 一个简单视图 5 | ``` 6 | from django.http import HttpResponse 7 | import datetime 8 | 9 | def current_datetime(request): 10 | now = datetime.datetime.now() 11 | html = "It is now %s." % now 12 | return HttpResponse(html) 13 | ``` 14 | 15 | ### 优雅URL 16 | 回顾一下我们之前在 [polls](python28.md) 应用的URL设计。 17 | 18 | ### 装饰器(decorators 19 | Django 提供了多个可以应用于视图的装饰器,以支持各种HTTP功能,使用 @ 标识符。 20 | 21 | ``` 22 | from django.contrib.auth.decorators import login_required 23 | 24 | @login_required(login_url='/accounts/login/') 25 | def my_view(request): 26 | ... 27 | ``` 28 | 每次用户试图访问 my_view 时,都会检查用户是否通过身份验证,并将未登录用户重定向到login_url。 29 | 30 | ### 快捷函数 31 | 包 django.shortcuts 收集了“跨越” 多层MVC 的辅助函数和类。 换句话讲,这些函数/类为了方便,引入了可控的耦合。 32 | 33 | * render() 34 | * render_to_response() 35 | * redirect() 36 | * get_object_or_404() 37 | * get_list_or_404() 38 | 39 | 我们常用 render() 替换 HttpResponse() 40 | ``` 41 | from django.shortcuts import render 42 | 43 | def my_view(request): 44 | # View code here... 45 | return render(request, 'myapp/index.html', { 46 | 'foo': 'bar', 47 | }, content_type='application/xhtml+xml') 48 | ``` 49 | 相当于: 50 | ``` 51 | from django.http import HttpResponse 52 | from django.template import loader 53 | 54 | def my_view(request): 55 | # View code here... 56 | t = loader.get_template('myapp/index.html') 57 | c = {'foo': 'bar'} 58 | return HttpResponse(t.render(c, request), content_type='application/xhtml+xml') 59 | ``` 60 | 61 | ### 内置视图 62 | Django 提供了内置视图,如 error 视图: 63 | * 404 (page not found) 64 | defaults.page_not_found(request, exception, template_name='404.html') 65 | * 500 (server error) 66 | defaults.server_error(request, template_name='500.html') 67 | * 403 (HTTP Forbidden) 68 | defaults.permission_denied(request, exception, template_name='403.html') 69 | * 400 (bad request) 70 | defaults.bad_request(request, exception, template_name='400.html') 71 | 72 | ![404](images/class35-01.png) 73 | 74 | 配图来自Twitter:@chengr28 75 | 76 | ![配图35](https://wiki.huihoo.com/images/4/46/Devopsgirls35.jpg) 77 | -------------------------------------------------------------------------------- /courses/python36.md: -------------------------------------------------------------------------------- 1 | # 第36课:视图(二) 2 | 3 | 这里我们介绍基于类的视图。 4 | 5 | ### 基于类的视图(Class-based views) 6 | 视图不仅仅只有函数(def),而可以是类(class) 7 | 8 | 基于类的视图提供了另一种将视图实现为Python对象而不是函数的方法。 9 | 10 | Django 也提供了一些可用作视图的类的示例,允许你通过继承和复用构建自己的视图并且复用这些代码。 11 | 12 | 将一个函数定义的视图转换成基于类的视图: 13 | 14 | 函数定义的视图 15 | ``` 16 | from django.http import HttpResponse 17 | 18 | def my_view(request): 19 | if request.method == 'GET': 20 | # 21 | return HttpResponse('result') 22 | ``` 23 | 转换成 -> 基于类的视图: 24 | ``` 25 | from django.http import HttpResponse 26 | from django.views import View 27 | 28 | class MyView(View): 29 | def get(self, request): 30 | # 31 | return HttpResponse('result') 32 | ``` 33 | 34 | ### 内置基于类的视图 35 | 大致的一个划分: 36 | * Base views 37 | * Generic display views 38 | * Generic editing views 39 | * Generic date views 40 | * Class-based views mixins 41 | * Class-based generic views 42 | 43 | 配图来自Twitter:@chengr28 44 | 45 | ![配图36](https://wiki.huihoo.com/images/c/c2/Devopsgirls36.jpg) 46 | -------------------------------------------------------------------------------- /courses/python37.md: -------------------------------------------------------------------------------- 1 | # 第37课:模板(一) 2 | 模板提供了一个对设计师友好的语法用于渲染向用户呈现的信息,这里涉及如何使用语法以及如何扩展的内容。 3 | 4 | Django 项目可以配置一个或多个模板引擎,Django后端内置一个自己的模板系统:Django template language(DTL) `` 。当然,也可以使用第三方模版引擎,如:jinja2 5 | 6 | Django 定义了一个标准的API,用于加载和渲染模板,而不用考虑后端的模板系统。加载包括查找给定标识符的模板并对其进行预处理,通常将其编译的结果保存在内存中。渲染工具将上下文数据插入模板并返回结果字符串。 7 | 8 | ### 概念 9 | * Engine 10 | django.template.Engine 封装了 Django 模板系统的一个实例,实例化引擎的主要原因是在 Django 项目之外直接使用 Django 模板语言。 11 | 12 | django.template.backends.django.DjangoTemplates 是一个包装器(wrapper),它将 django.template.Engine 适配成 Django 的模板后端API。 13 | * Template 14 | django.template.Template 是已编译的模板,使用 Engine.get_template() 或 Engine.from_string() 获取模板 15 | 16 | 同样,django.template.backends.django.Template 是一个包装器(wrapper),它将 django.template.Template 适配成公共模板API。 17 | 18 | * Context 19 | 除了上下文数据外,django.template.Context 还包含一些元数据(metadata), 它被传递给 Template.render() 用于渲染模板。 20 | 21 | django.template.RequestContext 是 Context 的子类,它存储当前 HttpRequest 并运行模板上下文处理器(template context processors)。 22 | 23 | * Loaders 24 | 模板加载器负责定位模板,加载模板和返回模板对象。Django 提供了几个内置模板加载器并支持自定义模板加载器。 25 | 26 | * Context processors 27 | 上下文处理器是接收当前 HttpRequest 作为参数的函数,并返回一个添加数据到渲染上下文的字典。它们的主要用途是将所有模板共享的公共数据添加到上下文中,而不用在每个视图中重复代码。 28 | 29 | Django 提供了许多内置的上下文处理器,实现自定义上下文处理器就像定义函数一样简单。 30 | 31 | ### 配置 32 | mysite/settings.py 33 | ``` 34 | TEMPLATES = [ 35 | { 36 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 37 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 38 | 'APP_DIRS': True, 39 | 'OPTIONS': { 40 | 'context_processors': [ 41 | 'django.template.context_processors.debug', 42 | 'django.template.context_processors.request', 43 | 'django.contrib.auth.context_processors.auth', 44 | 'django.contrib.messages.context_processors.messages', 45 | ], 46 | }, 47 | }, 48 | ] 49 | ``` 50 | 也可多配置一个模版系统,如:jinja2 51 | ``` 52 | { 53 | 'BACKEND': 'django.template.backends.jinja2.Jinja2', 54 | 'DIRS': [ 55 | '/home/html/jinja2', 56 | ], 57 | }, 58 | ``` 59 | ### 简单使用 60 | 为了减少加载和渲染模板的重复性,Django 提供了一个自动处理的快捷函数:render_to_string() 61 | ``` 62 | from django.template.loader import render_to_string 63 | rendered = render_to_string('my_template.html', {'foo': 'bar'}) 64 | ``` 65 | 66 | 此外,你可以在 Django 项目之外直接使用配置好的模版引擎: 67 | ``` 68 | from django.template import engines 69 | 70 | django_engine = engines['django'] 71 | template = django_engine.from_string("Hello {{ name }}!") 72 | ``` 73 | 74 | 配图来自Twitter:@chengr28 75 | 76 | ![配图37](https://wiki.huihoo.com/images/thumb/3/3f/Devopsgirls37.jpg/684px-Devopsgirls37.jpg) 77 | -------------------------------------------------------------------------------- /courses/python38.md: -------------------------------------------------------------------------------- 1 | # 第38课:模板(二) 2 | 3 | ### Django template language(DTL) 4 | 了解一些基本语法,这些标签和过滤器可以是内置的,也可以自定义的: 5 | * 变量(variable):{{ and }} 6 | 7 | My first name is {{ first_name }}. My last name is {{ last_name }}. 8 | 9 | * 标签(Tags):{% and %} 10 | 11 | {% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %} 12 | 13 | * 过滤器(Filters):{{ | }} 14 | 15 | {{ django|title }} 16 | 17 | * 注释(Comments):{# and #} 18 | 19 | {# this won't be rendered #} 20 | 21 | ### 自定义标签 22 | 注册自定义标签:django.template.Library.simple_tag() 23 | ``` 24 | import datetime 25 | from django import template 26 | register = template.Library() 27 | @register.simple_tag 28 | def current_time(format_string): 29 | return datetime.datetime.now().strftime(format_string) 30 | ``` 31 | 32 | ### 自定义过滤器 33 | 自定义的过滤器就是一些有一到两个参数的Python函数,如: 34 | 35 | 在过滤器``{{ var|foo:"bar" }}``中,变量``var``和参数``bar``会传递给过滤器``foo`` 36 | 37 | 注册自定义过滤器:django.template.Library.filter() 38 | ``` 39 | >>> from django import template 40 | >>> register = template.Library() 41 | >>> @register.filter 42 | ... def lower(value): 43 | ... return value.lower() 44 | ``` 45 | 46 | 配图来自Twitter:@chengr28 47 | 48 | ![配图38](https://wiki.huihoo.com/images/thumb/b/b7/Devopsgirls38.jpg/727px-Devopsgirls38.jpg) 49 | -------------------------------------------------------------------------------- /courses/python39.md: -------------------------------------------------------------------------------- 1 | # 第39课:表单(一) 2 | 3 | ### 表单 4 | 若你的网站需要接收访问者的输入,就需要理解和使用表单。 5 | 6 | 创建 Form 类时,最重要的是定义表单的字段,以及每个字段的验证逻辑。 7 | 8 | Django 提供了一系列的工具和库来帮助您构建表单来接收网站访客的输入,然后处理以及响应这些输入。 9 | 10 | ### 内置字段 11 | 这是一个完整的示例 Form,它为两个字段实现标签,并指定了 auto_id = False 来简化输出: 12 | ``` 13 | >>> from django import forms 14 | >>> class CommentForm(forms.Form): 15 | ... name = forms.CharField(initial='Allen') 16 | ... url = forms.URLField(initial='https://huihoo.com') 17 | ... comment = forms.CharField() 18 | ... 19 | >>> f = CommentForm(auto_id=False) 20 | >>> print(f) 21 | Name: 22 | Url: 23 | Comment: 24 | ``` 25 | 26 | ### 内置widgets 27 | widget 是 Django 对 HTML 输入元素的表示,widget 处理 HTML 的渲染,以及从与 widget 对应的 GET/POST 字典中提取数据。 28 | 29 | 一个简单的 widget:Textarea 30 | ... 31 | from django import forms 32 | 33 | class CommentForm(forms.Form): 34 | name = forms.CharField() 35 | url = forms.URLField() 36 | comment = forms.CharField(widget=forms.Textarea) 37 | ... 38 | 39 | 配图来自Twitter:@chengr28 40 | 41 | ![配图39](https://wiki.huihoo.com/images/thumb/9/9c/Devopsgirls39.jpg/798px-Devopsgirls39.jpg) -------------------------------------------------------------------------------- /courses/python40.md: -------------------------------------------------------------------------------- 1 | # 第40课:表单(二) 2 | 3 | ### 模型表单 4 | 模型中定义了字段,表单中就不需要再定义字段类型了。每个模型字段都有一个对应的默认表单字段。 5 | 6 | Django 提供了一个辅助类让你可以从一个 Django 模型创建一个 Form 类。 7 | ``` 8 | >>> from django.forms import ModelForm 9 | >>> from polls.models import Person 10 | >>> class PersonForm(ModelForm): 11 | ... class Meta: 12 | ... model = Person 13 | ... fields = ['first_name', 'last_name'] 14 | ... 15 | >>> form = PersonForm('Jeff', 'Zhang') 16 | ``` 17 | 思考下,如何把这条记录写入(save)数据库中。 18 | 19 | ### 表单集 20 | formset是一个抽象层,它可以在同一页面上处理多个表单。 21 | 22 | 如一次创建多个Person,需要创建 PersonForm 的 formset,方法如下: 23 | ``` 24 | >>> from django.forms import formset_factory 25 | >>> PersonFormSet = formset_factory(PersonForm) 26 | >>> formset = PersonFormSet() 27 | >>> for form in formset: 28 | ... print(form.as_table()) 29 | ... 30 | 31 | 32 | ``` 33 | ### 字段验证 34 | Django 表单(和模型)字段支持使用简单的实用函数和称为验证器的类。验证器只是一个可调用的对象或函数,它接受一个值,如果值有效则返回任何内容,否则引发 ValidationError。 35 | 36 | 这些可以通过字段的验证器参数传递给字段的构造函数,或者使用 default_validators 属性定义在 Field 类上。 37 | 38 | SlugField 是一个带有自定义验证器的 CharField,用于验证提交的文本是否符合某些字符规则。 39 | ``` 40 | >>> from django.core import validators 41 | >>> from django.forms import CharField 42 | >>> 43 | >>> class SlugField(CharField): 44 | ... default_validators = [validators.validate_slug] 45 | ... 46 | >>> slug = forms.SlugField() 47 | ``` 48 | 49 | 配图来自Twitter:@chengr28 50 | 51 | ![配图40](https://wiki.huihoo.com/images/thumb/1/16/Devopsgirls40.jpg/768px-Devopsgirls40.jpg) 52 | 53 | -------------------------------------------------------------------------------- /courses/python41.md: -------------------------------------------------------------------------------- 1 | # 第41课:认证 2 | 3 | ### 认证中间件 4 | AuthenticationMiddleware 5 | 6 | ### 用户认证 7 | Django 带有用户身份验证系统,包含用户账号、用户组、权限和基于cookie的用户管理。 8 | 9 | ![class41-01](images/class41-01.png) 10 | 11 | 默认用户的主要属性有: 12 | * username 13 | * password 14 | * email 15 | * first_name 16 | * last_name 17 | ![class41-03](images/class41-03.png) 18 | 19 | ![class41-02](images/class41-02.png) 20 | 21 | ### 第三方验证 22 | 支持微博、微信、Twitter、Facebook 等第三方身份验证和账户登录。 23 | 24 | ### 自定义扩展Django验证 25 | Django 自带的验证机制足以应对一般情况,但用户总会有自己的特殊需求,这时就需要自定义和扩展验证机制,你需要了解在已有验证系统中哪些地方是可以扩展的,哪些地方是可以代替的。 26 | 27 | 28 | 配图来自Twitter:@chengr28 29 | 30 | ![配图41](https://wiki.huihoo.com/images/thumb/3/3e/Devopsgirls41.png/728px-Devopsgirls41.png) 31 | -------------------------------------------------------------------------------- /courses/python42.md: -------------------------------------------------------------------------------- 1 | # 第42课:会话 2 | 3 | ### 了解会话 4 | 打开浏览器,我们使用 Cookie 包含会话ID,而不是数据本身(除非你使用基于cookie的后端),Django 会话框架基于 cookie,Django 有完整的会话管理解决方案,支持多种后段服务。 5 | * django.contrib.sessions.backends.db (默认) 6 | * django.contrib.sessions.backends.file 7 | * django.contrib.sessions.backends.cache 8 | * django.contrib.sessions.backends.cached_db 9 | * django.contrib.sessions.backends.signed_cookies 10 | 11 | 一旦用户通过身份验证,Django 会将之前用于验证该用户的后端保存在用户的 session 中,以便在将来(session 有效期内)需要访问当前已验证的用户时可以重用该后端。这个优化意味着在 session 中缓存了验证后端的代码,因此,如果你修改了 AUTHENTICATION_BACKENDS 同时希望使用另外的方法重新验证用户,那么需要清除 session 数据,清除 session 数据的一个简单方法是执行 Session.objects.all().delete()。 12 | 13 | ![class42](images/class42-01.png) 14 | Django 会话是通过中间件实现的,在 mysite/setting.py 激活: 15 | ``` 16 | INSTALLED_APPS = [ 17 | 'django.contrib.sessions', 18 | 19 | MIDDLEWARE = [ 20 | 'django.contrib.sessions.middleware.SessionMiddleware', 21 | ``` 22 | 取某一用户的会话过期时间: 23 | ``` 24 | >>> from django.contrib.sessions.models import Session 25 | >>> s = Session.objects.get(pk='ud23ao1l6fwa4ft3ut4ksxcof0mh91g4') 26 | >>> s.expire_date 27 | datetime.datetime(2019, 2, 22, 15, 13, 2, 369009, tzinfo=) 28 | ``` 29 | 大家可看到,这个数据就是上图的会话数据。 30 | 31 | 大家也对照自己的数据库数据,重复这个实验过程。 32 | 33 | ### 会话设置 34 | Django 提供了一些设置可帮助你控制会话行为: 35 | * SESSION_CACHE_ALIAS 36 | * SESSION_COOKIE_AGE 37 | * SESSION_COOKIE_DOMAIN 38 | * SESSION_COOKIE_HTTPONLY 39 | * SESSION_COOKIE_NAME 40 | * SESSION_COOKIE_PATH 41 | * SESSION_COOKIE_SAMESITE 42 | * SESSION_COOKIE_SECURE 43 | * SESSION_ENGINE 44 | * SESSION_EXPIRE_AT_BROWSER_CLOSE 45 | * SESSION_FILE_PATH 46 | * SESSION_SAVE_EVERY_REQUEST 47 | * SESSION_SERIALIZER 48 | 49 | 如,SESSION_ENGINE,默认是 django.contrib.sessions.backends.db 50 | 51 | 52 | 配图来自Twitter:@ukiukisoda 53 | 54 | ![配图42](https://wiki.huihoo.com/images/thumb/9/99/Devopsgirls42.jpg/717px-Devopsgirls42.jpg) 55 | -------------------------------------------------------------------------------- /courses/python43.md: -------------------------------------------------------------------------------- 1 | # 第43课:分页 2 | 3 | ### 简介 4 | Django 提供了一些帮助你管理分页数据,这些类在 django/core/paginator.py 中定义 5 | 6 | ### 例子 7 | ``` 8 | >>> from django.core.paginator import Paginator 9 | >>> objects = ['Pyton', 'Go', 'C', 'C++', 'C#'] 10 | >>> p = Paginator(objects, 2) 11 | >>> p.count 12 | 5 13 | >>> p.num_pages 14 | 3 15 | >>> p.page_range 16 | range(1, 4) 17 | >>> page1 = p.page(1) 18 | >>> page1 19 | 20 | >>> page1.object_list 21 | ['Pyton', 'Go'] 22 | >>> page2 = p.page(2) 23 | >>> page2.object_list 24 | ['C', 'C++'] 25 | >>> page2.has_next() 26 | True 27 | ``` 28 | 29 | ### 在视图中使用Paginator 30 | 为方便,直接使用 Django 自带的 User 模型(不需要自己创建,也没有迁移过程),先通过 Admin 后台增加一些测试用户。 31 | 32 | ![class43-02](images/class43-02.png) 33 | 34 | 创建一个 Users 应用:$ python manage.py startapp users 35 | 36 | ### 修改视图 37 | users/views.py 38 | ``` 39 | from django.shortcuts import render 40 | from django.contrib.auth.models import User 41 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 42 | 43 | def index(request): 44 | user_list = User.objects.all() 45 | page = request.GET.get('page', 1) 46 | 47 | paginator = Paginator(user_list, 3) 48 | try: 49 | users = paginator.page(page) 50 | except PageNotAnInteger: 51 | users = paginator.page(1) 52 | except EmptyPage: 53 | users = paginator.page(paginator.num_pages) 54 | 55 | return render(request, 'user_list.html', { 'users': users }) 56 | 57 | ``` 58 | 59 | ### 修改模版 60 | users/templates/user_list.html 61 | ``` 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | {% for user in users %} 72 | 73 | 74 | 75 | 76 | 77 | {% endfor %} 78 | 79 |
UsernameFirst nameEmail
{{ user.username }}{{ user.first_name }}{{ user.email }}
80 | 81 | {% if users.has_other_pages %} 82 | 83 | {% if users.has_previous %} 84 | « 85 | {% else %} 86 | « 87 | {% endif %} 88 | {% for i in users.paginator.page_range %} 89 | {% if users.number == i %} 90 | {{ i }} (current) 91 | {% else %} 92 | {{ i }} 93 | {% endif %} 94 | {% endfor %} 95 | {% if users.has_next %} 96 | » 97 | {% else %} 98 | » 99 | {% endif %} 100 | {% endif %} 101 | ``` 102 | 103 | ### URL声明 104 | users/urls.py 105 | ``` 106 | from django.urls import path 107 | from . import views 108 | 109 | app_name = 'users' 110 | urlpatterns = [ 111 | path('', views.index, name='index'), 112 | ] 113 | 114 | ``` 115 | 116 | ### mysite添加相应配置 117 | 把 users 应用添加到 mysite 项目里(一个项目可包含多个应用): 118 | 119 | mysite/settings.py 120 | ``` 121 | INSTALLED_APPS = [ 122 | 'users.apps.UsersConfig', 123 | 'polls.apps.PollsConfig', 124 | ``` 125 | 126 | mysite/urls.py 127 | ``` 128 | urlpatterns = [ 129 | path('users/', include('users.urls')), 130 | path('polls/', include('polls.urls')), 131 | ``` 132 | 133 | ### 大功告成 134 | $ python manage.py runserver 135 | 136 | http://localhost:8000/ 可看到有 users 应用了 137 | 138 | ![class43-03](images/class43-03.png) 139 | 140 | http://localhost:8000/users 141 | 142 | ![class43-04](images/class43-04.png) 143 | 144 | 配图来自Twitter:@ukiukisoda 145 | 146 | ![配图43](https://wiki.huihoo.com/images/d/d3/Devopsgirls43.jpg) 147 | -------------------------------------------------------------------------------- /courses/python44.md: -------------------------------------------------------------------------------- 1 | # 第44课:验证 2 | 3 | ### 验证器 4 | 验证器是可调用(callable)的,它接受一个值并在不符合某些条件时引发ValidationError,验证器可在不同类型的字段之间重用这些验证逻辑。 5 | 6 | 例如,只允许偶数的验证器: 7 | ``` 8 | from django.core.exceptions import ValidationError 9 | from django.utils.translation import gettext_lazy as _ 10 | 11 | def validate_even(value): 12 | if value % 2 != 0: 13 | raise ValidationError( 14 | _('%(value)s is not an even number'), 15 | params={'value': value}, 16 | ) 17 | ``` 18 | 之后 ,你就可以通过字段的 validators 参数将其添加到模型字段的验证中了: 19 | ``` 20 | from django.db import models 21 | 22 | class MyModel(models.Model): 23 | even_field = models.IntegerField(validators=[validate_even]) 24 | ``` 25 | 26 | ### 内置验证器 27 | django.core.validators 模块包含一组可调用的验证器,用于模型和表单字段。 28 | * RegexValidator 29 | * EmailValidator 30 | * URLValidator 31 | * validate_email # EmailValidator实例(instance),无任何自定义。 32 | * validate_slug # RegexValidator实例,用于确保一个值仅包含字母,数字,下划线或连字符。 33 | * validate_unicode_slug # RegexValidator实例,用于确保一个值仅包含Unicode字母,数字,下划线或连字符。 34 | * validate_ipv4_address # RegexValidator实例,用于确保这是一个IPv4地址。 35 | * validate_ipv6_address # 使用 django.utils.ipv6 检查IPv6地址的有效性。 36 | * validate_ipv46_address # 使用 validate_ipv4_address 和 validate_ipv6_address 确保值是有效的IPv4或IPv6地址。 37 | * validate_comma_separated_integer_list # RegexValidator实例,确保值是以逗号分隔的整数列表。 38 | * int_list_validator # 返回一个 RegexValidator 实例,该实例确保字符串由 sep(sep=',')分隔的整数组成。当 allow_negative 为 True 时,允许负整数。 39 | * MaxValueValidator # 若 value 大于 limit_value,则使用 ‘max_value’ 抛出 ValidationError。 40 | * MinValueValidator # 若 value 小于 limit_value,则使用 'min_value' 抛出 ValidationError。 41 | * MaxLengthValidator # 若 value 的长度大于 limit_value,则使用 ‘max_length’ 抛出 ValidationError。 42 | * MinLengthValidator # 若 value 的长度小于 limit_value,则使用 'min_length' 抛出 ValidationError。 43 | * DecimalValidator # 这些 max_digits、max_decimal_places、max_whole_digits 代码可能会抛出 ValidationError 错误。 44 | * FileExtensionValidator # 若在 allowed_extensions 中找不到 value.name 的扩展名,则抛出 ValidationError 错误。 45 | * validate_image_file_extension # 使用 Pillow 确保 value.name 是个有效图像扩展名。 46 | * ProhibitNullCharactersValidator # 若 str(value)包含一个或多个空值字符('\ x00'),则抛出 ValidationError 错误。 47 | 48 | ### URLValidator例子 49 | ``` 50 | >>> from django.core.validators import URLValidator 51 | >>> from django.core.exceptions import ValidationError 52 | >>> def is_valid_url(url): 53 | ... validate = URLValidator() 54 | ... try: 55 | ... validate(url) 56 | ... return True 57 | ... except ValidationError: 58 | ... return False 59 | ... 60 | >>> is_valid_url("htps://github.com") 61 | False 62 | >>> is_valid_url("https://github.com") 63 | True 64 | ``` 65 | 66 | 配图来自Twitter:@ukiukisoda 67 | 68 | ![配图44](https://wiki.huihoo.com/images/thumb/9/9c/Devopsgirls44.jpg/732px-Devopsgirls44.jpg) 69 | 70 | -------------------------------------------------------------------------------- /courses/python45.md: -------------------------------------------------------------------------------- 1 | # 第45课:序列化 2 | 3 | ### 简介 4 | Django 序列化框架提供了一种将 Django 模型转换为其他格式的机制。 5 | 6 | Django 支持的序列化格式有: 7 | * XML 8 | * JSON 9 | * YAML 10 | 11 | ### 序列化 12 | ``` 13 | >>> from django.core import serializers 14 | >>> with open("person.xml", "w") as out: 15 | ... xml_serializer.serialize(Person.objects.all(), stream=out) 16 | ``` 17 | 这时在目录下生成了 person.xml,内容如下: 18 | ``` 19 | 20 | 21 | 22 | AllenLong 23 | 24 | 25 | PeterChen 26 | 27 | 28 | ``` 29 | 试试 JSON 格式: 30 | ``` 31 | >>> from django.core.serializers import serialize 32 | >>> with open("person.json", "w") as out: 33 | ... serialize('json', Person.objects.all(), stream=out) 34 | ``` 35 | 目录下生成了 person.json,内容如下: 36 | ``` 37 | [ 38 | { 39 | "model": "polls.person", 40 | "pk": 1, 41 | "fields": { 42 | "first_name": "Allen", "last_name": "Long" 43 | } 44 | }, 45 | { 46 | "model": "polls.person", 47 | "pk": 2, 48 | "fields": { 49 | "first_name": "Peter", "last_name": "Chen" 50 | } 51 | } 52 | ] 53 | ``` 54 | 55 | ### 反序列化 56 | 57 | 配图来自Twitter:@ukiukisoda 58 | 59 | ![配图45](https://wiki.huihoo.com/images/2/24/Devopsgirls45.png) 60 | -------------------------------------------------------------------------------- /courses/python46.md: -------------------------------------------------------------------------------- 1 | # 第46课:缓存 2 | 3 | ### 简介 4 | 对于动态 Web 网站,每次用户发起的请求,服务器都会计算,从数据库查询、业务逻辑、页面渲染等,这些都会消费计算资源。而缓存就是保存这些计算结果,不用每一次都重新计算,这样就极大的减少了服务端的开销和压力,也会带来性能和用户体验的提升。 5 | 6 | Web 应用涉及不同层面的缓存:数据库、文件系统、内存等。 7 | * Memcached 8 | * Database caching 9 | * Filesystem caching 10 | * Local-memory caching 11 | * Dummy caching (for development) 12 | 13 | ### 缓存API 14 | 通过 Django 提供的缓存 API,你可以任意粒度缓存各种 Python 对象:字符串、字典、模型对象列表等。 15 | 16 | ``` 17 | >>> from django.core.cache import cache 18 | >>> cache.set('my_key', 'hello, world!', 30) 19 | >>> cache.get('my_key') 20 | 'hello, world!' 21 | >>> cache.get('my_key') 22 | >>> 23 | 没有返回值,因为30秒后,cache已过期(expire)。 24 | ``` 25 | 26 | ### Memcached 27 | Memcached 是 Django 原生支持的最快,最有效的缓存类型,它是一个完全基于内存的缓存服务器,所有缓存的数据都存储在内存中,Facebook、Wikipedia 等大型网站使用它来减少数据库访问并显着提高网站性能。 28 | 29 | 安装完 Memcached 后,你需要安装两个最常见的 Python 包:[python-memcached](https://pypi.org/project/python-memcached/)、[pylibmc](https://pypi.org/project/pylibmc/)。 30 | 31 | Memcached 有很多的配置方案,这是本地缓存的例子,使用了 python-memcached 绑定。 32 | ``` 33 | CACHES = { 34 | 'default': { 35 | 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 36 | 'LOCATION': '127.0.0.1:11211', 37 | } 38 | } 39 | ``` 40 | ### 数据库缓存 41 | 需要先在数据库中建立一个用于缓存的数据库表,数据库缓存使用的是你配置文件中的数据库,而不是其他的数据库,本教程指的是 PostgreSQL。 42 | 43 | $ python manage.py createcachetable my_cache_table 44 | 45 | 配置信息 46 | ``` 47 | CACHES = { 48 | 'default': { 49 | 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 50 | 'LOCATION': 'my_cache_table', 51 | } 52 | } 53 | ``` 54 | ### 文件系统缓存 55 | 目录使用绝对地址 56 | ``` 57 | CACHES = { 58 | 'default': { 59 | 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 60 | 'LOCATION': '/var/tmp/django_cache', # 'LOCATION': 'c:/foo/bar', 这是 Windows 下的目录格式 61 | } 62 | } 63 | ``` 64 | 65 | ### 本地内存缓存 66 | 如果未在设置文件中指定其他缓存方案,则它就是默认缓存。若你想运行类似 Memcached 这样速度优势的方案(但没安装 Memcached),可采用此方案用于开发。 67 | 68 | 缓存使用最近最少使用(least-recently-used,LRU)策略。 69 | 70 | ``` 71 | CACHES = { 72 | 'default': { 73 | 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 74 | 'LOCATION': 'unique-snowflake', 75 | } 76 | } 77 | ``` 78 | ### 虚拟缓存 79 | 虚拟缓存,实际上并不是真实的缓存,它只是实现了缓存接口而不做任何事情,常用于开发/测试中不使用缓存的情况。 80 | 81 | ``` 82 | CACHES = { 83 | 'default': { 84 | 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', 85 | } 86 | } 87 | ``` 88 | 89 | ### 缓存中间件 90 | 要注意顺序,因为中间件的顺序决定了运行的顺序。UpdateCache一定要放在第一位,Fetch必须放最后。 91 | ``` 92 | MIDDLEWARE = [ 93 | 'django.middleware.cache.UpdateCacheMiddleware', 94 | 'django.middleware.common.CommonMiddleware', 95 | 'django.middleware.cache.FetchFromCacheMiddleware', 96 | ] 97 | ``` 98 | 99 | 配图来自Twitter:@tomo_3 100 | 101 | ![配图46](https://wiki.huihoo.com/images/thumb/3/33/Devopsgirls46.jpg/726px-Devopsgirls46.jpg) 102 | -------------------------------------------------------------------------------- /courses/python47.md: -------------------------------------------------------------------------------- 1 | # 第47课:日志 2 | 3 | Django 使用 Python 内置的 logging 模块处理日志信息。 4 | 5 | ### 日志框架 6 | 一个 Python logging 配置有以下四个部分组成: 7 | * Loggers 8 | * Handlers 9 | * Filters 10 | * Formatters 11 | 12 | #### Loggers 13 | logger 是日志系统的入口。每个 logger 都是命名的 bucket, 消息写入 bucket 以便进一步处理。 14 | 15 | 日志级别 16 | * logger.debug() 17 | * logger.info() 18 | * logger.warning() 19 | * logger.error() 20 | * logger.critical() 21 | 22 | 此外,你还可以: 23 | * logger.log():手动输出一条指定日志级别的日志消息。 24 | * logger.exception():创建一个包含当前异常堆栈帧的 ERROR 级别日志消息。 25 | 26 | #### Handlers 27 | Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为,比如把消息输出到屏幕、文件或网络 socket。 28 | 29 | #### Filters 30 | 在日志记录从 logger 传到 handler 的过程中,使用 Filter 来做过滤操作。 31 | 32 | #### Formatters 33 | 日志记录最终是以文本呈现,Formatter 描述文本的格式。 34 | 35 | ### 配置示例 36 | 一个简单的配置,将来自 Django logger 的所有日志记录写入本地文件: 37 | ``` 38 | LOGGING = { 39 | 'version': 1, 40 | 'disable_existing_loggers': False, 41 | 'handlers': { 42 | 'file': { 43 | 'level': 'DEBUG', 44 | 'class': 'logging.FileHandler', 45 | 'filename': '/var/log/django/debug.log', 46 | }, 47 | }, 48 | 'loggers': { 49 | 'django': { 50 | 'handlers': ['file'], 51 | 'level': 'DEBUG', 52 | 'propagate': True, 53 | }, 54 | }, 55 | } 56 | ``` 57 | 58 | ### 使用Logger 59 | 配置好了 logger,handler,filter 和 formatter 后,就是在代码里调用 logging 模块: 60 | ``` 61 | import logging 62 | 63 | logger = logging.getLogger(__name__) 64 | 65 | def my_view(request, arg1, arg): 66 | ... 67 | if bad_mojo: 68 | logger.error('Something went wrong!') 69 | ``` 70 | bad_mojo 条件每次满足都会写一条 error 日志。 71 | 72 | 配图来自Twitter:@tomo_3 73 | 74 | ![配图47](https://wiki.huihoo.com/images/c/ce/Devopsgirls47.jpg) 75 | -------------------------------------------------------------------------------- /courses/python48.md: -------------------------------------------------------------------------------- 1 | # 第48课:安全概览 2 | 3 | 在 Web 应用的发展中,安全是最重要主题,Django 提供了多种保护手段和机制。 4 | 5 | 本节课概述 Django 安全功能,以及 Django 驱动网站的安全建议。 6 | 7 | ### XSS 保护 8 | Cross site scripting (XSS) 攻击允许恶意用户将客户端脚本注入其他用户的浏览器中,这通常通过让用户单击链接来实现,该链接将导致攻击者的JavaScript由用户的浏览器执行。 9 | 10 | 使用 Django 模板可以保护你免受大多数XSS攻击,存在一定局限性。 11 | 12 | ### CSRF 保护 13 | Cross site request forgery (CSRF) 攻击允许恶意用户使用其他用户的证书(credentials)执行操作,而无需用户的知情或同意。 14 | 15 | Django 内置了针对大多数类型的CSRF攻击的保护,只要你在适当的地方启用和使用它,也存在一定局限性。 16 | 17 | CSRF 通过检查每个POST请求中的 secret 来保护工作,用户可使用 csrf_exempt 装饰器标记视图。 18 | 19 | ### SQL 注入保护 20 | SQL 注入(injection)是一种攻击类型,恶意用户可以在数据库上执行任意SQL代码,这可能导致数据库记录被删除或数据泄漏。 21 | 22 | Django 查询集(querysets)受到SQL注入的保护,它们的查询是使用查询参数化构造的,查询的SQL语句与查询的参数分开定义。由于参数可能是用户提供的,因此不安全,所以它们会被底层数据库驱动程序转义(escaped)。 23 | 24 | ### 点击劫持保护 25 | 点击劫持(Clickjacking)也是一种攻击类型,其中恶意网站将另一个站点包装(wraps)在一个帧中,此攻击可能导致不知情的用户被欺骗在目标站点上执行意外操作。 26 | 27 | Django 包含 X-Frame-Options 中间件形式的点击劫持保护,在支持的浏览器中可以防止网站在框架内渲染。 28 | 29 | ### SSL/HTTPS 30 | 支持 HTTPS 的站点拥有更好的安全性,请尽可能使用它。 31 | 32 | ### Header 验证 33 | 这个主要是防虚假主机的,因为即使安全配置了的 Web 服务器也容易受到虚假主机 Headers 的影响,Django 会根据 django.http.HttpRequest.get_host() 方法中的 ALLOWED_HOSTS 设置验证主机 Headers。 34 | 35 | ### Session 安全 36 | 这块是有关 [django.contrib.sessions](python42.md) 的主题。 37 | 38 | 配图来自Twitter:@tomo_3 39 | 40 | ![配图48](https://wiki.huihoo.com/images/thumb/e/e3/Devopsgirls48.jpg/684px-Devopsgirls48.jpg) 41 | -------------------------------------------------------------------------------- /courses/python49.md: -------------------------------------------------------------------------------- 1 | # 第49课:加密签名 2 | 3 | 背景:Web 应用安全的黄金法则是永远不要信任来自不受信任来源的数据。 4 | 5 | Django 既提供用于签名值的低级 API,也提供用于设置和读取签名cookie的高级 API。 6 | 7 | ### SECRET_KEY 8 | 使用 startproject 创建 Django 项目时,会自动生成 settings.py 文件并获取随机的 SECRET_KEY 值。 此值是保护签名数据的关键,其安全至关重要,因为攻击者可以使用它来生成自己的签名值。 9 | 10 | 类似这样的一个值:SECRET_KEY = 'c=$*+jdept%gz2a+b(dasdfdsczc5&&2q&gasdfeasy#1j=' 11 | 12 | ### 使用API 13 | ``` 14 | >>> from django.core.signing import Signer 15 | >>> signer = Signer() 16 | >>> value = signer.sign('python') 17 | >>> value 18 | 'python:Gl-at2uNL427Vt2IuODkwD93Tzc' 19 | >>> 20 | 21 | >>> original = signer.unsign(value) 22 | >>> original 23 | 'python' 24 | ``` 25 | 26 | 配图来自Twitter:@tomo_3 27 | 28 | ![配图49](https://wiki.huihoo.com/images/thumb/8/87/Devopsgirls49.jpg/1280px-Devopsgirls49.jpg) -------------------------------------------------------------------------------- /courses/python50.md: -------------------------------------------------------------------------------- 1 | # 第50课:中间件 2 | 3 | 前面的课程中我们都有使用到 Django 中间件,这里我们简单梳理一下。 4 | 5 | 中间件是可调用的,它接受请求并返回响应,就像视图一样。 6 | 7 | ![middleware](https://docs.djangoproject.com/en/1.9/_images/middleware.svg) 8 | 9 | 注意:此图来自 Django 1.9 官方文档,之后版本已没有此图,仅供大家参考,有一个整体思路。 10 | 11 | 中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低层的插件系统,用于全局改变 Django 的输入或输出。 12 | 13 | 每个中间件组件负责做一些特定的功能。如,AuthenticationMiddleware 中间件 ,它使用会话将用户与请求关联起来。 14 | 15 | 一些常见的功能我们可以采用中间件的方式,当然,我们也可以开发新的中间件。 16 | 17 | 中间件是有顺序的,因为中间件会依赖其他中间件。你可以把它想象成一个洋葱:每个中间件都是一个层,它们覆盖了洋葱的核心。如果请求是通过洋葱的所有层(每一个调用 get_response )以将请求传递到下一层,一直到内核的视图,那么响应将在返回的过程中通过每个层(以相反的顺序)。 18 | 19 | 以下是中间件的顺序(ordering): 20 | * 1、SecurityMiddleware 21 | * 2、UpdateCacheMiddleware 22 | * 3、GZipMiddleware 23 | * 4、SessionMiddleware 24 | * 5、ConditionalGetMiddleware 25 | * 6、LocaleMiddleware 26 | * 7、CommonMiddleware 27 | * 8、CsrfViewMiddleware 28 | * 9、AuthenticationMiddleware 29 | * 10、MessageMiddleware 30 | * 11、FetchFromCacheMiddleware 31 | * 12、FlatpageFallbackMiddleware 32 | * 13、RedirectFallbackMiddleware 33 | 34 | ### SecurityMiddleware 35 | 这里主要介绍 django.middleware.security.SecurityMiddleware 安全中间件 36 | 37 | 它在 settings.py 定义: 38 | ``` 39 | MIDDLEWARE = [ 40 | 'django.middleware.security.SecurityMiddleware', 41 | ``` 42 | SecurityMiddleware 为应用的请求和响应周期提供了若干安全增强功能,每个都可以设置启用或禁用。 43 | * SECURE_BROWSER_XSS_FILTER 44 | * SECURE_CONTENT_TYPE_NOSNIFF 45 | * SECURE_HSTS_INCLUDE_SUBDOMAINS 46 | * SECURE_HSTS_PRELOAD 47 | * SECURE_HSTS_SECONDS 48 | * SECURE_REDIRECT_EXEMPT 49 | * SECURE_SSL_HOST 50 | * SECURE_SSL_REDIRECT 51 | 52 | 配图来自Twitter:@tomo_3 53 | 54 | ![配图50](https://wiki.huihoo.com/images/thumb/f/fc/Devopsgirls50.png/724px-Devopsgirls50.png) 55 | -------------------------------------------------------------------------------- /courses/python51.md: -------------------------------------------------------------------------------- 1 | # 第51课:知识回顾 2 | 3 | ### Python知识点 4 | * 数据类型:Number、String、Tuple、List、Dictionary、Set,区分可变、不可变 5 | * 条件 if - elif - else : 6 | * 循环 for、while 7 | * 文件目录:open、write、 close 和 dir、chdir、path 8 | * 错误异常:SyntaxError、try/except、raise、Exception、Finally、traceback 9 | * 语法(Syntax)、语义(Semantics)、词汇(Lexical) 10 | * 操作符:(+、-、*、/),(==、!=、<、>=、<=),(&、|、^、~、<< 、>>),(and、or、not),(in、not in) 11 | * 程序结构:包、模块、函数/类 12 | * 面向对象:属性 + 方法,公有、私有、实例化 13 | * 接口:是定义,不实现 14 | * 闭包:避免了全局变量的使用,包裹里有自由变量 15 | * 元编程:不要重复自己 16 | * 测试:unittest、doctest、py.test、mock、自动化、持续集成 17 | * 设计模式:有很多,记住三大类:创建、结构、行为 18 | * 领域特定语言:内部DSL和外部DSL的使用帮助你应对特定领域问题,如数据库查询、文本处理等 19 | 20 | ### Django知识点 21 | * Django 包含了开发动态 Web 应用的几乎所有相关知识,一站式框架帮助你快速建立完整知识结构 22 | * 核心:模型、模板、视图 23 | * 动态 Web 应用基本功能:认证、会话、验证、分页、序列化、缓存、日志、安全、加密 24 | * 中间件:是可复用的基本功能:安全、缓存、验证、会话、消息 ... 25 | * Django 管理后台帮助更好的管理项目和应用 26 | 27 | ### PostgreSQL知识点 28 | * 使用pgAdmin连接和管理PostgreSQL会带来很多方便 29 | * 使用Psycopgs适配器 30 | * Django 提供 PostgreSQL 的特定功能:django.contrib.postgres 31 | 32 | 配图来自Twitter:@tomo_3 33 | 34 | ![配图51](https://wiki.huihoo.com/images/e/e9/Devopsgirls51.jpg) 35 | -------------------------------------------------------------------------------- /courses/python52.md: -------------------------------------------------------------------------------- 1 | # 第52课:难点强化 2 | 3 | 简单讲,Web 应用的核心就是模型、视图、模版、表单、安全等,而模型(数据库)、安全是重中之中,所以我们的强化部分也将围绕它们展开。 4 | 5 | 配图来自Twitter:@tomo_3 6 | 7 | ![配图52](https://wiki.huihoo.com/images/2/2f/Devopsgirls52.png) 8 | -------------------------------------------------------------------------------- /courses/python53.md: -------------------------------------------------------------------------------- 1 | # 第53课:Python进阶 2 | 3 | ### 项目 4 | 一些网友推荐的项目形式: 5 | * 教女孩纸如何扒帅哥照片,以女孩纸兴趣引导教学; 6 | * 爬虫、姨妈钟; 7 | ... 8 | 9 | ### 参考资料 10 | DevOpsGirls(Python程序媛)也参考和引用了以下资料,大家可进一步深入: 11 | 12 | * [Python Cheat Sheet(Python速查表)](https://github.com/crazyguitar/pysheeet) 帮助查阅和熟悉Python3代码和各个细节知识点。 13 | * [《Python进阶》](https://github.com/eastlakeside/interpy-zh)是《Intermediate Python》的中文译本。 14 | * [《Python Cookbook》 3rd 中文版](https://github.com/yidao620c/python3-cookbook) 15 | * [《Django 中文文档》](https://docs.huihoo.com/django/2.1-zh-cn/index.html) 16 | * [《Python Web开发实践》](https://www.amazon.cn/dp/B01L8NVIC6/) 17 | * [Python 3 教程](http://www.runoob.com/python3/python3-tutorial.html) 18 | * [轻量级Django](https://www.amazon.cn/dp/B01M4S72G0/) 19 | * [Django教程](https://www.w3cschool.cn/django/) 20 | * [Django Girls 教程](https://tutorial.djangogirls.org/zh/) 21 | * [基于 Python3.5 和 Django 1.10 的 Django Blog 项目](https://github.com/zmrenwu/django-blog-tutorial) 22 | * [python-doc中文文档](https://github.com/ictar/python-doc) 23 | 24 | 配图来自Twitter:@tomo_3 25 | 26 | ![配图53](https://wiki.huihoo.com/images/thumb/b/bf/Devopsgirls53.jpg/696px-Devopsgirls53.jpg) 27 | -------------------------------------------------------------------------------- /courses/python54.md: -------------------------------------------------------------------------------- 1 | # 第54课:Python面试 2 | 3 | Python 面试或许会有点像考试,想想之前的中考、高考,你也应该有些感受。 4 | 5 | 首先,多做Python练习题和编码,重点难点反复推敲理解、做到举一反三。 6 | 7 | 努力达成的结果,两个字总结:快(基础扎实、编码快)深(重点难点的深入理解,如:模型) 8 | 9 | ### Python面试题 10 | 网上已有很多 Python 面试题了,这里先收集整理一些,反复看和练习,最好把它们记住: 11 | * [关于Python的面试题](https://github.com/taizilongxu/interview_python) 12 | * [2018年最常见的Python面试题&答案(上篇)](https://juejin.im/post/5b6bc1d16fb9a04f9c43edc3) [(下篇)](https://juejin.im/post/5b8505b6e51d4538884d22bf) 13 | * [Python面试必须要看的15个问题](http://codingpy.com/article/essential-python-interview-questions/) 14 | 15 | ### 问题深入展开 16 | 这里就从模型入手,作为一个参考,将你对模型深入理解的思路、重点逐步展开: 17 | * 1、Python 中的一切都是对象。 18 | * 2、模型是一种特殊的对象,它保存在数据库中,列(字段)行(数据)。 19 | * 3、$ python manage.py startapp blog 创建一个应用,生成模型文件:models.py 20 | * 4、在 modles.py 中定义 Post 模型,有标题、内容、创建时间、作者等类变量,它们对应数据库表字段 21 | * 5、激活迁移模型,这时数据库和表会从模型自动生成 22 | * 6、以后表修改就采用类似的步骤:改变模型、生成迁移文件、完成数据库迁移 23 | 24 | 25 | 配图来自Twitter:@atikix 26 | 27 | ![配图54](https://wiki.huihoo.com/images/d/d3/Devopsgirls54.jpg) 28 | -------------------------------------------------------------------------------- /slides/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/slides/README.md -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihoo/DevOpsGirls/c7b39c1b69d3283b765698153eb470eb413d60fc/src/README.md --------------------------------------------------------------------------------