diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d7a963a62..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: "node_js"
-node_js:
- - "8"
-before_install:
- - find . -type f -name "*.md" ! -path "./README.md" -a ! -path "./SUMMARY.md"|xargs -i sed -ri '/^/d;0,/^## /s/(^## .*)/\n<\/extoc>\n\n\1/' '{}'
-install:
- - "npm install gitbook"
- - "npm install gitbook-cli@2.3.0"
-branches:
- only:
- - master
-env:
- global:
- - GH_REF: github.com/lyonyang/blogs.git
-script:
- - bash summary_create.sh
- - travis_wait 100 bash deploy.sh
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/01-\350\257\255\350\250\200\345\237\272\347\241\200.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/01-\350\257\255\350\250\200\345\237\272\347\241\200.md"
deleted file mode 100644
index 6ba615f07..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/01-\350\257\255\350\250\200\345\237\272\347\241\200.md"
+++ /dev/null
@@ -1,428 +0,0 @@
-# Attack on Python - 语言基础 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## Hello World
-
-学一门语言基本都是从Hello World开始的 , 如下一个最简单的Hello World程序
-
-```python
-Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32
-Type "help", "copyright", "credits" or "license" for more information.
->>> print("Hello World")
-Hello World
->>>
-```
-
-此为Python 3.5.2版本 , 上述代码为在Windows环境命令行中执行 , 即以管理员身份运行 "命令提示符"
-
-```python
-# 已添加环境变量
-C:\Windows\system32>python
-```
-
-Python 2.7.x 版本的Hello World程序
-
-```python
-Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:53:40) [MSC v.1500 64 bit (AMD64)] on win32
-Type "help", "copyright", "credits" or "license" for more information.
->>> print "Hello World"
-Hello World
->>>
-```
-
-当然使用`Python shell` 仅仅适合处理一些非常简单的小程序 , 对于比较复杂 , 代码量稍微大一点的就不适合了
-
-
-
-## 变量
-
-变量用于存储在计算机程序中被引用和操作的信息
-
-变量可能被明确为是能表示可变状态、具有存储空间的抽象(如在Java和Visual Basic中) , 变量的唯一目的是在内存中标记和存储数据 , 这些数据可以在整个程序中使用
-
-声明变量
-
-```python
-# 声明一个变量name,并绑定值"Lyon"
-name = "Lyon"
-# 同时为多个变量赋值
-a = b = c = 1
-```
-
-Python变量定义的规则 :
-
-1. 变量名只能是 字母、数字或者下划线的任意组合
-
-2. 变量名的第一个字符不能是数字
-
-3. 以下关键字不能声明为变量名 , 属于Python中的保留字and
-
-
-| and | exec | not |
-| -------- | ------- | ------ |
-| assert | finally | or |
-| break | for | pass |
-| class | from | print |
-| continue | global | raise |
-| def | if | return |
-| del | import | try |
-| elif | in | while |
-| else | is | with |
-| except | lambda | yield |
-
-
-## 行和缩进
-
-Python 与其他语言最大的区别就是 , Python 的代码块不使用大括号 `{}` 来控制类 , 函数以及其他逻辑判断 , Python 最具特色的就是用缩进来写模块
-
-缩进的空白数量是可变的 , 但是所有代码块语句必须包含相同的缩进空白数量 , 这个必须严格执行
-
-```python
-if True:
- print "True"
-else:
- print "False"
-'''
-执行会出现错误提醒:
-IndentationError: unexpected indent
-'''
-```
-
-`IndentationError: unexpected indent` 错误是Python编译器在告诉你 , 你的文件里格式有问题 , 可能是tab和空格没对齐的问题
-
-还有`IndentationError: unindent does not match any outer indentation level` 错误表明 , 你使用的缩进方式不一致 , 有的是 tab 键缩进 , 有的是空格缩进 , 改为一致即可。
-
-因此 , 在 Python 的代码块中必须使用相同数目的行首缩进空格数
-
-建议你在每个缩进层次使用 **单个制表符** 或 **两个空格** 或 **四个空格** , 切记不能混用
-
-## 多行语句
-
-Python语句中一般以新作为为语句的结束符
-
-但是我们可以使用斜杠 ` \ ` 将一行的语句分为多行显示 , 如下 :
-
-```python
-total = item_one + \
- item_two + \
- item_three
-```
-
-语句中包含 [], {} 或 () 括号就不需要使用多行连接符 , 如下实例 :
-
-```python
-days = ['Monday', 'Tuesday', 'Wednesday',
- 'Thursday', 'Friday']
-```
-
-**同一行使用多条语句**
-
-Python可以在同一行中使用多条语句 , 语句之间使用分号 `;` 分割 , 如下 :
-
-```python
-#!/usr/bin/python
-import sys; x = 'runoob'; sys.stdout.write(x + '\n')
-```
-
-## 字符串
-
-Python 可以使用引号( **'** )、双引号( **"** )、三引号( **'''** 或 **"""** ) 来表示字符串 , 引号的开始与结束必须的相同类型的
-
-其中三引号可以由多行组成 , 编写多行文本的快捷语法 , 常用于文档字符串 , 在文件的特定地点 , 被当做注释
-
-```python
-word = 'word'
-sentence = "This is a sentence"
-paragraph = """This is a paragraph
- Contains multiple statements"""
-```
-
-## 注释
-
-Python中单行注释采用 ` # ` 开头
-
-```python
-# 第一个注释
-print("Hello,Python") # 第二个注释
-```
-
-Python中多行注释采用三个单引号 ` ''' ` 或三个双引号 `""" `
-
-```python
-'''
-这是多行注释,使用单引号。
-这是多行注释,使用单引号。
-这是多行注释,使用单引号。
-'''
-"""
-这是多行注释,使用双引号。
-这是多行注释,使用双引号。
-这是多行注释,使用双引号。
-"""
-```
-
-## 字符编码
-
-Python解释器在加载 `.py` 文件中的代码时 , 会对内容进行编码 (默认ASCII)
-
-然而ASCII是无法处理中文的 , 所以如果我们的代码中出现了中文 , 那么需要在代码的顶端加上一句声明
-
-```python
-#!/usr/bin/env python
-# -*- coding:utf-8 -*-
-'''
-第一行,为脚本语言指定解释器
-第二行,告诉Python解释器,用utf-8编码来进行编码
-'''
-```
-
-## 用户输入
-
-当我们需要用户自己输入信息时 , 就可以使用`input` 语句 , 如下 :
-
-```python
-# 让用户进行输入,并用变量name接收用户输入的值
-name = input("Please input your name:")
-```
-
-上述代码 , 会一直等待用户输入 , 直到用户按回车键后才会退出
-
-## 输出
-
-当我们需要让控制台输出一些我们想要的信息时 , 可以使用`print` 语句 , 在Hello World里我们已经见到了
-
-```python
-#!/usr/bin/python
-# -*- coding: UTF-8 -*-
-# Author:Lyon
-x = "a"
-y = "b"
-# 换行输出
-print(x)
-print(y)
-print('---------')
-# 不换行输出
-print(x,)
-print(y,)
-# 不换行输出
-print(x, y)
-'''
-执行结果:
-a
-b
----------
-a b a b
-'''
-```
-
-## 数据类型
-
-我们知道在变量创建时 , 会在内存中开辟一个空间 , 用来存放变量的值 , 而这些变量的值可以是各种各样的类型 , 如 : 数字 , 字符串 , 列表 , 元组 , 字典 , 集合等等
-
-**数字类型**
-
-1. int (整型)
-
- 整数的大小范围由计算机字长确定
-
-2. long (长整型)
-
- 跟C语言不同 , Python的长整数没有指定位宽 , 即 : Python没有限制长整数数值的大小 , 但实际上由于机器内存有限 , 我们使用的长整数数值不可能无限大
-
- 注意 , 自从Python 2.2 起 , 如果整数发生溢出 , Python会自动将整数数据转换为长整数 , 所以如今在长整数数据后面不加字母 L 也不会导致严重后果了
-
-3. float (浮点型)
-
- 浮点数用来处理实数 , 即带有小数的数字 , 类似于C语言中的double类型 , 占8个字节(64位) , 其中52位表示底 , 11位表示指数 , 剩下的一位表示符号
-
-4. complex (复数)
-
- 复数由实数部分和虚数部分组成,一般形式为x+yh,其中的x是复数的实数部分,y是复数的虚数部分,这里的x和y都是实数
-
-注 : Python中存在整数小数字池 : -5~257 , 在此范围的整数数字共享
-
-**布尔值**
-
-即真或假 , 1或0
-
-更多数据类型 , 后续文章中详细整理
-
-## 数据运算
-
-算术运算符
-
-| 运算符 | 描述 | 实例 |
-| ---- | ------------------------- | ---------------------------------------- |
-| + | 加 - 两个对象相加 | a + b 输出结果 30 |
-| - | 减 - 得到负数或是一个数减去另一个数 | a - b 输出结果 -10 |
-| * | 乘 - 两个数相乘或是返回一个被重复若干次的字符串 | a * b 输出结果 200 |
-| / | 除 - x除以y | b / a 输出结果 2 |
-| % | 取模 - 返回除法的余数 | b % a 输出结果 0 |
-| ** | 幂 - 返回x的y次幂 | a**b 为10的20次方 , 输出结果 100000000000000000000 |
-| // | 取整除 - 返回商的整数部分 | 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 |
-
-比较运算符
-
-| 运算符 | 描述 | 实例 |
-| ---- | ---------------------------------------- | -------------------------- |
-| == | 等于 - 比较对象是否相等 | (a == b) 返回 False |
-| != | 不等于 - 比较两个对象是否不相等 | (a != b) 返回 True |
-| <> | 不等于 - 比较两个对象是否不相等 | (a <> b) 返回 True这个运算符类似 != |
-| > | 大于 - 返回x是否大于y | (a > b) 返回 False |
-| < | 小于 - 返回x是否小于y , 所有比较运算符返回1表示真 , 返回0表示假
这分别与特殊的变量True和False等价 , 注意 , 这些变量名的大写 | (a < b) 返回 True |
-| >= | 大于等于 - 返回x是否大于等于y。 | (a >= b) 返回 False |
-| <= | 小于等于 - 返回x是否小于等于y。 | (a <= b) 返回 True |
-
-赋值运算符
-
-| 运算符 | 描述 | 实例 |
-| ----- | -------- | ---------------------------- |
-| = | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |
-| += | 加法赋值运算符 | c += a 等效于 c = c + a |
-| -= | 减法赋值运算符 | c -= a 等效于 c = c - a |
-| *= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
-| /= | 除法赋值运算符 | c /= a 等效于 c = c / a |
-| %= | 取模赋值运算符 | c %= a 等效于 c = c % a |
-| \*\*= | 幂赋值运算符 | c \*\*= a 等效于 c = c \*\* a |
-| //= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
-
-位运算符
-
-| 运算符 | 描述 | 实例 |
-| ---- | ---------------------------------------- | ---------------------------------------- |
-| & | 按位与运算符 : 参与运算的两个值 , 如果两个相应位都为1 , 则该位的结果为1 , 否则为0 | (a & b) 输出结果 12 , 二进制解释 : 0000 1100 |
-| \ | 按位或运算符 : 只要对应的二个二进位有一个为1时 , 结果位就为1 | (a 丨 b) 输出结果 61 , 二进制解释 : 0011 1101 |
-| ^ | 按位异或运算符 : 当两对应的二进位相异时 , 结果为1 | (a ^ b) 输出结果 49 , 二进制解释 : 0011 0001 |
-| ~ | 按位取反运算符 : 对数据的每个二进制位取反 , 即把1变为0 , 把0变为1 , ~x 类似于 -x-1 | (~a ) 输出结果 -61 , 二进制解释 : 1100 0011 , 在一个有符号二进制数的补码形式 |
-| << | 左移动运算符 : 运算数的各二进位全部左移若干位 , 由 << 右边的数字指定了移动的位数 , 高位丢弃 , 低位补0 | a << 2 输出结果 240 , 二进制解释 : 1111 0000 |
-| >> | 右移动运算符 : 把">>"左边的运算数的各二进位全部右移若干位 , >> 右边的数字指定了移动的位数 | a >> 2 输出结果 15 , 二进制解释 : 0000 1111 |
-
-逻辑运算符
-
-| 运算符 | 逻辑表达式 | 描述 | 实例 |
-| ---- | ------- | ---------------------------------------- | --------------------- |
-| and | x and y | 布尔"与" - 如果 x 为 False , x and y 返回 False , 否则它返回 y 的计算值 | (a and b) 返回 20 |
-| or | x or y | 布尔"或" - 如果 x 是非 0 , 它返回 x 的值 , 否则它返回 y 的计算值 | (a or b) 返回 10 |
-| not | not x | 布尔"非" - 如果 x 为 True , 返回 False , 如果 x 为 False , 它返回 True | not(a and b) 返回 False |
-
-成员运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ---------------------------------- | --------------------------------- |
-| in | 如果在指定的序列中找到值返回 True , 否则返回 False | x 在 y 序列中 , 如果 x 在 y 序列中返回 True |
-| not in | 如果在指定的序列中没有找到值返回 True , 否则返回 False | x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True |
-
-身份运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ------------------------- | ---------------------------------------- |
-| is | is 是判断两个标识符是不是引用自一个对象 | **x is y ** , 类似 **id(x) == id(y)** , 如果引用的是同一个对象则返回 True , 否则返回 False |
-| is not | is not 是判断两个标识符是不是引用自不同对象 | **x is not y** , 类似 **id(a) != id(b) , 如果引用的不是同一个对象则返回结果 True , 否则返回 False |
-
-运算符优先级表 , 从上到下优先级依次增高
-
-| Operator | Description |
-| ---------------------------------------- | ---------------------------------------- |
-| [`lambda`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#lambda) | Lambda expression |
-| [`if`](https://docs.python.org/3/reference/compound_stmts.html#if) – [`else`](https://docs.python.org/3/reference/compound_stmts.html#else) | Conditional expression |
-| [`or`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#or) | Boolean OR |
-| [`and`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#and) | Boolean AND |
-| [`not`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#not) `x` | Boolean NOT |
-| [`in`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#in), [`not in`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#not-in), [`is`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#is), [`is not`](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#is-not), `<`, `<=`, `>`, `>=`, `!=`, `==` | Comparisons, including membership tests and identity tests |
-| `丨` | Bitwise OR |
-| `^` | Bitwise XOR |
-| `&` | Bitwise AND |
-| `<<`, `>>` | Shifts |
-| `+`, `-` | Addition and subtraction |
-| `*`, `@`, `/`, `//`, `%` | Multiplication, matrix multiplication, division, floor division, remainder [[5\]](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#id21) |
-| `+x`, `-x`, `~x` | Positive, negative, bitwise NOT |
-| `**` | Exponentiation [[6\]](https://docs.python.org/3/reference/expressions.html?highlight=operator%20precedence#id22) |
-| `await` `x` | Await expression |
-| `x[index]`, `x[index:index]`, `x(arguments...)`, `x.attribute` | Subscription, slicing, call, attribute reference |
-| `(expressions...)`, `[expressions...]`, `{key: value...}`, `{expressions...}` | Binding or tuple display, list display, dictionary display, set display |
-
-## if ... else
-
-场景一 : 用户登录验证
-
-```python
-# 导入getpass模块
-import getpass
-# 等待用户输入
-name = input("请输入用户名:")
-# 等待用户输入密码,密码不可见
-password = getpass.getpass("请输入密码:")
-# 如果用户密码正确,执行如下
-if name =="Lyon" and password =="yang":
- print("欢迎你!")
-# 否则执行如下
-else:
- print("用户名或密码错误")
-```
-
-场景二 : 猜年龄游戏
-
-```python
-# 定义一个年龄
-age =21
-# 用户输入
-user_input = int(input("input your guess num:"))
-if user_input == age:
- print("Congratulations, you got it !")
-elif user_input < age:
- print("Oops,think bigger!")
-else:
- print("think smaller!")
-```
-
-## for循环
-
-循环10次
-
-```python
-for i in range(10):
- print("loop:", i )
-'''
-执行结果:
-loop: 0
-loop: 1
-loop: 2
-loop: 3
-loop: 4
-loop: 5
-loop: 6
-loop: 7
-loop: 8
-loop: 9
-'''
-```
-
-小于5就跳入下一次循环
-
-```python
-for i in range(10):
- if i<5:
- continue
- print("loop:", i)
-```
-
-## while循环
-
-写一个死循环
-
-```python
-count = 0
-while True:
- print("你是风儿我是沙,缠缠绵绵走天涯", count)
- count += 1
-```
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/02-\346\225\260\345\255\227.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/02-\346\225\260\345\255\227.md"
deleted file mode 100644
index e9106a586..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/02-\346\225\260\345\255\227.md"
+++ /dev/null
@@ -1,128 +0,0 @@
-# Attack on Python - 数字 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 整型
-
-在 `Python 2.7` 版本中 , `Python` 把 `int` 和 `long` 是分开的
-
-`int` 类型的最大值是 `2147483647` , 超过了这个值就是 `long` 类型了(长整数不过是大一些的数) ; 而在3.x中 , `int` 和 `long` 整合到一起了 , 以 `int` 来表示
-
-```python
->>> num = 123
->>> type(num)
-
-```
-
-## 浮点型
-
-float有两种表现形式 , 一种是十进制数形式 , 它由数字和小数点组成 , 并且这里的小数点是不可或缺的 ; 另一种是指数形式 , 用e(大写也可以)来表示之后可以有正负号 , 来表示指数的符号 , e就是10的幂 , 指数必须是整数
-
-```python
->>> a = 10E2
->>> a
-1000.0
->>> b = 10e2
->>> b
-1000.0
->>> c = 1.1
->>> type(c)
-
-```
-
-小 `Tips` : 在我们工作中很多时候会需要一个无穷大 , 或者无穷小的预设值 , 就可以使用 `float` 来实现 , 无穷小和无穷大分别是 , `float('-inf')` 和 `float('inf')`
-
-## 空值
-
-表示该值是一个空对象 , 空值是python里一个特殊的值 , 用None表示
-
-None不能理解为0 , 因为0是有意义的 , 而None是一个特殊的空值 ; None有自己的数据类型NoneType , 它与其他的数据类型比较永远返回False , 你可以将None复制给任何变量 , 但是你不能创建其他NoneType对象
-
-```python
->>> type(None)
-
->>> None == 0
-False
->>> None == True
-False
->>> None == False
-False
-```
-
-## 布尔值
-
-bool就是用来表征真假的一种方式
-
-True为真 , False为假 ; Python中的值是自带bool值的 , 非0即真 , 为0即假
-
-```python
->>> False + False
-0
->>> True + True
-2
->>> True + False
-1
-```
-
-## 复数
-
-复数有实数和虚数部分组成 , 一般形式为 `x + yj` , 其中的 x 是复数的实数部分 , y是复数的虚数部分 , 这里x和y都是实数
-
-注意 , 虚数部分不区分大小写
-
-```python
->>> -.6545 + 0J
-(-0.6545+0j)
->>> 4.53e1 - 7j
-(45.3-7j)
->>> 45.j
-45j
->>> 3.14j
-3.14j
-```
-
-## 类型转换
-
-```python
-int(x [,base]) 将x转换为一个整数
-float(x ) 将x转换到一个浮点数
-complex(x) 将x转换为复数
-str(x) 将对象x转换为字符串 ,通常无法用eval()求值
-repr(x) 将对象x转换为表达式字符串 ,可以用eval()求值
-eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
-tuple(s) 将序列s转换为一个元组
-list(s) 将序列s转换为一个列表
-chr(x) 将一个整数转换为一个字符
-unichr(x) 将一个整数转换为Unicode字符
-ord(x) 将一个字符转换为它的整数值
-hex(x) 将一个整数转换为一个十六进制字符串
-oct(x) 将一个整数转换为一个八进制字符串
-```
-
-## 数学函数
-
-```python
-abs(x) 返回数字的绝对值,如abs(-10) 返回 10
-ceil(x) 返回数字的上入整数,如math.ceil(4.1) 返回 5
-cmp(x, y) 如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1
-exp(x) 返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045
-fabs(x) 返回数字的绝对值,如math.fabs(-10) 返回10.0
-floor(x) 返回数字的下舍整数,如math.floor(4.9)返回 4
-log(x) 如math.log(math.e)返回1.0,math.log(100,10)返回2.0
-log10(x) 返回以10为基数的x的对数,如math.log10(100)返回 2.0
-max(x1, x2,...) 返回给定参数的最大值,参数可以为序列
-min(x1, x2,...) 返回给定参数的最小值,参数可以为序列
-modf(x) 返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示
-pow(x, y) x**y 运算后的值。
-round(x [,n]) 返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数
-sqrt(x) 返回数字x的平方根,数字可以为负数,返回类型为实数,如math.sqrt(4)返回 2+0j
-```
\ No newline at end of file
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/03-\345\255\227\347\254\246\344\270\262.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/03-\345\255\227\347\254\246\344\270\262.md"
deleted file mode 100644
index 8167a2f2d..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/03-\345\255\227\347\254\246\344\270\262.md"
+++ /dev/null
@@ -1,471 +0,0 @@
-# Attack on Python - 字符串 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-字符串是 `Python` 中最基本的数据类型之一 , 它是一个定长对象 , 这意味着它的一旦创建 , 再也无法改变长度
-
-所以关于字符串的操作 , 都会返回一个新的字符串 , 而无法在原来的字符串上直接操作
-
-字符串的使用需要用引号括起来 , 例如 : `name = "Lyon"` ; 这里name就是一个变量名 , 而引号里面的`Lyon` 则就是该变量绑定的值 , 该值的类型为 " str" 类型 , 我们可以利用`type()` 函数进行查看 :
-
-```python
->>> name = "Lyon"
->>> type(name)
-
->>>
-```
-
-这就是字符串类型 , 当然如上使用的是双引号 , 这里其实还可以使用单引号`'Lyon'`以及三引号`'''Lyon'''`(或者是`"""Lyon"""` , 单引号双引号都可以) , 不过对于三引号 , 我们通常是表示多行字符串 , 这样我们就不需要利用 " \n " (换行符)来进行每一行的换行了
-
-对于嵌套引号的时候要注意 , 需要用不同的引号来避免歧义 , 比如 : `'I am "Lyon"'` , 也可以 `"I am 'Lyon'"`
-
-对于所有的基本数据类型 , 我们都应该熟悉其特性以及操作
-
-字符串操作主要有 **拷贝、拼接、查找、比较、统计、切片、测试、大小写等**
-
-## 拷贝
-
-```python
->>> a = "Lyon"
->>> b = a
->>> print(a,b)
-Lyon Lyon
-```
-
-## 拼接
-
-```python
->>> a = "Hello"
->>> b = "Lyon"
->>> print(a + b)
-HelloLyon
-```
-
-小 `Tips` : 由于字符串是定长对象 , 这就导致我们如果做 `+` 运算 , 两两相加都会生成一个新的字符串 , 于是如果你这样操作 `a + a + a + a + a` 除了最后的结果 , 在内存中还会创建 3 个在运算过程中需要的字符串 , 所以如果拼接操作过多 , 我们正确的方式应该是使用 `''.join(list())` , 也就是通过 `join` 方法
-
-```python
->>> a = "Lyon"
->>> b = "Hello"
->>> print(a.join(b))
-HLyoneLyonlLyonlLyono #HLyon eLyon lLyon lLyon o
-```
-
-## 查找
-
-```python
->>> name = "Lyon"
-# 返回L字符所在的下标,下标是从0开始的整数
->>> name.index('L')
-0
-# 如果不存在就会报错
->>> name.index('N')
-Traceback (most recent call last):
- File "", line 1, in
-ValueError: substring not found
-# 也可以用in,not in来进行判断
->>>'L' in name
->>>
-```
-
-## 比较
-
-本来 `Python 2` 中有个 `str.cmp()` 方法来比较两个对象 , 并根据结果返回一个整数 , 整数的正负就是数值的大小了 , 但是在 `Python 3` 中就没有这个方法了 , 官方文档如下 :
-
-```The cmp() function should be treated as gone, and the __cmp__() special method is no longer supported. Use __lt__() for sorting, __eq__() with __hash__(), and other rich comparisons as needed. (If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a, b).)
-The cmp() function should be treated as gone, and the __cmp__() special method is no longer supported. Use __lt__() for sorting, __eq__() with __hash__(), and other rich comparisons as needed. (If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a, b).)
-```
-
-大致的意思就是cmp()函数已经走了 , 如果你真的需要cmp函数 , 你可以用表达式`(a>b)-(a>> a = "100"
->>> b = "50"
->>> cmp(a,b) # a>b 负数
--1
->>> cmp(b,a) # b>> name = "Lyon"
- # name中"L"的个数
->>> name.count("L")
-1
-```
-
-## 切片
-
-```python
->>> name = "i like Lyon"
-# 切取第7个到第9个字符,注意空格也是一个字符
->>> name[7:10]
-'Lyo'
->>> name = "i like Lyon"
-# 第7到第10各,顾头不顾尾
->>> name[7:11]
-'Lyon'
-```
-
-## 检测
-
-```python
->>> name = "Lyon"
-# 检测"L"是否在name中,返回bool值
->>> "L" in name
-True
->>> num = "3412313"
-# 检测num里面是否全都是整数
->>> num.isdigit()
-True
->>> name = "Lyon"
-# 检测name是否可以被当作标标志符,即是否符合变量命名规则
->>> name.isidentifier()
-True
-# 检测name里面有没有"L",有就返回下标
->>> name.find('L')
-0
-# 检测name里面有没有"N",没有就返回-1
->>> name.find('N')
--1
-```
-
-检测相关
-
-```python
-str.startswith(prefix[,start[,end]]) # 是否以prefix开头
-str.endswith(suffix[,start[,end]]) # 以suffix结尾
-str.isalnum() # 是否全是字母和数字,并至少有一个字符
-str.isalpha() # 是否全是字母,并至少有一个字符
-str.isdigit() # 是否全是数字,并至少有一个字符
-str.isspace() # 是否全是空白字符,并至少有一个字符
-str.islower() # 是否全是小写
-str.isupper() # 是否便是大写
-str.istitle() # 是否是首字母大写的
-```
-
-注 : 返回值全为 `bool` 值
-
-## 大小写
-
-```python
->>> name = "I am Lyon"
-# 大小写互换
->>> name.swapcase()
-'i AM lYON'
-# 首字母大写,其它都小写
->>> name.capitalize()
-'I am lyon'
-# 转换为大写
->>> name.upper()
-'I AM LYON'
-# 转换为小写
->>> name.lower()
-'i am lyon'
-```
-
-## 更多
-
-```python
- | capitalize(...)
- | S.capitalize() -> str
- |
- | Return a capitalized version of S, i.e. make the first character
- | have upper case and the rest lower case.
- |
- | casefold(...)
- | S.casefold() -> str
- |
- | Return a version of S suitable for caseless comparisons.
- |
- | center(...)
- | S.center(width[, fillchar]) -> str
- |
- | Return S centered in a string of length width. Padding is
- | done using the specified fill character (default is a space)
- |
- | count(...)
- | S.count(sub[, start[, end]]) -> int
- |
- | Return the number of non-overlapping occurrences of substring sub in
- | string S[start:end]. Optional arguments start and end are
- | interpreted as in slice notation.
- |
- | encode(...)
- | S.encode(encoding='utf-8', errors='strict') -> bytes
- |
- | Encode S using the codec registered for encoding. Default encoding
- | is 'utf-8'. errors may be given to set a different error
- | handling scheme. Default is 'strict' meaning that encoding errors raise
- | a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and
- | 'xmlcharrefreplace' as well as any other name registered with
- | codecs.register_error that can handle UnicodeEncodeErrors.
- |
- | endswith(...)
- | S.endswith(suffix[, start[, end]]) -> bool
- |
- | Return True if S ends with the specified suffix, False otherwise.
- | With optional start, test S beginning at that position.
- | With optional end, stop comparing S at that position.
- | suffix can also be a tuple of strings to try.
- |
- | expandtabs(...)
- | S.expandtabs(tabsize=8) -> str
- |
- | Return a copy of S where all tab characters are expanded using spaces.
- | If tabsize is not given, a tab size of 8 characters is assumed.
- |
- | find(...)
- | S.find(sub[, start[, end]]) -> int
- |
- | Return the lowest index in S where substring sub is found,
- | such that sub is contained within S[start:end]. Optional
- | arguments start and end are interpreted as in slice notation.
- |
- | Return -1 on failure.
- |
- | format(...)
- | S.format(*args, **kwargs) -> str
- |
- | Return a formatted version of S, using substitutions from args and kwargs.
- | The substitutions are identified by braces ('{' and '}').
- |
- | format_map(...)
- | S.format_map(mapping) -> str
- |
- | Return a formatted version of S, using substitutions from mapping.
- | The substitutions are identified by braces ('{' and '}').
- |
- | index(...)
- | S.index(sub[, start[, end]]) -> int
- |
- | Like S.find() but raise ValueError when the substring is not found.
- |
- | isalnum(...)
- | S.isalnum() -> bool
- |
- | Return True if all characters in S are alphanumeric
- | and there is at least one character in S, False otherwise.
- |
- | isalpha(...)
- | S.isalpha() -> bool
- |
- | Return True if all characters in S are alphabetic
- | and there is at least one character in S, False otherwise.
- |
- | isdecimal(...)
- | S.isdecimal() -> bool
- |
- | Return True if there are only decimal characters in S,
- | False otherwise.
- |
- | isdigit(...)
- | S.isdigit() -> bool
- |
- | Return True if all characters in S are digits
- | and there is at least one character in S, False otherwise.
- |
- | isidentifier(...)
- | S.isidentifier() -> bool
- |
- | Return True if S is a valid identifier according
- | to the language definition.
- |
- | Use keyword.iskeyword() to test for reserved identifiers
- | such as "def" and "class".
- |
- | islower(...)
- | S.islower() -> bool
- |
- | Return True if all cased characters in S are lowercase and there is
- | at least one cased character in S, False otherwise.
- |
- | isnumeric(...)
- | S.isnumeric() -> bool
- |
- | Return True if there are only numeric characters in S,
- | False otherwise.
- |
- | isprintable(...)
- | S.isprintable() -> bool
- |
- | Return True if all characters in S are considered
- | printable in repr() or S is empty, False otherwise.
- |
- | isspace(...)
- | S.isspace() -> bool
- |
- | Return True if all characters in S are whitespace
- | and there is at least one character in S, False otherwise.
- |
- | istitle(...)
- | S.istitle() -> bool
- |
- | Return True if S is a titlecased string and there is at least one
- | character in S, i.e. upper- and titlecase characters may only
- | follow uncased characters and lowercase characters only cased ones.
- | Return False otherwise.
- |
- | isupper(...)
- | S.isupper() -> bool
- |
- | Return True if all cased characters in S are uppercase and there is
- | at least one cased character in S, False otherwise.
- |
- | join(...)
- | S.join(iterable) -> str
- |
- | Return a string which is the concatenation of the strings in the
- | iterable. The separator between elements is S.
- |
- | ljust(...)
- | S.ljust(width[, fillchar]) -> str
- |
- | Return S left-justified in a Unicode string of length width. Padding is
- | done using the specified fill character (default is a space).
- |
- | lower(...)
- | S.lower() -> str
- |
- | Return a copy of the string S converted to lowercase.
- |
- | lstrip(...)
- | S.lstrip([chars]) -> str
- |
- | Return a copy of the string S with leading whitespace removed.
- | If chars is given and not None, remove characters in chars instead.
- |
- | partition(...)
- | S.partition(sep) -> (head, sep, tail)
- |
- | Search for the separator sep in S, and return the part before it,
- | the separator itself, and the part after it. If the separator is not
- | found, return S and two empty strings.
- |
- | replace(...)
- | S.replace(old, new[, count]) -> str
- |
- | Return a copy of S with all occurrences of substring
- | old replaced by new. If the optional argument count is
- | given, only the first count occurrences are replaced.
- |
- | rfind(...)
- | S.rfind(sub[, start[, end]]) -> int
- |
- | Return the highest index in S where substring sub is found,
- | such that sub is contained within S[start:end]. Optional
- | arguments start and end are interpreted as in slice notation.
- |
- | Return -1 on failure.
- |
- | rindex(...)
- | S.rindex(sub[, start[, end]]) -> int
- |
- | Like S.rfind() but raise ValueError when the substring is not found.
- |
- | rjust(...)
- | S.rjust(width[, fillchar]) -> str
- |
- | Return S right-justified in a string of length width. Padding is
- | done using the specified fill character (default is a space).
- |
- | rpartition(...)
- | S.rpartition(sep) -> (head, sep, tail)
- |
- | Search for the separator sep in S, starting at the end of S, and return
- | the part before it, the separator itself, and the part after it. If the
- | separator is not found, return two empty strings and S.
- |
- | rsplit(...)
- | S.rsplit(sep=None, maxsplit=-1) -> list of strings
- |
- | Return a list of the words in S, using sep as the
- | delimiter string, starting at the end of the string and
- | working to the front. If maxsplit is given, at most maxsplit
- | splits are done. If sep is not specified, any whitespace string
- | is a separator.
- |
- | rstrip(...)
- | S.rstrip([chars]) -> str
- |
- | Return a copy of the string S with trailing whitespace removed.
- | If chars is given and not None, remove characters in chars instead.
- |
- | split(...)
- | S.split(sep=None, maxsplit=-1) -> list of strings
- |
- | Return a list of the words in S, using sep as the
- | delimiter string. If maxsplit is given, at most maxsplit
- | splits are done. If sep is not specified or is None, any
- | whitespace string is a separator and empty strings are
- | removed from the result.
- |
- | splitlines(...)
- | S.splitlines([keepends]) -> list of strings
- |
- | Return a list of the lines in S, breaking at line boundaries.
- | Line breaks are not included in the resulting list unless keepends
- | is given and true.
- |
- | startswith(...)
- | S.startswith(prefix[, start[, end]]) -> bool
- |
- | Return True if S starts with the specified prefix, False otherwise.
- | With optional start, test S beginning at that position.
- | With optional end, stop comparing S at that position.
- | prefix can also be a tuple of strings to try.
- |
- | strip(...)
- | S.strip([chars]) -> str
- |
- | Return a copy of the string S with leading and trailing
- | whitespace removed.
- | If chars is given and not None, remove characters in chars instead.
- |
- | swapcase(...)
- | S.swapcase() -> str
- |
- | Return a copy of S with uppercase characters converted to lowercase
- | and vice versa.
- |
- | title(...)
- | S.title() -> str
- |
- | Return a titlecased version of S, i.e. words start with title case
- | characters, all remaining cased characters have lower case.
- |
- | translate(...)
- | S.translate(table) -> str
- |
- | Return a copy of the string S in which each character has been mapped
- | through the given translation table. The table must implement
- | lookup/indexing via __getitem__, for instance a dictionary or list,
- | mapping Unicode ordinals to Unicode ordinals, strings, or None. If
- | this operation raises LookupError, the character is left untouched.
- | Characters mapped to None are deleted.
- |
- | upper(...)
- | S.upper() -> str
- |
- | Return a copy of S converted to uppercase.
- |
- | zfill(...)
- | S.zfill(width) -> str
- |
- | Pad a numeric string S with zeros on the left, to fill a field
- | of the specified width. The string S is never truncated.
- |
- | ----------------------------------------------------------------------
-```
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/04-\345\205\203\347\273\204.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/04-\345\205\203\347\273\204.md"
deleted file mode 100644
index 770313825..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/04-\345\205\203\347\273\204.md"
+++ /dev/null
@@ -1,155 +0,0 @@
-# Attack on Python - 元组 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-元组和字符串一样 , 也是定长对象
-
-元组的创建很简单 , 只需要在括号中添加元素 , 并使用逗号隔开即可
-
-## 创建
-
-```python
-# 创建一个带有元素的元组
-mytuple = ("Lyon", "Alex", "Leon", 1, 2, 3)
-# 也可以不加括号,但是一定要加引号
-mytuple = "Lyon", "Alex", "Leon", 1, 2, 3
-# 创建一个空元组
-mytuple = ()
-# 当元组中只有一个元素,加逗号来消除歧义哟,这是一个好习惯,因为()既可以表示tuple又可以表示数学公式中的小括号
-only_one = ("Lyon",)
-```
-
-## 访问
-
-```python
-# 创建一个元组
-names = ("Lyon", "Alex", "Leon", 1, 2, 3)
-# 访问元组中的第一个元素并打印结果,下标索也是从0开始
-print(names[0])
-# 访问元组中第一和第二个元素并打印结果
-print(names[0:2])
-'''
-打印结果:
-Lyon
-('Lyon', 'Alex')
-'''
-```
-
-## 修改
-
-```python
-# 创建一个元组
-tuple_name = ("Lyon", "Alex", "Leon", 1, 2, 3)
-# 创建另一个元组
-tuple_num = (1, 2, 3, 4, 5)
-# 生成一个新的元组
-tuple_total = tuple_name + tuple_num
-# 打印tuple_total
-print(tuple_total)
-# 复制元组内元素一次
-tuple_total = tuple_name * 2
-# 打印tuple_total看结果
-print(tuple_total)
-# 在列表中可以通过索引取值后进行修改,但是元组里面是非法的哦
-tuple_name[0] = "lyon" # 这里直接就报错
-'''
-打印结果:
-('Lyon', 'Alex', 'Leon', 1, 2, 3, 1, 2, 3, 4, 5)
-('Lyon', 'Alex', 'Leon', 1, 2, 3, 'Lyon', 'Alex', 'Leon', 1, 2, 3)
-'''
-```
-
-注意 : 元组是不可变的 , 所以对于所有的修改操作 , 都是在根据原元组生成了一个新的元组
-
-## 删除
-
-```python
-#创建一个元组
-names = ("Lyon", "Alex", "Leon", 1, 2, 3)
-# 删除元组names
-del names
-# TypeError: 'tuple' object doesn't support item deletion
-del names[0]
-```
-
-## 切片
-
-```python
-names = ("Lyon", "Kenneth", "Leon", "Charlie")
-# 打印子集,第二个至第三个
-print(names[1:2])
-# 打印子集,倒数第三个(即第二个)至第三个
-print(names[-3:3])
-# 打印子集,第一个至第三个,隔一个取一个
-print(names[0:2:1])
-'''
-打印结果:
-('Kenneth', 'Leon')
-('Kenneth', 'Leon')
-('Leon',)
-'''
-```
-
-## 检测
-
-```python
-# 创建一个元组
-tuple_name = ("Lyon","Alex","Leon",1,2,3)
-# "Lyon"是否在tuple_name中,打印结果
-print("Lyon" in tuple_name)
-# 打印结果:True
-```
-
-## 更多
-
-实例
-
-```python
-# 创建一个元组
-tuple_name = ("Lyon","Alex","Leon",1,2,3)
-# 计算元组长度
-tuple_len = len(tuple_name)
-# 打印结果
-print(tuple_len)
-# 创建一个元素全为数字的元组
-tuple_num = (1,2,3,4,5)
-# 返回元组中的最大值
-print(max(tuple_num))
-# 返回元组中的最小值
-print(min(tuple_num))
-# 创建一个列表
-list_name = ["Lyon","Alex","Leon"]
-# 将列表转换为元组
-tuple_names = tuple(list_name)
-# 打印tuple_names
-print(tuple_names)
-'''
-打印结果:
-6
-5
-1
-('Lyon', 'Alex', 'Leon')
-'''
-```
-
-方法
-
-```python
- | count(...)
- | T.count(value) -> integer -- return number of occurrences of value
- |
- | index(...)
- | T.index(value, [start, [stop]]) -> integer -- return first index of value.
- | Raises ValueError if the value is not present.
-```
\ No newline at end of file
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/05-\345\210\227\350\241\250.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/05-\345\210\227\350\241\250.md"
deleted file mode 100644
index 99c253b94..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/05-\345\210\227\350\241\250.md"
+++ /dev/null
@@ -1,301 +0,0 @@
-# Attack on Python - 列表 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-列表是我们以后最常用的数据类型之一 , 通过列表可以对数据实现最方便的存储、修改等操作
-
-列表是变长对象 , 且列表是有序的
-
-列表相当于其他语言中的数组
-
-## 创建
-
-```python
-# 创建一个列表
-names = ["Alex","Lyon","Leon"]
-# 创建一个空列表
-names = []
-# 也可通过list方法
-names = list()
-```
-
-## 访问
-
-```python
-# 创建一个列表
-names = ["Alex","Lyon","Leon"]
-# 与字符串的索引一样,列表索引从0开始,访问列表中的第一个元素
-fristname = names[0]
-# 打印结果
-print(fristname)
-# 访问列表中第三个元素
-threename = names[2]
-# 打印结果
-print(threename)
-# 访问列表中最后一个元素
-endname = names[-1]
-# 打印结果
-print(endname)
-# 访问倒数第二个元素
-penultimate = names[-2]
-# 打印结果
-print(penultimate)
-'''
-执行结果:
-Alex
-Leon
-Leon
-Lyon
-'''
-```
-
-**获取下标**
-
-```python
-# 创建一个列表
-names = ['Alex', 'Lyon', 'Leon', 'CTO','Lyon']
-# 获取下标并打印
-print(names.index('Lyon'))
-# 注:只返回找到的第一个下标
-'''
-执行结果:
-1
-'''
-```
-
-**统计**
-
-```python
-# 创建一个列表
-names = ['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing',"IT",21,"man"]
-# 统计 "Lyon" 的个数,并打印
-print(names.count("Lyon"))
-'''
-执行结果:
-1
-'''
-```
-
-## 切片
-
-```python
-# 创建一个列表
-names = ["Alex","Lyon","Leon","CTO","WuHan"]
-# 取下标为1至下标3之间的值,包括1,不包括4
-cutnames1 = names[1:3]
-# 打印cutnames1
-print(cutnames1)
-# 取下标为1至-1的值,不包括-1(-1就是最后一个)
-cutnames2 = names[1:-1]
-# 打印cutnames2
-print(cutnames2)
-# 从第一个到第三个
-cutnames3 = names[0:3]
-# 从头开始取,0可以省略,跟上面的效果一样
-cutnames4 = names[:3]
-# 打印cutnames3,cutnames4
-print(cutnames3,cutnames4)
-# 想取最后一个,只能这样写,切片是不包含后一个参数的
-cutnames5 = names[3:]
-# 后面的2是代表,每隔一个元素,就取一个
-cutnames6 = names[0::2]
-# 或者这样
-cutnames7 = names[::2]
-# 打印cutnames6,cutnames7
-print(cutnames6,cutnames7)
-'''
-执行结果:
-['Lyon', 'Leon']
-['Lyon', 'Leon', 'CTO']
-['Alex', 'Lyon', 'Leon'] ['Alex', 'Lyon', 'Leon']
-['Alex', 'Leon', 'WuHan'] ['Alex', 'Leon', 'WuHan']
-'''
-```
-
-## 追加
-
-```python
-# 创建一个列表
-names = ["Alex","Lyon","Leon","CTO","WuHan"]
-# 追加一个元素
-names.append("New")
-# 打印names
-print(names)
-# 注:append 方法只能追加到列表的最后一位
-'''
-执行结果:
-['Alex', 'Lyon', 'Leon', 'CTO', 'WuHan', 'New']
-'''
-```
-
-## 插入
-
-```python
-# 创建一个列表
-names = ["Alex","Lyon","Leon","CTO","WuHan","New"]
-# 插入到下标1前面
-names.insert(1,"Insert")
-# 打印names
-print(names)
-# 如果下标不存在就会插入到最后一个
-names.insert(7,"NoIndex")
-# 打印names
-print(names)
-'''
-执行结果:
-['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'WuHan', 'New']
-['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'WuHan', 'New', 'NoIndex']
-'''
-```
-
-## 修改
-
-```python
-# 创建一个列表
-names = ['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'WuHan', 'New', 'NoIndex']
-# 把 'WuHan' 改成 'BeiJing'
-names[5] = 'BeiJing'
-# 打印names
-print(names)
-# 注:就是通过下标直接改变list本身
-'''
-执行结果:
-['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'New', 'NoIndex']
-'''
-```
-
-## 删除
-
-```python
-# 创建一个列表
-names = ['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'New', 'NoIndex']
-# 删除下标为7的元素
-del names[7]
-#打印names
-print(names)
-# 删除 'Insert',remove删除指定元素
-names.remove("Insert")
-# 打印names
-print(names)
-# 删除最后一个元素
-names.pop()
-# 打印names
-print(names)
-'''
-执行结果:
-['Alex', 'Insert', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'New']
-['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'New']
-['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing']
-'''
-```
-
-## 扩展
-
-```python
-# 创建一个列表
-names = ['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing']
-# 创建另一个列表
-name = ["IT",21,"man"]
-# 将name扩展到names
-names.extend(name)
-# 打印names
-print(names)
-# 这里还有一个"万恶的'+' "也是可以的
-print(names + name)
-'''
-执行结果:
-['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'IT', 21, 'man']
-['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'IT', 21, 'man']
-'''
-```
-
-## 拷贝
-
-```python
-# 创建一个列表
-names = ['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing',"IT",21,"man"]
-# 拷贝names,这只是浅copy
-names_copy = names.copy()
-# 打印names_copy
-print(names_copy)
-'''
-执行结果:
-['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing', 'IT', 21, 'man']
-'''
-```
-
-注意 : 在 `Python 2.7` 中列表的内置方法是没有 `copy` 这个方法的 , 这是在 `Python 3` 后加的 , 并且 `Python 3`也只有有 `copy (浅copy)` 这一个方法 , 用深 `copy` 需要我们导入 `copy` 模块 , 即 `import copy`
-
-## 排序&翻转
-
-```python
-# 创建一个列表
-names = ['Alex', 'Lyon', 'Leon', 'CTO', 'BeiJing',"IT",21,"man"]
-# 在python3中不同的数据类型不能一起排序,换成str
-names[-2] = "21"
-# 排序,顺序为数字>大写>小写
-names.sort()
-# 打印names
-print(names)
-# 翻转
-names.reverse()
-# 打印names
-print(names)
-'''
-执行结果:
-['21', 'Alex', 'BeiJing', 'CTO', 'IT', 'Leon', 'Lyon', 'man']
-['man', 'Lyon', 'Leon', 'IT', 'CTO', 'BeiJing', 'Alex', '21']
-'''
-```
-
-所有方法如下 :
-
-```python
- | append(...)
- | L.append(object) -> None -- append object to end
- |
- | clear(...)
- | L.clear() -> None -- remove all items from L
- |
- | copy(...)
- | L.copy() -> list -- a shallow copy of L
- |
- | count(...)
- | L.count(value) -> integer -- return number of occurrences of value
- |
- | extend(...)
- | L.extend(iterable) -> None -- extend list by appending elements from the iterable
- |
- | index(...)
- | L.index(value, [start, [stop]]) -> integer -- return first index of value.
- | Raises ValueError if the value is not present.
- |
- | insert(...)
- | L.insert(index, object) -- insert object before index
- |
- | pop(...)
- | L.pop([index]) -> item -- remove and return item at index (default last).
- | Raises IndexError if list is empty or index is out of range.
- |
- | remove(...)
- | L.remove(value) -> None -- remove first occurrence of value.
- | Raises ValueError if the value is not present.
- |
- | reverse(...)
- | L.reverse() -- reverse *IN PLACE*
- |
- | sort(...)
- | L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
-```
-
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/06-\345\255\227\345\205\270.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/06-\345\255\227\345\205\270.md"
deleted file mode 100644
index a273a0a78..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/06-\345\255\227\345\205\270.md"
+++ /dev/null
@@ -1,227 +0,0 @@
-# Attack on Python - 字典 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-字典是一种 `key - value` 的数据类型 , 用 冒号 `" : "` 来关联键值对 , 每个对象之间用逗号 `" , "` 分割 , 整个字典包括在花括号 `"{ }"` 中
-
-字典中的键(key)是唯一的 , 但值(value)则不必
-
-字典是变长对象 , 在 `Python 3.5` 之前字典是无序的 , 但是在 `3.6` 之后官方就已经改成有序的了 , 所以在使用时需要注意一下
-
-注意 : `key` 是不可变的 , 所以可变对象无法作为字典的 `key` , 如 : `list` , 对于不可变的数据类型则可以 , 如 : `str`、`int`、`tuple`
-
-## 创建
-
-```python
-# 创建一个空字典
-empty_info = {}
-# 创建一个字典
-info = {"name":"Lyon","age":21}
-# 也可调用dict()方法
-info = dict()
-```
-
-## 增加
-
-```python
-# 创建一个字典
-info = {"name":"Lyon","age":21}
-# 增加新的键/值对
-info["school"] = "university"
-# 打印info
-print(info)
-# 注:字典是无序的,所以打印结果也是随机打印
-'''
-执行结果:
-{'school': 'university', 'age': 21, 'name': 'Lyon'}
-'''
-```
-
-## 修改
-
-```python
-# 创建一个字典
-info = {"name":"Lyon","age":21,"school":"university"}
-# 修改age
-info["age"] = 18
-# 打印info
-print(info)
-'''
-执行结果:
-{'age': 18, 'school': 'university', 'name': 'Lyon'}
-'''
-```
-
-## 删除
-
-```python
-# 创建一个字典
-info = {"name":"Lyon","age":21,"school":"university"}
-# 标准删除姿势
-info.pop("school")
-# 打印info
-print(info)
-# 换个姿势
-del info["age"]
-# 打印info
-print(info)
-# 随机删除
-info.popitem()
-# 打印info
-print(info)
-'''
-执行结果:
-{'name': 'Lyon', 'age': 21}
-{'name': 'Lyon'}
-{}
-'''
-```
-
-## 查找
-
-```python
-# 创建一个字典
-info = {"name":"Lyon","age":21,"school":"university"}
-# 标准查找,判断name是否在字典info中
-print("name" in info) #打印:True
-# 获取值
-print(info.get("name")) #打印:Lyon
-# 换换姿势
-print(info["name"]) #打印:Lyon
-# 这种方式要注意如果key不存在就会报错,而get仅仅返回None
-print(info["home"])
-# 报错:KeyError: 'home'
-'''
-执行结果:
-True
-Lyon
-Lyon
-KeyError:'home'
-'''
-```
-
-## 遍历
-
-```python
-# 创建一个字典
-info = {"name":"Lyon","age":21,"school":"university"}
-# 方法1,推荐
-for key in info:
- print(key,info[key])
-# 方法2
-for k,v in info.items():
- print(k,v)
-'''
-执行结果:
-school university
-name Lyon
-age 21
-school university
-name Lyon
-age 21
-'''
-```
-
-## 嵌套
-
-```python
-# 创建一个多级嵌套字典
-datas ={
- '湖北省':{
- "武汉市":{
- "武昌区":["Hello"],
- "洪山区":["Sorry"],
- "江夏区":["Welcome"],
- },
- },
- '湖南省':{
- "长沙市":{
- "岳麓区":{},
- "天心区":{},
- "芙蓉区":{},
- },
- },
- '广东省':{
- "佛山市":{
- "三水区":{},
- "顺德区":{},
- "男海区":{},
- },
- },
-}
-# 修改最里层的value
-datas["湖北省"]["武汉市"]["武昌区"].append("Lyon")
-# 打印结果
-print(datas["湖北省"]["武汉市"])
-'''
-执行结果:
-{'洪山区': ['Sorry'], '武昌区': ['Hello', 'Lyon'], '江夏区': ['Welcome']}
-'''
-```
-
-## 更多
-
-```python
-len(dict) # 计算字典元素个数
-dict.clear() # 清空词典所有条目
-dict.fromkeys(seq, val)) # 创建一个新字典,以列表 seq 中元素做字典的键,val 为字典所有键对应的初始值
-dict.has_key(key) # 如果键在字典dict里返回true,否则返回false
-dict.items() # 以列表返回可遍历的(键, 值) 元组数组
-dict.keys() # 以列表返回一个字典所有的键
-dict.values() # 以列表返回字典中的所有值
-dict.setdefault(key, default=None) # 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
-dict.update(dict2) # 把字典dict2的键/值对更新到dict里
-```
-方法合集
-
-```python
- | clear(...)
- | D.clear() -> None. Remove all items from D.
- |
- | copy(...)
- | D.copy() -> a shallow copy of D
- |
- | fromkeys(iterable, value=None, /) from builtins.type
- | Returns a new dict with keys from iterable and values equal to value.
- |
- | get(...)
- | D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
- |
- | items(...)
- | D.items() -> a set-like object providing a view on D's items
- |
- | keys(...)
- | D.keys() -> a set-like object providing a view on D's keys
- |
- | pop(...)
- | D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
- | If key is not found, d is returned if given, otherwise KeyError is raised
- |
- | popitem(...)
- | D.popitem() -> (k, v), remove and return some (key, value) pair as a
- | 2-tuple; but raise KeyError if D is empty.
- |
- | setdefault(...)
- | D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
- |
- | update(...)
- | D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
- | If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]
- | If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v
- | In either case, this is followed by: for k in F: D[k] = F[k]
- |
- | values(...)
- | D.values() -> an object providing a view on D's values
-```
-
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/07-\351\233\206\345\220\210.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/07-\351\233\206\345\220\210.md"
deleted file mode 100644
index 9689cc9d2..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/07-\351\233\206\345\220\210.md"
+++ /dev/null
@@ -1,181 +0,0 @@
-# Attack on Python - 集合 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-集合是变长对象 , 集合是无序且不重复的数据组合 , 因此我们可以用来做 :
-
-- 去重 , 把一个列表变成集合 , 就自动去重了
-- 集合运算 , 求两个集合的并集 , 交集 , 差集 , 对称差集
-
-在 `Python 2.7` 中集合表示如下 :
-
-```python
-set([1,2,3])
-```
-
-在 `Python 3.x` 中则是如下 :
-
-```python
-{1,2,3}
-```
-
-我们可以通过 `set()` 方法 , 将 `list` 和 `tuple` 转换为集合 : `set(list())` , `set(tuple())`
-
-## 创建
-
-与字符串等数据类型一样 , 集合支持如下方式创建
-
-```python
-# 创建空集合只能用这种方式,参数为一个可迭代对象
-s = set()
-# 注意集合是单个元素,字典是键值对
-s = {1,2,3}
-```
-
-## 添加
-
-为集合添加元素
-
-```python
-# 定义集合
-s = {'lyon','kenneth'}
-# 添加一项
-s.add('geek')
-```
-
-注意 : 集合不支持 "+"
-
-## 更新
-
-```python
-# 定义集合
-s = {'lyon','kenneth'}
-# 添加多项,参数为可迭代对象
-s.update(['1','2','3'])
-```
-
-## 删除
-
-```python
-# 定义集合
-s = {'lyon','kenneth'}
-# 删除一项
-s.remove('kenneth')
-# 清空集合
-s.clear()
-```
-
-## 关系运算
-
-```python
-a = {1,2,3,4,5}
-b = {1,2,3}
-# 测试是否b中的每一个元素都在a中,即 b<=a ,返回bool值
-b.issubset(a)
-# 测试是否a中的每一个元素都在b中,即 b>=a ,返回bool值
-b.issuperset(a)
-```
-
-## 集合操作
-
-```python
->>>a = {1,2,3}
->>>b = {4,5,6}
-# 求并集
->>>a.union(b)
-# 同上,求并集
->>>a | b
-# 求交集
->>>a.intersection(b)
-# 同上,求交集
->>>a & b
-# 求差集
->>>a.difference(b)
-# 同上,求差集
->>>a - b
-# 求对称差集
->>>a.symmetric_difference(b)
-# 同上,求对称差集
->>>a ^ b
-```
-
-集合对象所有方法
-
-```python
- | add(...)
- | Add an element to a set.
- |
- | This has no effect if the element is already present.
- |
- | clear(...)
- | Remove all elements from this set.
- |
- | copy(...)
- | Return a shallow copy of a set.
- |
- | difference(...)
- | Return the difference of two or more sets as a new set.
- |
- | (i.e. all elements that are in this set but not the others.)
- |
- | difference_update(...)
- | Remove all elements of another set from this set.
- |
- | discard(...)
- | Remove an element from a set if it is a member.
- |
- | If the element is not a member, do nothing.
- |
- | intersection(...)
- | Return the intersection of two sets as a new set.
- |
- | (i.e. all elements that are in both sets.)
- |
- | intersection_update(...)
- | Update a set with the intersection of itself and another.
- |
- | isdisjoint(...)
- | Return True if two sets have a null intersection.
- |
- | issubset(...)
- | Report whether another set contains this set.
- |
- | issuperset(...)
- | Report whether this set contains another set.
- |
- | pop(...)
- | Remove and return an arbitrary set element.
- | Raises KeyError if the set is empty.
- |
- | remove(...)
- | Remove an element from a set; it must be a member.
- |
- | If the element is not a member, raise a KeyError.
- |
- | symmetric_difference(...)
- | Return the symmetric difference of two sets as a new set.
- |
- | (i.e. all elements that are in exactly one of the sets.)
- |
- | symmetric_difference_update(...)
- | Update a set with the symmetric difference of itself and another.
- |
- | union(...)
- | Return the union of sets as a new set.
- |
- | (i.e. all elements that are in either set.)
- |
- | update(...)
- | Update a set with the union of itself and others.
-```
\ No newline at end of file
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/08-\345\255\227\347\254\246\347\274\226\347\240\201.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/08-\345\255\227\347\254\246\347\274\226\347\240\201.md"
deleted file mode 100644
index 1c65214ad..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/08-\345\255\227\347\254\246\347\274\226\347\240\201.md"
+++ /dev/null
@@ -1,127 +0,0 @@
-# Attack on Python - 字符编码 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-**字符编码**
-
-字符编码 (Character encoding) 也称字集码 , 它是一套**法则** , 使用该法则能够对自然语言的字符的一个集合 (如字母表或音节表) , 与其他东西的一个集合 (如号码或电脉冲) 进行配对 , 即在符号集合与数字系统之间建立对应关系
-
-再简单一点说其实就是一张具有对应关系的表格 , 如下
-
-```
-+----+-----------+
-| id | character |
-+----+-----------+
-| 65 | A |
-| 66 | B |
-| 67 | C |
-+----+-----------+
-```
-
-如上表所示 , 这就是一套法则 , 使我们用数字成功的表示了字符
-
-> *为什么要一套这样的法则 ?*
-
-众所周知 , 计算机只认识机器码 , 也就是一堆0101之类的二进制数字 , 计算机并不认识我们的 "A" , "B" ,"C" , 我们为了使其友好的显示 , 就需要一套这样的法则 , 来完成这些转换 , 于是两个名词诞生了
-
-**编码**
-
-通俗的说 , 就是按照何种规则将字符存储在计算机中 . 比如 "A" 用65表示 , 也就是把字符"A"以二进制的方式存储在计算机中
-
-**解码**
-
- 反之 , 将存储在计算机中的二进制数解析显示出来 , 这就是解码
-
-在Python中
-
-```python
-'''既然是对于字符,那么自然对应着Python中的字符串了'''
-'''Python中提供了两个函数来完成编码和解码'''
-# 编码函数encode()
-encode()
-character → byte
-# 解码函数decode()
-byte → character
-```
-
-**PS : 必须采用相对应的法则 , 否则就会出错 , 也就是我们常说的乱码**
-
-最后还有一个名词 , 字符集
-
-**字符集**
-
-是一个系统支持的所有抽象字符的集合 , 字符是各种文字和符号的总称 , 包括各国家文字、标点符号、图形符号、数字等
-
-字符编码就是在字符集与数字系统之间建立的对应关系
-
-## ASCII
-
-ASCII (American Standard Code for Information Interchange , 美国信息交换标准码) , 是基于拉丁字母的一套电脑编码系统 , 主要用于显示现代英语
-
-ASCII字符集 : 主要包括控制字符 (回车键 , 退格 , 换行键等) , 可显示字符 (英文大小写字符 , 阿拉伯数字和西文符号)
-
-ASCII编码 : 将ASCII字符集转换为计算机可以接收的数字系统的数的规则 , 使用7位(Bit)表示一个字符 , `1 Byte = 8 Bit` , 一共可以表示128(2的7次方)个字符
-
-具体ASCII字符集映射到数字编码规则可以自行查询
-
-## ANSI
-
-ANSI编码为在ASCII编码(7位)的基础上 , 将其最后一位也使用上 , 即使用8位
-
-ANSI使使计算机支持更多语言 , 通常对于没超过128的即用ASCII编码 , 超过的即用扩展的ASCII编码ANSI
-
-当然不同的国家和地区指定了不同的标准 , 由此产生了GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的编码标准
-
-在简体中文Windows操作系统中 , ANSI 编码代表 GBK 编码 ; 在繁体中文Windows操作系统中 , ANSI编码代表Big5 ; 在日文Windows操作系统中 , ANSI 编码代表 Shift_JIS 编码
-
-## GBXXX
-
-**GB2312编码**
-
-计算机发明之初及后面很长一段时间 , 只应用于美国及西方一些发达国家 , 于是到中国时 , 一个字节8位 , 256个字符是远远不能满足的 , 要想想中国有多少汉字 , 于是聪明的中国人这样规定 :
-
-**一个小于127的字符的意义与原来相同 , 但是两个大于127的字符连在一起时 , 就表示一个汉字** , 前面的一个字节称为高字节 , 后面的为低字节 , 这样就组合出了大约7000多个简体汉字了 , 这就是`GB2312` ,全称 `信息交换用汉字编码字符集 ▪ 基本集`
-
-**GB18030**
-
-由于7000多个汉字还是不够用 , 于是继续改进 , 每个汉字可以由1个 , 2个或4个字节组成 , 于是庞大的编码空间形成了 , 最多可以定义161万个字符 , 这就是`GB18030` , 全称 `信息技术中文编码字符集`
-
-## Unicode
-
-各种各样的字符编码都出来了 , 大家各用各的 , 那么问题就来了 , 一旦出现在网络上 , 由于不兼容 , 互相访问就出现了乱码现象 , 为了解决这个问题 , Unicode编码系统应运而生
-
-Unicode编码系统为表达任意语言的任意字符而设计 , 它使用2字节的数字来表达每个字母 , 符号 , 或者表意文字 , 每个数字代表唯一的至少在某种语言中使用的符号 (并不是所有的数字都用上了 , 但是总数已经超过了65535 所以2个字节的数字是不够用的)
-
-总而言之 , Unicode是业界的一种标准 , 也叫做统一码 , 万国码 , 单一码 , 标准万国码
-
-所以Unicode编码也成为了一个编码转换的基础 , 因为大家都支持他 , 从一种编码到另一中编码 , 只需要Unicode在中间搭桥就能简单的实现了
-
-**UTF - 8**
-
-对于Unicode来讲 , 任何字符都使用2个字节来存储 , 这明显是很浪费内存的 , 因为我们编写代码时 , 用到中文毕竟极少 , 所以为了节省内存 , 就有了`UTF-8` , UTF - 8规定 , 英文只使用1个字节 , 中文使用3个字节
-
-虽然说UTF - 8具有良好的国际兼容性 , 但中文需要比GBK/BIG5版本多占用50%的数据库存储空间 , 因此并不推荐使用
-
-## Python编码处理
-
-在Python3中 , 源代码读取进行语法校验时 , 会将源代码中的字符串从声明的编码转换成Unicode类型 , 等到语法校验通过后 , 再将这些字符换回初始的编码 , 这也就是说 , Python3中 , 字符串默认编码就是Unicode
-
-查看默认编码
-
-```python
->>> import sys
->>> sys.getdefaultencoding()
-```
-
-**PS : Windows下命令行的字符编码默认是GBK ; 并且Python2中 , 字符串是有两种类型的 , 这里不多说明**
\ No newline at end of file
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/09-\346\226\207\344\273\266\346\223\215\344\275\234.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/09-\346\226\207\344\273\266\346\223\215\344\275\234.md"
deleted file mode 100644
index 9acca1082..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/09-\346\226\207\344\273\266\346\223\215\344\275\234.md"
+++ /dev/null
@@ -1,272 +0,0 @@
-# Attack on Python - 文件操作 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-在磁盘上读写文件的功能都是由操作系统提供的 , 现代操作系统不允许普通的程序直接操作磁盘 , 所以 , 读写文件就是请求操作系统打开一个文件对象 (通常称为文件描述符) ; 然后 , 通过操作系统提供的接口从这个文件对象中读取数据 (读文件) , 或者把数据写入这个文件对象 (写文件)
-
-在Python中我们进行文件操作需要首先利用`open()` 函数获取一个文件流来操作文件
-
-这个流就是我们所使用的文件描述符 , 是一个I/O通道
-
-## open()
-
-```python
-open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
- """
- file:文件名
- mode:模式
- buffering:设置缓冲策略
- encoding:指定使用编码
- errors:指定处理编码和解码错误的方式
- newline:控制通用换行模式的工作方式(只适用文本模式)
- closefd:如果为False并且给出了文件描述符而不是文件名,则文件关闭时,文件描述符将保持打开;如果给定文件名,则closefd必须为True,否则将抛出异常
- opener:自定义开启器
- """
-```
-
-对于上述参数中 , 我们主要需要了解的就是`file` , `mode` , `encoding` 这三个
-
-对于mode , 有以下模式 :
-
-| Character | Meaning |
-| --------- | ---------------------------------------- |
-| `'r'` | open for reading (default) |
-| `'w'` | open for writing, truncating the file first |
-| `'x'` | open for exclusive creation, failing if the file already exists |
-| `'a'` | open for writing, appending to the end of the file if it exists |
-| `'b'` | binary mode |
-| `'t'` | text mode (default) |
-| `'+'` | open a disk file for updating (reading and writing) |
-| `'U'` | [universal newlines](https://docs.python.org/3.5/glossary.html#term-universal-newlines) mode (deprecated) |
-
-常使用的就是`'r'` , `'w'` , `'a'` , `'+'` , `'b'` , 当然还可以组合使用 , 下面进行详细介绍 :
-
-- r , 只读模式 , 文件必须已经存在
-- r+ , 可读可写模式 , 文件必须已经存在
-- w , 只写模式 , 会重新创建 , 意味着文件如果已存在会被空文件覆盖
-- w+ , 可写可读模式 , 同样会创建文件
-- a , 追写模式 , 文件不存在参考'w'
-- a+ , 追写并可读模式 , 文件不存在参考'w'
-- b , 以二进制的模式进行处理 (Linux可忽略 , Windows处理二进制文件时需标注) , 可以用该模式来读取图片 , 视频等等
- - rb , 同r
- - wb , 同w
- - ab , 同a
-
-简单实例
-
-file.txt
-
-```txt
-A man is not old until his regrets take place of his dreams.
-
-Nothing can help us endure dark times better than our faith.
-
-No one but ourselves can degrade us.
-```
-
-实例
-
-```python
-f = open('file.txt','r')
-contents = f.read
-print(contents)
-'''
-执行结果:
-A man is not old until his regrets take place of his dreams.
-
-Nothing can help us endure dark times better than our faith.
-
-No one but ourselves can degrade us.
-'''
-```
-
-## file-like object
-
-以下内容可以学习完模块篇之后再继续学习
-
-`io` 模块提供了Python处理各种类型I/O的主要工具 , 有三种主要类型 , 即`文本I/O` , `二进 制I/O`和`原始I/O` , 这些是通用类别 , 并且可以为它们中的每一个使用各种后备存储
-
-三种主要类型详细见 : [`TextIOBase`](https://docs.python.org/3.5/library/io.html?highlight=io#io.TextIOBase) , [`BufferedIOBase`](https://docs.python.org/3.5/library/io.html?highlight=io#io.BufferedIOBase) , [`RawIOBase`](https://docs.python.org/3.5/library/io.html?highlight=io#io.RawIOBase)
-
-属于这些类别中的任何一个的具体对象称为`file-like object`
-
-创建这些类别的具体对象最简单的方法就是使用内置的`open()` 函数 , 其也被定义在io模块中 , 下面仅介绍一些这些类别对象常用的方法 :
-
-```python
-detach()
-'''
-Separate the underlying binary buffer from the TextIOBase and return it.
-
-After the underlying buffer has been detached, the TextIOBase is in an unusable state.
-
-Some TextIOBase implementations, like StringIO,
- may not have the concept of an underlying buffer and calling this method will raise UnsupportedOperation.
-
-New in version 3.1.
-'''
-
-read(size)
-'''
-Read and return at most size characters from the stream as a single str.
-If size is negative or None, reads until EOF.
-'''
-
-readline(size=-1)
-'''
-Read until newline or EOF and return a single str.
-If the stream is already at EOF, an empty string is returned.
-
-If size is specified, at most size characters will be read.
-'''
-
-readlines(hint=-1)
-'''
-Read and return a list of lines from the stream. hint can be specified to control the number of lines read: no more lines will be read if the total size (in bytes/characters) of all lines so far exceeds hint.
-
-Note that it’s already possible to iterate on file objects using for line in file: ... without calling file.readlines().
-'''
-
-readable()
-'''
-Return True if the stream can be read from.
-If False, read() will raise OSError.
-'''
-
-write(s)
-'''
-Write the string s to the stream and return the number of characters written.
-'''
-
-writable()
-'''
-Return True if the stream supports writing.
-If False, write() and truncate() will raise OSError.
-'''
-
-writelines(lines)
-'''
-Write a list of lines to the stream.
-Line separators are not added,
-so it is usual for each of the lines provided to have a line separator at the end.
-'''
-
-seek(offset[, whence])
-'''
-Change the stream position to the given offset.
-Behaviour depends on the whence parameter.
-The default value for whence is SEEK_SET.
-
-SEEK_SET or 0: seek from the start of the stream (the default);
-offset must either be a number returned by TextIOBase.tell(), or zero.
-Any other offset value produces undefined behaviour.
-SEEK_CUR or 1: “seek” to the current position;
-offset must be zero, which is a no-operation (all other values are unsupported).
-SEEK_END or 2: seek to the end of the stream;
-offset must be zero (all other values are unsupported).
-Return the new absolute position as an opaque number.
-
-New in version 3.1: The SEEK_* constants.
-'''
-
-tell()
-'''
-Return the current stream position as an opaque number.
-The number does not usually represent a number of bytes in the underlying binary storage.
-'''
-
-close()
-'''
-Flush and close this stream.
-This method has no effect if the file is already closed.
-Once the file is closed,
-any operation on the file (e.g. reading or writing) will raise a ValueError.
-
-As a convenience, it is allowed to call this method more than once;
-only the first call, however, will have an effect.
-'''
-
-fileno()
-'''
-Return the underlying file descriptor (an integer) of the stream if it exists. An OSError is raised if the IO object does not use a file descriptor.
-'''
-
-flush()
-'''
-Flush the write buffers of the stream if applicable.
-This does nothing for read-only and non-blocking streams.
-'''
-
-isatty()
-'''
-Return True if the stream is interactive (i.e., connected to a terminal/tty device).
-'''
-
-seek(offset[, whence])
-'''
-Change the stream position to the given byte offset.
-offset is interpreted relative to the position indicated by whence.
-The default value for whence is SEEK_SET. Values for whence are:
-
-SEEK_SET or 0 – start of the stream (the default);
-offset should be zero or positive
-SEEK_CUR or 1 – current stream position;
-offset may be negative
-SEEK_END or 2 – end of the stream;
-offset is usually negative
-Return the new absolute position.
-
-New in version 3.1: The SEEK_* constants.
-
-New in version 3.3: Some operating systems could support additional values,
-like os.SEEK_HOLE or os.SEEK_DATA.
-The valid values for a file could depend on it being open in text or binary mode.
-'''
-
-seekable()
-'''
-Return True if the stream supports random access.
-If False, seek(), tell() and truncate() will raise OSError.
-'''
-
-truncate(size=None)
-'''
-Resize the stream to the given size in bytes (or the current position if size is not specified).
-The current stream position isn’t changed.
-This resizing can extend or reduce the current file size.
-In case of extension, the contents of the new file area depend on the platform (on most systems, additional bytes are zero-filled).
-The new file size is returned.
-
-Changed in version 3.5: Windows will now zero-fill files when extending.
-'''
-```
-
-注意 : 当使用完文件后一定要记得使用`close()` 方法将其关闭 ; 其次在进行文件操作时要注意文件描述符所在的位置
-
-## with
-
-为了避免打开文件后忘记手动关闭 , 可以通过管理上下文 , 即使用`with`语句 , 如下 :
-
-```python
-with open('filepath','mode') as f:
- pass
-```
-
-在Python 2.7以上的版本 , 支持同时对多个文件同时进行上下文管理 , 如下 :
-
-```python
-with open('filepath1','mode') as f1,open('filepath2','mode') as f2:
- pass
-```
-
-更多文档资料 : https://docs.python.org/3.5/library/io.html?highlight=io#module-io
\ No newline at end of file
diff --git "a/01-Python/01-\345\237\272\347\241\200\347\257\207/README.md" "b/01-Python/01-\345\237\272\347\241\200\347\257\207/README.md"
deleted file mode 100644
index ef69d25f1..000000000
--- "a/01-Python/01-\345\237\272\347\241\200\347\257\207/README.md"
+++ /dev/null
@@ -1,46 +0,0 @@
-# Attack on Python - 基础篇 🐍
-
-
-
-
-
-
-
-
-
-
-## 前言
-
-基础篇中的内容 , 应对的是 `Python` 的基础语法 , 以及基础数据类型的文章
-
-在开始之前 , 你可以熟悉一下 `Python` 的语言参考 : [The Python Language Reference](https://docs.python.org/3/reference/index.html)
-
-最好的教程就是官方文档 , 所以阅读官方文档是一个好的学习习惯
-
-## 介绍
-
-Python基础主要包括基础语句 , 基础数据类型 , 字符编码 , 文件操作等
-
-## 基础语句
-
-- Hello World
-- 变量
-- 行和缩进
-- 多行语句
-- 注释
-- input
-- print
-- 数据运算
-- 条件语句
-- for
-- while
-
-## 数据类型
-
-- 数字 , Number
-- 字符串 , String
-- 元组 , Tuple
-- 列表 , List
-- 字典 , Dictionary
-- 集合 , Set
-
diff --git "a/01-Python/02-\345\207\275\346\225\260\347\257\207/01-\345\207\275\346\225\260\345\237\272\347\241\200.md" "b/01-Python/02-\345\207\275\346\225\260\347\257\207/01-\345\207\275\346\225\260\345\237\272\347\241\200.md"
deleted file mode 100644
index b3236032e..000000000
--- "a/01-Python/02-\345\207\275\346\225\260\347\257\207/01-\345\207\275\346\225\260\345\237\272\347\241\200.md"
+++ /dev/null
@@ -1,321 +0,0 @@
-# Attack on Python - 函数基础 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-函数是组织好的 , 可重复使用的 , 用来实现单一 , 或相关联功能的代码段
-
-函数能提高应用的模块性 , 和代码的重复利用率 , 比如我们一直使用的`print()` , `input()` 等等 , 都是函数
-
-如下我们写了一个用户认证程序 ; 而现在我们又需要写一个用户管理系统 , 管理系统中有很多的功能 , 比如添加用户 , 删除用户 , 查询用户 , 修改用户 ; 但是这些功能必须先通过用户认证程序才能使用 , 明显我们不可能在每一个功能前加上一段用户认证代码 , 因为这将大大增加我们的重复代码
-
-那么为了解决这个问题我们就可以将用户认证功能封装到一个函数之中 , 而后续我们如果需要使用这个函数仅需调用即可 , 着就是函数的魅力所在 , 当然更多的还是通过下面进一步了解函数
-
-## 定义函数
-
-```python
-# 自定义函数,function_name为函数名
-def function_name():
- """注释"""
-
- '''
- 功能代码块
- '''
- # 返回值,一般都具有返回值,当然也不可以不设定
- return result
-```
-
-简单实例
-
-```python
-def hello():
- print("Hello Lyon!")
- return None
-```
-
-**注意 :** 上述仅为定义函数 , 函数并不会执行 , 只有当函数被调用时 , 函数内部代码才会执行
-
-## 函数调用
-
-函数调用通过*函数名*后加`()` 进行调用 , 如下 :
-
-```python
-# 定义函数
-def hello():
- print("Hello Lyon!")
- return None
-# 调用函数
-hello()
-```
-
-既然函数调用是通过函数名后加括号 , 在这个固定语法之中前者函数名有是什么? 如下 :
-
-```python
-# 定义函数
-def hello():
- print("Hello Lyon!")
- return None
-# 打印函数名
-print(hello)
-'''
-执行结果:
-
-'''
-```
-
-我们可以发现 , 函数名打印出来的是一个内存地址 , 由此不难理解 :
-
-**函数名相当于一个变量 , 而变量所绑定的对象就是函数对象本身 ; **
-
-## 参数说明
-
-**形参 :** 变量只有在被调用时才分配内存单元 , 在调用结束时 , 即刻释放所分配的内存单元 ; 因此 , 形参只在函数内部有效 , 函数调用结束返回主调用函数后则不能再使用该形参变量
-
-**实参 : **可以是常量、变量、表达式、函数等 , 无论实参是何种类型的量 , 在进行函数调用时 , 它们都必须有确定的值 , 以便把这些值传送给形参 ; 因此应预先用赋值 , 输入等办法使参数获得确定值
-
-```python
-# 定义函数func
-def func(argument1,argument2): # argument1与argument2都为形参,形式参数
- print(argument1,argument2)
-
-# 调用函数func
-func("Hello", "Lyon") # Hello和Lyon都是实参,实际参数
-'''
-执行结果:
-Hello Lyon
-'''
-```
-
-**位置参数 :** 即参数必须以正确的顺序传入函数 , 传入的数量必须和声明的一样 , 不一样就报错
-
-```python
-# 用户登录验证
-def login(username,password):
- if username == "Lyon" and password == "123456":
- print("Login successfully!")
- else:
- print("Login failed!")
-# 进行调用
-login("Lyon","123456")
-# 进行调用
-login("Lyon","78910JkQ")
-'''
-执行结果:
-Login successfully!
-Login failed!
-'''
-```
-
-### 默认参数
-
-调用时不指定就以默认值传入 , 指定则按指定值传入
-
-```python
-# 同时定义位置参数和默认参数
-def add_userinfo(name,age,province="北京"):
- return name,province
-# 位置参数必填,默认参数可选
-add_userinfo("Lyon",18)
-'''
-执行结果:
-('Lyon', '北京')
-'''
-```
-
-注:通过默认参数,我们就算不传参数也不会报错 , 即`province` 默认为`"北京"`
-
-### 关键字参数
-
-正常情况下 , 给函数传参数的时候要按照顺序传 , 如果不想按照顺序就可以使用关键参数
-
-```python
-def add_userinfo(name,age,province="北京"):
- return name,province
-add_userinfo("Lyon",province="湖北",age=18)
-# 注意关键参数不用按照顺序传入,但是关键参数必须写在位置参数后面
-```
-
-### 非固定参数
-
-当我们想要传入多个参数 , 但是我们又不确定的时候就可以使用非固定参数 ; 非固定参数有两个 , 一个 `*args (元组形式)` 以及 `**kwargs (字典形式) `
-
-```python
-# 设定两个非固定参数
-def main(*args,**kwargs):
- # 打印args,以及args的类型
- print(args,type(args))
- # 打印kwargs,以及kwargs的类型
- print(kwargs,type(kwargs))
-# 调用
-main((1,2,3,4),{1:2,3:4})
-```
-
-对于非固定参数 , 其主要在于`*` 号 , `*` 号的作用是进行打包与解包 :
-
-- 一个`*` 号 , 则表示打包成元组或者将元组进行解包 , 过程如下 :
-
- ```python
- def main(n,*args):
- return args
- # 传递参数,第一个参数被认为是位置参数n,余后参数*号将会对其进行打包成元组,但参数形式必须符合元组规范
- result = main(1,2,3,4,5)
- print(result)
- '''
- 执行结果:
- (2, 3, 4, 5)
- '''
- '''
- 额外说明:
- 传递参数时,*号将参数封装成一个元组,即元组args
- '''
- ```
-
-- 两个`**` 号 , 则表示打包成字典或者将字典进行解包 , 过程如下 :
-
- ```python
- def main(**kwargs):
- return kwargs
- # 传递参数,**号将会对其进行打包成字典,但参数形式必须符合字典规范,即必须key-value
- result = main(n2=2,n3=3,n4=4)
- print(result)
- '''
- 执行结果:
- {'n4': 4, 'n2': 2, 'n3': 3}
- '''
- '''
- 额外说明:
- 传递参数时,**号将参数封装成一个字典,即字典kwargs
- '''
- ```
-
-- 两者的解包如下 :
-
- ```python
- # 进行打包
- def main(*args,**kwargs): # 参数状态:(1,2,3,4,5){'n1':1,'n2':2,'n3'=3}
- # 进行解包
- return (*args),{**kwargs} # 参数状态:1,2,3,4,5,n1=1,n2=2,n3=3
- result = main(1,2,3,4,5,n1=1,n2=2,n3=3)
- print(result)
- '''
- 执行结果:
- (1, 2, 3, 4, 5, {'n2': 2, 'n3': 3, 'n1': 1})
- '''
- # 解包补充
- '''只要是可迭代对象我们都可以对其进行解包,如下'''
- mytuple = (1,2,3,4,5,6,7)
- # _为占位符,*c打包成列表
- a,_,b,*c,d = mytuple
- print(a)
- print(b)
- print(c)
- print(d)
- '''
- 执行结果:
- 1
- 3
- [4, 5, 6]
- 7
- '''
- ```
-
-### 参数顺序与传递
-
-**参数顺序**
-
-在函数头部 (定义参数) : 一般参数 → 默认参数 → 非固定参数`*args` → 非固定参数`**kwargs`
-
-在函数调用中 (传递参数) : 位置参数 → 关键字参数 → 默认参数 → 非固定参数`*args` → 非固定参数`**kwargs`
-
-**参数传递**
-
-在我们使用过程中 , 如果没有非固定参数 , 那么我们的关键参数或者默认参数可以用关键字进行传递 ; 如果有非固定参数 , 必须按照位置参数的方式进行传递
-
-默认参数和非固定参数`*args`位置可以进行调换 , 调换后默认参数传递需要加上关键字
-
-## 全局与局部变量
-
-局部变量:只在函数内部起作用的变量
-
-全局变量:在整个程序中都起作用
-
-```python
-# 全局变量name
-name = "Lyon"
-def func(name):
- print(name)
- # 局部变量name
- name = "Kenneth"
- print(name)
-# 调用函数
-func(name)
-print(name)
-'''
-执行结果:
-Lyon
-Kenneth
-Lyon
-'''
-```
-
-总结 : 全局变量**作用域**是整个程序 , 局部变量**作用域**是定义该变量的子程序 ; 当全局变量与局部变量同名时 : 在定义局部变量的子程序内 , 局部变量起作用 ; 在其他地方全局变量起作用
-
-**global语句 : **可以将局部变量变成全局变量 , 在函数内部变量前加上 global 即可如 : `global name`
-
-## return语句
-
-`return` 语句用于返回函数的执行结果 , 比如操作类函数一般都不需要返回值 , 当然可由我们的需要自己进行设定
-
-不使用`return` 即返回None , 没有返回值
-
-我们函数在执行过程中如果遇到return语句 , 就会结束并返回结果
-
-```python
-def sum( arg1, arg2 ):
- # 返回2个参数的和
- total = arg1 + arg2
- print("两数之和:",total)
- return total
- # 上一步函数就已经结束,不会往下执行
- print("已经返回!")
-# 调用sum函数
-total = sum( 10, 20 )
-'''
-执行结果:
-两数之和: 30
-'''
-```
-如果我们返回函数名
-
-```python
-def func():
- print("I am Lyon")
- # 返回func,函数名 → 内存地址
- return func
-# result1接收返回值func函数名
-result1 = func()
-# 返回一个函数对象
-print(result1)
-# 可以继续调用
-result2 = result1()
-print(result2)
-result2()
-'''
-执行结果:
-I am Lyon
-
-I am Lyon
-
-I am Lyon
-'''
-```
diff --git "a/01-Python/02-\345\207\275\346\225\260\347\257\207/02-\345\214\277\345\220\215\345\207\275\346\225\260.md" "b/01-Python/02-\345\207\275\346\225\260\347\257\207/02-\345\214\277\345\220\215\345\207\275\346\225\260.md"
deleted file mode 100644
index f9c3e3136..000000000
--- "a/01-Python/02-\345\207\275\346\225\260\347\257\207/02-\345\214\277\345\220\215\345\207\275\346\225\260.md"
+++ /dev/null
@@ -1,103 +0,0 @@
-# Attack on Python - 匿名函数 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## 介绍
-
-匿名函数顾名思义就是一个没有名字的函数 , 我们可以通过 `lambda` 关键字来定义
-
-`lambda` 是一个表达式 , 而并非语句 , 所以可以出现在def语句所不能出现的位置 , 并且不需要指定函数名; `lambda` 表达式还可以提高代码的可读性 , 简化代码
-
-`lambda` 表达式主要用于写一些简单的方法 , 对于复杂的还是用函数写的好
-
-示例:
-
-```python
-# 普通函数
-def func(x):
- return x * x
-print(func(5))
------------------------
-# 匿名函数,自带return功能
-func = lambda x : x * x
-print(func(5))
----------------------------------------------------
-func = lambda arguments : expression using argument
-```
-
-使用匿名函数可以减少命名空间使用内存 , 因为没有函数名
-
-可直接后面传递参数
-
-```python
->>> (lambda x,y : x if x > y else y)(1,2)
-2
-```
-
-非固定参数
-
-```python
->>> (lambda *args : args)(1,2,3,4)
-(1, 2, 3, 4)
-```
-
-***PS : 匿名函数主要是与其他函数搭配使用***
-
-## 运用
-
-***结合使用***
-
-map , 计算平方
-
-```python
-# map后返回的对象为map对象,所以利用list方法进行强转
->>> list(map(lambda x : x * x, [1,2,3,4]))
-[1,4,9,16]
-```
-
-filter , 筛选偶数
-
-```python
->>> list(filter(lambda x : x % 2 == 0,[1,2,3,4]))
-[2,4]
-```
-
-reduce , 求和
-
-```python
-# python3中已经没有reduce方法了,调用需要导入
->>> from functools import reduce
-# reduce(function, sequence, initial=None)
->>> reduce(lambda x , y : x + y, [1,2,3,4,5],100)
-115
-```
-
-***嵌套使用***
-
-版本一
-
-```python
-def func(x):
- return lambda x : x + y
-f = func(2)
-print(f(2))
-# output: 4
-```
-
-版本二
-
-```python
-func = lambda x : (lambda y: x + y)
-y = func(1)
-y(2)
-# output: 3
-```
\ No newline at end of file
diff --git "a/01-Python/02-\345\207\275\346\225\260\347\257\207/03-\345\207\275\346\225\260\350\277\233\351\230\266.md" "b/01-Python/02-\345\207\275\346\225\260\347\257\207/03-\345\207\275\346\225\260\350\277\233\351\230\266.md"
deleted file mode 100644
index 1d7b9d75a..000000000
--- "a/01-Python/02-\345\207\275\346\225\260\347\257\207/03-\345\207\275\346\225\260\350\277\233\351\230\266.md"
+++ /dev/null
@@ -1,350 +0,0 @@
-# Attack on Python - 函数进阶 🐍
-
-
-
-
-## 介绍
-
-接下来我们会介绍一些函数更高级的用法
-
-## 嵌套函数
-
-嵌套函数即函数里面再套一个函数 , 如下 :
-
-```python
-# 全局变量name
-name = "Lyon_1"
-def func():
- # 第一层局部变量name
- name = "Lyon_2"
- print("第1层打印",name)
-
- #嵌套
- def func2():
- # 第二层局部变量name
- name = "Lyon_3"
- print("第2层打印", name)
-
- # 嵌套
- def func3():
- # 第三层局部变量
- name = "Lyon_4"
- print("第3层打印", name)
- # 调用内层函数
- func3()
- # 调用内层函数
- func2()
-func()
-print("最外层打印", name)
-'''
-执行结果:
-第1层打印 Lyon_2
-第2层打印 Lyon_3
-第3层打印 Lyon_4
-最外层打印 Lyon_1
-'''
-```
-
-嵌套函数不能越级调用 , 也就是说我们不能在`func2` 的外部去调用`func3` , 当然反过来我们的代码就进入无限递归了
-
-当然我们有时需要的就是在嵌套函数中 , 使用上一层的变量 , 那么我们可以使用`nonlocal` 语句
-
-`nonlocal` 的作用就是改变变量的作用域 , 但是不会扩展到全局变量 , 即只能在函数内部改变 ; nonlocal声明之后 , 会从上层开始找并返回第一个变量 , 没找到则会报错
-
-```python
-def func(arg):
- n = arg
- def func1():
- n = 2
- def func2():
- nonlocal n # n = 2
- n += 1
- func2()
- print(n) # n = 3
- func1()
- print(n)
-func(10)
-'''
-执行结果:
-3
-10
-'''
-```
-
-## 高阶函数
-
-高阶函数就是将一个函数以参数的形式传入另一个函数
-
-```python
-# 定义一个主函数,并设置一个参数func
-def main_func(func):
- # 返回func的值
- return func
-
-# 定义一个函数作为参数传入主函数
-def func():
- # 返回"Lyon"给func()
- return "Lyon"
-
-# res接收main_func的返回值,将func()的返回值作为参数传入main_func函数
-res = main_func(func())
-print(res)
-'''
-执行结果:
-Lyon
-'''
-```
-
-## 闭包
-
-闭包是一个结构体 , 闭包必须是内部定义的函数 (嵌套函数) , 该函数包含对外部作用域而不是全局作用域名字 (命名空间) 的引用
-
-```python
-def foo():
- # 局部变量name
- name = 'Lyon'
- # 内部定义的函数
- def bar():
- # 引用了外部定义的变量name,即内部函数使用外部函数变量,这一行为就叫闭包
- print("I am",name)
- return "In the bar"
- # 调用bar并打印结果
- print(bar())
- return "In the foo"
-# 调用foo并打印结果
-print(foo())
-'''
-执行结果:
-I am Lyon
-In the bar
-In the foo
-'''
-```
-
-我们可以通过查看函数对象的 `__closure__` 属性来显示的查看是否有闭包
-
-```python
-def foo():
- # 局部变量name
- name = 'Lyon'
- def bar():
- print("I am",name)
- return "In the bar"
- print(bar.__closure__)
-foo()
-'''
-执行结果:
-(,)
-'''
-```
-
-1. 闭包的这种引用方式 , 我们完全可以把闭包当做一个局部的 `"全局命名空间"` , 也就是说它只是在闭包的作用域中是可见的 , 对外并不可见 , 且闭包只有调用时才会创建 , 所以每个闭包都是完全独立的 , 拥有自己的环境
-
-2. 而且在闭包中被引用的变量的生命周期将会得到提升 , 只要有一个闭包引用了这个变量 , 它就会一直存在
-
-我们来用两个例子加深一下印象
-
-我们可以利用上面第一条所说的来实现一个累加器
-
-```python
-# 利用闭包实现一个累加器
-def add():
- count = [0]
- def inner():
- count[-1] += 1
- return count[-1]
- return inner
-
-adder1 = add() # 实例化第一个累加器
-adder2 = add() # 实例化第二个累加器
-print(adder1())
-print(adder1())
-print(adder1())
-print(adder2())
-'''
-执行结果:
-1
-2
-3
-1
-'''
-```
-
-可以看到两个累加器互不干扰 , 这就像对象的实例化 , 所以你应该知道了 , 闭包可以用来实现对象系统
-
-我们再看看生命周期提升的好处
-
-```python
-# 方式一, 利用闭包
-def func():
- name = "Lyon"
- def inner():
- hello_name = 'Hello' + name
- [inner() for _ in range(10)]
-
-# 方式二, 不利用闭包
-def func():
- def inner():
- name = "Lyon"
- hello_name = 'Hello' + name
- [inner() for _ in range(10)]
-
-func()
-"""
-首先我们不讨论这段代码是否有实际意义, 只讨论它们的执行方式
-我们对比一下方式1和方式2, 它们两者的区别在于 name = "Lyon" 一个在inner外部, 一个在内部
-当func执行时
-方式1: 创建name变量, 然后执行10次inner函数
-方式2: 执行10次inner函数, 每次执行inner函数中, 创建name变量
-"""
-```
-
-通过代码 , 很明显 , 方式1只需要创建1次 `name` , 而方式2会创建10次 , 原因就在于当一个函数执行完毕 , Python 的垃圾回收机制会将无用的对象进行销毁
-
-虽然从这里可以看出 , 闭包的使用可以提升某些时候的性能 , 但是同时 , 由于生命周期的提升 , 它将永远都不会被销毁 , 这不见得是一件好事 , 所以使用闭包还是需要注意不要滥用
-
-我们再留一个思考 , 思考一下下面这道面试题的结果会是什么呢
-
-```python
-s = [lambda x: x + i for i in range(10)]
-print(s[0](10))
-print(s[1](10))
-print(s[2](10))
-print(s[3](10))
-```
-
-## 装饰器
-
-装饰器即给原来的函数进行装饰的工具
-
-装饰器由函数去生成 , 用于装饰某个函数或者方法 (类中的说法) , 它可以让这个函数在执行之前或者执行之后做某些操作
-
-装饰器其实就是上一节闭包中的应用 , 而 `Python` 为了方便我们使用就创造出一个语法糖来方便我们使用
-
-语法糖 : 指那些没有给计算机语言添加新功能 , 而只是对人类来说更"甜蜜"的语法 , 语法糖主要是为程序员提供更实用的编码方式 , 提高代码的可读性 , 并有益于更好的编码风格
-
-语法糖如下 :
-
-```python
-# 装饰器函数
-def decorator(func):
- def inner():
- # 我们可以在func执行前, 干一些别的事情
- # 引用外部传入的func, 一般是一个函数对象
- func()
- # 当然也可以在func执行后, 干一些别的事情
- return inner
-
-# 语法糖版本,@ 函数名
-@decorator
-def func():
- pass
-
-# 闭包调用版本
-func = decorator(func)
-```
-
-该语法糖只是将我们闭包中最后自己处理的部分进行处理了 , 如下 :
-
-```python
-@decorator
- ↓ 等价
-func = decorator(func)
-```
-
-实例
-
-```python
-def decorator(func):
- def inner():
- print("I am decorator")
- func()
- return inner
-@decorator # → func = decorator(func)
-def func():
- print("I am func")
- return func
-func()
-'''
-执行结果:
-I am decorator
-I am func
-'''
-```
-
-多个装饰器装饰同一个函数
-
-```python
-def decorator1(func):
- def inner():
- return func()
- return inner
-
-def decorator2(func):
- def inner():
- return func()
- return inner
-
-@decorator1
-@decorator2
-def func():
- print("I am func")
-func()
-```
-
-被装饰函数带有参数
-
-```python
-def decorator(func):
- def inner(*args,**kwargs):
- return func(*args,**kwargs)
- return inner
-
-@decorator
-def func(name):
- print("my name is %s" % name)
-func("Lyon")
-```
-
-带参数的装饰器
-
-```python
-F = False
-def outer(flag):
- def decorator(func):
- def inner(*args,**kwargs):
- if flag:
- print('before')
- ret = func(*args,**kwargs)
- print('after')
- else:
- ret = func(*args, **kwargs)
- return ret
- return inner
- return decorator
-
-@outer(F) # outer(F) = decorator(func)
-def func():
- print('I am func')
-```
-
-我们利用装饰器虽然功能达到了 , 但是注意原函数的元信息却没有赋值到装饰器函数内部 , 比如函数的注释信息 , 如果我们需要将元信息也赋值到装饰器函数内部 , 可以使用 `functools` 模块中的`wraps()`方法 , 如下 :
-
-```python
-import functools
-def outer(func):
- @functools.wraps(func)
- def inner(*args, **kwargs):
- print(inner.__doc__)
- return func()
- return inner
-@outer
-def func():
- """
- I am func
- """
- return None
-func()
-```
-
-我们也可以自己手动修改 , 比如 `inner.__qualname__ = func.__qualname__` , `inner.__doc__ = func.__doc__`
diff --git "a/01-Python/02-\345\207\275\346\225\260\347\257\207/04-\345\206\205\347\275\256\345\207\275\346\225\260.md" "b/01-Python/02-\345\207\275\346\225\260\347\257\207/04-\345\206\205\347\275\256\345\207\275\346\225\260.md"
deleted file mode 100644
index 2de2b47f5..000000000
--- "a/01-Python/02-\345\207\275\346\225\260\347\257\207/04-\345\206\205\347\275\256\345\207\275\346\225\260.md"
+++ /dev/null
@@ -1,615 +0,0 @@
-# Attack on Python - 内置函数 🐍
-
-
-
-
-
-
-
-
-
-
-
-
-## str类型代码的执行(3个)
-
-> `exec`(object[, globals[, locals]]) 👈
-
-将字符串当做表达式去执行,没有返回值
-
-```python
-# 流程语句用exec
->>> exec("print('123')")
-123
->>> exec('1+2+3+4')
-10
->>> res = exec('1+2+3+4')
-None
-```
-
-> `eval`(expression, globals=None, locals=None) 👈
-
-将字符串当做表达式去执行,并返回执行结果
-
-```python
-# 简单求值表达式用eval
->>> res = eval('1+2+3+4')
->>> res
-10
-```
-
-> `compile`(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) 👈
-
-把字符传编译成python可执行的代码,但是不会执行
-
-*filename* : 默认`sys.stout`,即默认打印在控制台,打印到指定文件
-
-*mode* : 指定compile后的对象的执行模式,注意有个`single`模式,当source带有变量赋值时,eval模式是解释不了的,所以需要用single模式或者exec模式
-
-```python
-# 交互语句用single
->>> code3 = 'name = input("please input your name:")'
->>> compile3 = compile(code3,'','single')
-# 执行前name变量不存在
->>> name
-# 报错说'name'变量没有定义
-Traceback (most recent call last):
- File "", line 1, in
- name
-NameError: name 'name' is not defined
->>> exec(compile3)
-# 执行时显示交互命令,提示输入
-please input your name:'pythoner'
-# 执行后name变量有值
->>> name
-"'pythoner'"
-```
-
-## 数据类型相关(38)
-
-### 数字相关
-
-#### 数据类型
-
-> `bool`([*x*]) 👈
-
-查看一个元素的布尔值
-
-> `int`(*x=0*) / `int`(*x*, *base=10*) 👈
-
-获取一个数的十进制或者进行进制转换
-
-```python
->>> int('1')
-1
-# 二进制转十进制
->>> int('0b11',base=2)
-3
-```
-
-> `float`([*x*]) 👈
-
-将整数和字符串转换成浮点数
-
-> `complex`([*real*[, *imag*]]) 👈
-
-创建一个值为real + imag * j的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数
-
-```python
->>> complex(1, 2)
-(1+2j)
-# 数字
->>> complex(1)
-(1+0j)
-# 当做字符串处理
->>> complex("1")
-(1+0j)
-# 注意:这个地方在“+”号两边不能有空格,也就是不能写成"1 + 2j",应该是"1+2j",否则会报错
->>> complex("1+2j")
-(1+2j)
-```
-
-#### 进制转换
-
-> `bin`(*x*) 👈
-
-将整数x转换为二进制字符串,如果x不为Python中int类型,x必须包含方法`__index__()`并且返回值为整数
-
-```python
-# 返回一个整数的二进制
->>> bin(999)
-'0b1111100111'
-# 非整型的情况,必须包含__index__()方法且返回值为integer的类型
->>> class myType:
-... def __index__(self):
-... return 35
-...
->>> myvar = myType()
->>> bin(myvar)
-'0b100011'
-```
-
-> `oct`(*x*) 👈
-
-转换为八进制
-
-```python
->>> oct(8)
-'0o10'
-```
-
-> `hex`(*x*) 👈
-
-转换为十六进制
-
-```python
->>> oct(13)
-'0o15'
-```
-
-#### 数学运算
-
->`abs`(*x*) 👈
-
-返回一个数的绝对值
-
-```python
->>> num = -1
->>> abs(num)
-1
-```
-
-> `divmod`(*a*, *b*) 👈
-
-返回两个数的除,余
-
-```python
->>> divmod(5,2)
-# 第一个数为整除,第二个为取余
-(2, 1)
-```
-
->`min`(*iterable*, **[, key, default]*) 👈
->
->`min`(*arg1*, *arg2*, **args*[, *key*]) 👈
-
-返回最小值,如果多个参数最小值一样,则返回第一个
-
-```python
->>> min([1,2,3,4])
-1
-# 返回第一个
->>> min([1,2,3],[4,5],[1,2])
-[1,2,3]
-```
-
->`max`(*iterable*, **[, key, default]*) 👈
->
->`max`(*arg1* , *arg2*, **args*[, *key*]) 👈
-
-返回最大值,如果多个参数最大值,则返回第一个
-
-```python
->>> max([1,2,3,4])
-4
->>> max([2,3],[1,2,3])
-[2, 3]
-```
-
-> `sum`(*iterable*[, *start*]) 👈
-
-求和,参数为可迭代对象
-
-```python
->>> sum((1,2,3,4))
-10
-```
-
-> `round`(*number[, ndigits]*) 👈
-
-小数精确
-
-```python
-# 保留两位小数,四舍五入
->>> round(1.235,2)
-1.24
-```
-
-> `pow`(*x*, *y*[, *z*]) 👈
-
-幂运算
-
-```python
-
->>> pow(2,2)
-4
-# 参数z相当余 x**y % z
->>> pow(2,2,2)
-0
-```
-
-### 数据类型相关
-
-#### 序列
-
-列表和元组
-
->`list`([*iterable*]) 👈
-
-将可迭代对象转换成list对象,实际上我们创建一个空list时,python解释器自动为我们调用了该方法
-
-> `tuple`([*iterable*]) 👈
-
-将可迭代对象转换成tuple对象,与list类似
-
-相关内置函数
-
->`reversed`(*seq*) 👈
-
-顺序翻转,与list中reverse的区别在于,该翻转为新生成了一个对象,而不是在原对象上操作
-
->`slice`(*stop*) 👈
->
->`slice`(*start*, *stop*[, *step*]) 👈
-
-返回切片操作的三个参数
-
-```python
-# 相当于[0:2:],注意最后一个参数不能为0而是None
->>> op = slice(0,2,None)
->>> l = [1,2,3,4]
->>> l[op]
-[1,2,3]
-```
-
-字符串
-
->`str`(*object=''*) 👈
->
->`str`(*object=b''*, *encoding='utf-8'*, *errors='strict'*) 👈
-
-返回一个字符串对象,创建字符串时python解释器为我们调用了该方法进行创建
-
-> `repr`(*object*) 👈
-
-返回一个可打印的字符串对象
-
-```python
->>> repr(123)
-```
-
->`format`(*value*[, *format_spec*]) 👈
-
-格式化字符串
-
->`bytes`([*source*[, *encoding*[, *errors*]]]) 👈
-
-将字符串转成bytes类型
-
-```python
->>> bytes('lyon',encoding='utf-8')
-b'lyon'
-```
-
-> `bytearray`([*source*[, *encoding*[, *errors*]]]) 👈
-
-返回一个byte数组,Bytearray类型是一个可变的序列,并且序列中的元素的取值范围为[0,255]
-
-*source* :
-
-1. 如果source为整数,则返回一个长度为source的初始化数组;
-2. 如果source为字符串,则按照指定的encoding将字符串转换为字节序列;
-3. 如果source为可迭代类型,则元素必须为[0,255]中的整数;
-4. 如果source为与buffer接口一致的对象,则此对象也可以被用于初始化bytearray
-
->`memoryview`(*obj*) 👈
-
-函数返回给定参数的内存查看对象(Momory view)
-
-所谓内存查看对象,是指对支持缓冲区协议的数据进行包装,在不需要复制对象基础上允许Python代码访问
-
->`ord`(*c*) 👈
-
-把一个字符转换成ASCII表中对应的数字
-
-```python
->>> ord('a')
-97
-```
-
-> `chr`(*i*) 👈
-
-返回一个数字在ASCII编码中对应的字符
-
-```python
->>> chr(66)
-'B'
-```
-
-> `ascii`(*object*) 👈
-
-在对象的类中寻找` __repr__`方法,获取返回值
-
-```python
->>> class Foo:
-... def __repr_(self):
-... return "hello"
-...
->>> obj = Foo()
->>> r = ascii(obj)
->>> print(r)
-# 返回的是一个可迭代的对象
-<__main__.Foo object at 0x000001FDEE13D320>
-```
-
-#### 数据集合
-
-字典
-
-
->`dict`(**\*kwarg*)
->
->`dict`(*mapping*, **\*kwarg*)
->
->`dict`(*iterable*, **\*kwarg*)
-
-转换成字典类型,创建一个字典时python解释器会自动帮我们调用该方法
-
-集合
-
-> `set`([*iterable*]) 👈
-
-转换成集合类型,创建集合时,事实上就是通过该方法进行创建的
-
-> `frozenset`([*iterable*]) 👈
-
-定义冻结集合,即不可变集合,存在hash值
-
-好处是它可以作为字典的key,也可以作为其它集合的元素。缺点是一旦创建便不能更改,没有add,remove方法
-
-#### 相关内置函数
-
->`len`(*s*) 👈
-
-返回一个对象的长度
-
->`enumerate`(*iterable*, *start=0*) 👈
-
-为元素生成序号,可以定义序号的初始值,默认从0开始
-
-```python
->>> l = ['a','b','c']
->>> for i,k in enumerate(l,0):
-... print(i,k)
-...
-0 a
-1 b
-2 c
-```
-
-> `all`(*iterable*) 👈
-
-判断一个可迭代对象中的元素是否都为空,返回bool值
-
->`any`(*iterable*) 👈
-
-判断一个可迭代对象中是否有真元素,返回bool值
-
->`zip`(**iterables*) 👈
-
-将两个长度相同的序列整合成键值对,返回一个zip对象可以用dict方法转换查看
-
-```python
->>> l1 = ['k1','k2','k3']
->>> l2 = ['v1','v2','v3']
->>> ret = zip(l1,l2)
->>> dict(ret)
-{'k1':'v1','k2':'v2','k3':'v3'}
-```
-
-> `filter`(*function*, *iterable*) 👈
-
-筛选过滤,把可迭代对象中的元素一一传入function中进行过滤
-
-```python
-# 筛选出偶数
->>> def func(x):
-... return x % 2 == 0
->>> f = filter(func,[1,2,3,4,5])
-
->>> ret = list(f)
-[2,4]
-```
-
->`map`(*function*, *iterable*, *...*) 👈
-
-将可迭代对象中的元素一一传入function中执行并返回结果
-
-```python
->>> def func(s):
-... return s + ' hello'
->>> m = map(func,['alex','egon','lyon'])
->>> m
- |
```
-### 手动渲染字段 🍀
+### 手动渲染字段
我们不必让Django打开表单的字段 , 如果我们想要 , 我们也可以手动执行 (例如 , 允许我们重新排序字段) , 每个字段都是表单的一个属性 , 可以使用
@@ -395,7 +395,7 @@ if form.is_valid():
```
-### 渲染表单错误信息 🍀
+### 渲染表单错误信息
对于错误信息 , Django已经帮我们处理好了 , 如下我们将自己处理每个字段的错误和表单整体的各种错误
@@ -408,7 +408,7 @@ if form.is_valid():
这个ul有一个`errorlist` CSS class , 你可以用它来定义外观
-### field属性 🍀
+### field属性
```html
{{ field.label }}
@@ -464,7 +464,7 @@ The Field instance from the form class that this BoundField wraps. You can use i
完整的属性和方法列表 , 见[`BoundField`](https://docs.djangoproject.com/en/1.11/ref/forms/api/#django.forms.BoundField)
-### 循环隐藏和可见的字段 🍀
+### 循环隐藏和可见的字段
如果你在模板中手动布局一个表单 , 而不是依赖Django的默认表单布局 , 你可能会想要用不同于非隐藏的字段来处理不同的字段 ; 例如 , 因为隐藏的字段不显示任何内容 , 将错误信息放在 "旁边" 可能会引起用户的混淆 , 因此这些字段的错误应该以不同的方式处理
@@ -486,7 +486,7 @@ Django提供了两种方法 , 让你可以独立地遍历隐藏和可见字段 :
这个示例没有处理隐藏字段中的任何错误信息 , 通常 , 隐藏字段中的错误意味着表单被篡改 , 因为正常的表单填写不会改变他们
-### 可重用表单模板 🍀
+### 可重用表单模板
如果你的网站在多个地方对表单使用相同的渲染逻辑 , 你可以保存表单的循环到一个单独的模板来减少重复 , 然后在其他模板中使用`include` 标签来重用它 :
diff --git "a/05-Web\346\241\206\346\236\266/01-HTTP\345\237\272\347\241\200.md" b/docs/django/http.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/01-HTTP\345\237\272\347\241\200.md"
rename to docs/django/http.md
index 2866436a1..448ad967e 100644
--- "a/05-Web\346\241\206\346\236\266/01-HTTP\345\237\272\347\241\200.md"
+++ b/docs/django/http.md
@@ -9,7 +9,7 @@
-## HTTP常用头字段 🍀
+## HTTP常用头字段
| 字段名 | 方向 | 解释 | 可能的值 |
| ------------------ | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
@@ -35,7 +35,7 @@
| Etag | Both | 内容唯一标识 , 服务端要把服务器传来的Etage保留 , 在下次请求相同的 URL 时提交给服务器 . 服务器用 Etag值判断同一个 URL 的内容是否有变化 , 如果有变化则发送更新的内容给客户端 | 任何值 |
| Via | Both | 列出从客户端到服务器或者相反方向的响应经过了哪些代理服务器 , 它们用什么协议 (和版本) 发送的请求 | |
-## HTTP常见错误代码 🍀
+## HTTP常见错误代码
在每个 Response 的第1行中有一个整数状态码用于表达其对应 Request 的结果 , HTTP 除了约定该状态的表达方式 , 还约定了该状态的取值范围 , 约定的 5 类状态码如下 :
@@ -57,7 +57,7 @@
| 402 | 需要付费访问 | 403 | 禁止访问 | 500 | 服务器异常错误 |
| 501 | 未执行 | 502 | 上游的其他来源错误 | 503 | 临时过载或维护中 |
-## HTTP请求方法 🍀
+## HTTP请求方法
HTTP 中常用的访问方式及其意义
diff --git "a/05-Web\346\241\206\346\236\266/Django/14-Django - Middleware.md" b/docs/django/middleware.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django/14-Django - Middleware.md"
rename to docs/django/middleware.md
index 614c0273c..ac6b2d2bd 100644
--- "a/05-Web\346\241\206\346\236\266/Django/14-Django - Middleware.md"
+++ b/docs/django/middleware.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
在Django中 , 中间件本质上就是一个类 , 我们可以使用中间件来对请求和响应进行批量处理 , 中间件所在的层次介于WSGI协议与Django URL系统之间 , 它类似一个一个的盒子 , 所有的请求和响应到来时 , 都必须穿过一个一个的盒子 (中间件) , 如下 :
@@ -50,7 +50,7 @@ MIDDLEWARE = [
内置中间件 : [built-in middleware reference](https://docs.djangoproject.com/en/1.11/ref/middleware/)
-## CSRF 🍀
+## CSRF
CSRF 即`Cross Site Request Forgery protection` , 中文意思为跨站请求伪造 , 也被称为"One Click Attack"或者 Session Riding , 通常缩写为CSRF或XSRF , 是一种对网站的恶意利用
@@ -58,7 +58,7 @@ CSRF 即`Cross Site Request Forgery protection` , 中文意思为跨站请求伪
所以为了防止CSRF的发生 , Django为我们提供了中间件`django.middleware.csrf.CsrfViewMiddleware`
-### CSRF中间件使用 🍀
+### CSRF中间件使用
如果要在我们的视图中使用CSRF保护 , 我们需要进行如下操作 :
@@ -82,7 +82,7 @@ CSRF 即`Cross Site Request Forgery protection` , 中文意思为跨站请求伪
更多CSRF中间件使用参考 : [Cross Site Request Forgery protection documentation](https://docs.djangoproject.com/en/1.11/ref/csrf/)
-## 激活中间件 🍀
+## 激活中间件
我们如果要使用中间件 , 就需要在Django配置中的`MIDDLEWARE`添加中间件组件
@@ -101,7 +101,7 @@ MIDDLEWARE = [
]
```
-## 自定义中间件 🍀
+## 自定义中间件
有时候我们需要自定义中间件来达到我们的实际要求 , 其有两种方式 , 即通过类或者函数
@@ -131,7 +131,7 @@ class SimpleMiddleware(object):
2. 每个请求都会调用一次`__call__()`方法
3. 当Web服务器启动时 , `__init__()`仅会被调用一次
-### MiddlewareMixin 🍀
+### MiddlewareMixin
上面的写法只适用于Django 1.9及之前的写法 , 在1.10的版本中 , Django为我们提供了`django.utils.deprecation.MiddlewareMixin`以简化`MIDDLEWARE`和旧的`MIDDLEWARE_CLASSES`兼容的中间件类 ; Django 1.10之后的版本使用`MIDDLEWARE`代替`MIDDLEWARE_CLASSES` , Django中包含的所有中间件类都兼容这两种设置
@@ -165,7 +165,7 @@ class MiddlewareMixin(object):
在大多数情况下 , 继承这种混合将足以使旧式中间件与新系统兼容 , 具有足够的向后兼容性
-### 钩子函数 🍀
+### 钩子函数
在请求阶段中 , 调用视图之前 , Django会按照`MIDDLEWARE`中定义的顺序自顶向下应用中间件 , 我们需要用到以下两个钩子函数 :
@@ -188,7 +188,7 @@ class MiddlewareMixin(object):
如果其中某一层短路并返回响应 , 那么将不能到达视图 , 而是直接在短路层就返回响应
-#### process_request() 🍀
+#### process_request()
```python
process_request(request):
@@ -204,7 +204,7 @@ process_request(request):
- 如果返回None , Django会继续处理这个请求 , 执行其它中间件的`process_request()` , 然后执行中间件的`process_view()` , 最后执行对应的视图
- 如果返回一个HttpResponse对象 , Django就不会去调用其他的中间件的`request_view`或`request_exception`或对应的视图 , 而是直接转变到响应阶段 , 按照原路返回
-#### process_view() 🍀
+#### process_view()
```python
process_view(request, view_func, view_args, view_kwargs):
@@ -230,7 +230,7 @@ Accessing request.POST inside middleware before the view runs or in process_view
The CsrfViewMiddleware class can be considered an exception, as it provides the csrf_exempt() and csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should occur.
```
-#### process_exception() 🍀
+#### process_exception()
```python
process_exception(request, exception):
@@ -244,7 +244,7 @@ process_exception(request, exception):
注意 : 在处理响应期间 , 中间件的执行顺序是倒序执行的 , 所以如果异常中间件返回响应 , 那么下一层中间件的`process_exception`方法将不会调用 , 因为在上一层已经捕捉完成
-#### process_template_response() 🍀
+#### process_template_response()
```python
process_template_response(request, response):
@@ -259,7 +259,7 @@ process_template_response(request, response):
并且一旦所有的模板响应中间件被调用 , 响应会自动被渲染
-#### process_response() 🍀
+#### process_response()
```python
process_response(request,response):
@@ -275,7 +275,7 @@ process_response(request,response):
`process_response`不像`process_request`和`process_view`那样会因为前一个中间件返回的HttpResponse而被跳过 , `process_response`方法总是会被调用 , 这意味着你的`process_response`方法不能依赖于`process_request`方法中的设置
-## 处理流响应 🍀
+## 处理流响应
不像`HttpResponse` , `StreamingHttpResponse`并没有`content`属性 , 所以 , 中间件再也不能假设所有响应都带有`content`属性 , 如果它们需要访问内容 , 他们必须测试是否为流式响应 , 并相应地调整自己的行为 , 如下 :
@@ -296,7 +296,7 @@ def wrap_streaming_content(content):
yield alter_content(chunk)
```
-## RBAC案例 🍀
+## RBAC案例
rbac即Role-Based Access Control , 基于角色的权限访问控制 , 这种控制极大地简化了权限的管理 , 下面为rbac中我们自定义使用的中间件案例 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/08-Django - Model Field Options.md" b/docs/django/model-field-options.md
similarity index 96%
rename from "05-Web\346\241\206\346\236\266/Django/08-Django - Model Field Options.md"
rename to docs/django/model-field-options.md
index dcf455f0d..279641f1d 100644
--- "a/05-Web\346\241\206\346\236\266/Django/08-Django - Model Field Options.md"
+++ b/docs/django/model-field-options.md
@@ -9,13 +9,13 @@
-## 介绍 🍀
+## 介绍
本篇文章为"工具"笔记 , 适合用于翻阅查找 , 对于字段元选项的总结
以下字段选项对于所有字段类型都是可选的
-## null 🍀
+## null
**说明**
@@ -36,7 +36,7 @@ class Student(models.Model):
*如果我们需要在`BooleanField` 字段中设置 `null` , 我们应该使用 `NullBooleanField` 字段来代替*
-## blank 🍀
+## blank
**说明**
@@ -51,7 +51,7 @@ class Student(models.Model):
name = models.CharField(blank=True)
```
-## choices 🍀
+## choices
**说明**
@@ -106,7 +106,7 @@ Django中 , 对于每一个选择框 , 都有一个 `get_fieldname_display()`
**PS :** 如果不指定默认选项 , 那么选择菜单默认为 "-----------" , 如果我们要进行重写 , 只需在元组添加一项包含None的元组到 `choices` 中 , 如 : `(None, 'Your Choices')`
-## db_column 🍀
+## db_column
**说明**
@@ -126,7 +126,7 @@ class Student(models.Model):
+----+---------+
```
-## db_index 🍀
+## db_index
**说明**
@@ -139,11 +139,11 @@ class Student(models.Model):
name = models.CharField(max_length=32, db_index=True)
```
-## db_tablespace 🍀
+## db_tablespace
***待整理***
-## default 🍀
+## default
**说明**
@@ -163,7 +163,7 @@ class Student(models.Model):
**PS :** 可调用对象不可使用 `lambdas` 函数 , 因为这类参数无法被 `migrations` 命令进行序列化
-## editable 🍀
+## editable
**说明**
@@ -176,7 +176,7 @@ class Student(models.Model):
role = models.CharField(max_length=32, editable=False)
```
-## error_messages 🍀
+## error_messages
**说明**
@@ -210,7 +210,7 @@ default_error_messages = {
}
```
-## help_text 🍀
+## help_text
**说明**
@@ -225,7 +225,7 @@ class Student(models.Model):
**PS :** 默认会对文档进行HTML转换 , 所以为了避免任何HTML特定的字符 , 我们可以使用简单文本或 `django.utils.html.escape()` 进行转换 , 以防止用户进行的跨站点脚本攻击
-## primary_key 🍀
+## primary_key
**说明**
@@ -240,7 +240,7 @@ class Student(models.Model):
**PS :** 主键字段是只读的 , 如果你更改现有对象的主键的值 , 然后将其保存 , 该结果并不是更改原对象的值 , 而是创建一个新对象
-## unique 🍀
+## unique
**说明**
@@ -259,7 +259,7 @@ class Student(models.Model):
版本区别 : 在Django 1.11 中 , 为了版本支持 , `unique=True` 不可以使用 `FileField`
-## unique_for_date 🍀
+## unique_for_date
**说明**
@@ -274,15 +274,15 @@ class Student(models.Model):
**PS :** 该选项是在Form验证期间通过 `Model.validate_unique()` 强制执行的 , 而不是在数据库级别进行的 , 所以这就意味着 , 如果字段中有 `editable=True` , 那么 `Model.validate_unique()` 将忽略该约束
-## unique_for_month 🍀
+## unique_for_month
类似于 `unique_for_date` , 只是要求字段对于月份是唯一的
-## unique_for_year 🍀
+## unique_for_year
类似于 `unique_for_date` , 只是要求字段对于年份是唯一的
-## verbose_name 🍀
+## verbose_name
**说明**
@@ -295,7 +295,7 @@ class Student(models.Model):
name = models.CharField(max_length=32, verbose_name="学生姓名")
```
-## validators 🍀
+## validators
**说明**
diff --git "a/05-Web\346\241\206\346\236\266/Django/07-Django - Model Fields.md" b/docs/django/model-fields.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django/07-Django - Model Fields.md"
rename to docs/django/model-fields.md
index e2763912e..1d686f009 100644
--- "a/05-Web\346\241\206\346\236\266/Django/07-Django - Model Fields.md"
+++ b/docs/django/model-fields.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
对于一个模型来说 , 最重要的和不可或缺的是列出该模型在数据库中定义的字段
@@ -30,7 +30,7 @@ class Album(models.Model):
num_stars = models.IntegerField()
```
-## 字段类型 🍀
+## 字段类型
模型中的每个字段都是 [`Field`](https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.Field) 子类的某个实例 , Djnaog根据字段的类型确定以下信息 :
@@ -40,7 +40,7 @@ class Album(models.Model):
Django拥有数十种内置的字段类型 ; 你可以在 [model field reference](https://docs.djangoproject.com/en/1.11/ref/models/fields/#model-field-types) 中找到完整列表 , 如果Django内置的字段不能满足我们的要求 , 那么我们可以进行自定义模型字段 : [Writing custom model fields](https://docs.djangoproject.com/en/1.11/howto/custom-model-fields/)
-## 字段选项 🍀
+## 字段选项
每个字段都接受一组与字段有关的参数 , 例如 , `CharField` (和它的派生类) 需要`max_length` 参数来指定`VARCHAR` 数据库字段的大小
@@ -104,7 +104,7 @@ class Person(models.Model):
注 : 上述仅仅对最常见的字段选项进行说明 , 完整查看 [common model field option reference](https://docs.djangoproject.com/en/1.11/ref/models/fields/#common-model-field-options)
-## 自增主键字段 🍀
+## 自增主键字段
默认 , Django给了每个模型一个主键字段 :
@@ -118,7 +118,7 @@ id = models.AutoField(primary_key=True)
每个模型只能有一个字段指定`primary_key=True`
-## 字段的自述名 🍀
+## 字段的自述名
除了`ForeignKey` , `ManyToManyField` 和 `OneToOneField` 之外 , 每个字段类型都接受一个可选的位置参数 , 即字段的自述名 (在第一的位置) ; 如果没有给定自述名 , Django将根据字段的属性名称自动创建自述名 , 即将属性名称的下划线替换成空格
@@ -149,7 +149,7 @@ place = models.OneToOneField(
习惯上 , `verbose_name` 的首字母不用大写 , Djnaog在必要的时候会自动大写首字母
-## 数据库关系 🍀
+## 数据库关系
关系型数据库的威力体现在表之间的相互关联 , 而Django提供了三种最常见的数据库关系 :
@@ -157,7 +157,7 @@ place = models.OneToOneField(
- 多对多 , many - to - many
- 一对一 , ont - to - one
-### 多对一 🍀
+### 多对一
Django使用`django.db.models.ForeignKey` 定义多对以关系
@@ -209,7 +209,7 @@ ForeignKey字段还接受许多别的参数 , 更多 : [the model field referen
多对一更多示例 : [Many-to-one relationship model example](https://docs.djangoproject.com/en/1.11/topics/db/examples/many_to_one/)
-### 多对多 🍀
+### 多对多
`ManyToManyField` 字段是用来定义多对多关系的 , 同使用其他字段类型一样
@@ -241,7 +241,7 @@ class Pizza(models.Model):
完整示例 : [Many-to-many relationship model example](https://docs.djangoproject.com/en/1.11/topics/db/examples/many_to_many/)
-### 中介模型 🍀
+### 中介模型
对与上一节中Pizza和Topping搭配这样简单的多对多关系时 , 使用标准的`ManyToManyField` 就可以了 , 但是有时我们可能需要关联数据到两个模型之间的上
@@ -348,7 +348,7 @@ datetime.date(1962, 8, 16)
'Needed a new drummer.'
```
-### 一对一 🍀
+### 一对一
`OneToOneField` 用来定义一对一关系 , 和使用其它字段类型一样
@@ -370,7 +370,7 @@ class OneToOneField(to, on_delete, parent_link=False, **options):
与ForeignKey一样 , 可以定义 [recursive relationship](https://docs.djangoproject.com/en/1.11/ref/models/fields/#recursive-relationships) 和 [references to as-yet undefined models](https://docs.djangoproject.com/en/1.11/ref/models/fields/#lazy-relationships)
-## Meta选项 🍀
+## Meta选项
使用内部的`class Meta` 可以定义模型的元数据 , 如下 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/10-Django - Model Making queries.md" b/docs/django/model-making-queries.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django/10-Django - Model Making queries.md"
rename to docs/django/model-making-queries.md
index a55d28d6c..944cc10d2 100644
--- "a/05-Web\346\241\206\346\236\266/Django/10-Django - Model Making queries.md"
+++ b/docs/django/model-making-queries.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
一旦我们建立好模型 , Django就会自动为我们生成一套数据库抽象的API , 可以让我们进行创建 , 检索 , 更新和删除对象 , 这篇文章主要阐述怎么去使用这些API
@@ -49,7 +49,7 @@ class Entry(models.Model):
return self.headline
```
-## 获取对象 🍀
+## 获取对象
从数据库获取对象 , 是通过模型中的[Manager](https://docs.djangoproject.com/en/1.11/topics/db/managers/#django.db.models.Manager) 构造出一个[QuerySet](https://docs.djangoproject.com/en/1.11/ref/models/querysets/) ; QuerySet表示从数据库中取出来的对象的集合 , 从SQL的角度来讲 , QuerySet与WHERE语句等价
@@ -66,7 +66,7 @@ all:QuerySet API
注意 : Manager只能通过模型类访问 , 而不能通过模型的实例访问 , 目的是为了强制区分"表级别" 的操作和"记录级别" 的操作 ; 对于一个模型来说 , Manager是QuerySet的主要来源
- ### 获取所有对象 🍀
+ ### 获取所有对象
可以使用Manager的`all()` 方法将一个表中的所有对象全部获取
@@ -75,7 +75,7 @@ all:QuerySet API
all_entries = Entry.objects.all()
```
-### 过滤器获取对象 🍀
+### 过滤器获取对象
`all()` 方法返回了一个包含数据库表中的所有记录的QuerySet , 但是通常情况下我们往往需要获取完整数据集的一个子集 , 即我们需要使用过滤器
@@ -95,7 +95,7 @@ Entry.objects.filter(pub_date_year=2006)
Entry.objects.all().filter(pub_date_year=2006)
```
-### 链接过滤器 🍀
+### 链接过滤器
QuerySet的筛选结果本身还是QuerySet , 所以可以将筛选语句链接在一起 , 如下 :
@@ -109,7 +109,7 @@ Entry.objects.filter(
)
```
-### QuerySet唯一性 🍀
+### QuerySet唯一性
每次筛选一个QuerySet , 得到的都是全新的另一个QuerySet , 它和之前的QuerySet没有任何绑定关系 , 每次筛选都会创建一个独立的QuerySet , 它可以被存储及反复使用 , 如下 :
@@ -125,7 +125,7 @@ q1不会受筛选过程的影响
'''
```
-### QuerySet惰性 🍀
+### QuerySet惰性
QuerySet是惰性执行的 , 创建QuerySet不会带来任何数据的访问 , 类似于Python中的生成器 , 你可以将过滤器保持一整天 , 知道QuerySet需要取值时 , Django才会真正执行这个查询 , 如下 :
@@ -137,7 +137,7 @@ q = q.exclude(body_text__icontains="food")
print(q)
```
-### QuerySet切片 🍀
+### QuerySet切片
QuerySet是支持切片的 , 它等同于SQL的OFFSET和LIMIT语句
@@ -152,7 +152,7 @@ Entry.objects.all()[5:10]
通常QuerySet的切片返回一个新的QuerySet , 它不会执行查询 , 但是如果使用Python切片语法中的` step` 参数 , 即步长 , 那么它将执行查询
-### 获取单个对象 🍀
+### 获取单个对象
如需获取单个对象 , 可以使用Manager的`get()` 方法
@@ -160,7 +160,7 @@ Entry.objects.all()[5:10]
one_entry = Entry.objects.get(pk=1)
```
-### 字段查询 🍀
+### 字段查询
字段查询是指如何指定SQL WHERE 子句的内容 , 通常使用过滤器的关键字参数指定
@@ -216,7 +216,7 @@ Entry.objects.filter(blog_id=4)
更多详细字段类型会在下一篇文章中整理
-### 跨表查询 🍀
+### 跨表查询
Django提供了一种强大又直观的方式来"处理"查询中的关联关系 , 它在后台自动帮你处理JOIN
@@ -249,7 +249,7 @@ models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
```
-### F expressions 🍀
+### F expressions
如果我们想将模型的一个字段与同一个模型的另外一个字段进行比较 , 可以使用`F()` 表达式
@@ -291,7 +291,7 @@ F('somefield').bitand(16)
更多F表达式相关 : [F expressions](https://docs.djangoproject.com/en/1.11/ref/models/expressions/#django.db.models.F)
-### 缓存与QuerySet 🍀
+### 缓存与QuerySet
每个QuerySet都包含一个缓存来最小化对数据的访问 , 在一个新创建的QuerySet中 , 缓存为空 ; 首次对QuerySet进行求值 , 同时发生数据库查询 , Django将保存查询的结果到QuerySet的缓存中并返回明确请求的结果 , 我们需要考虑的是对QuerySet重用缓存的问题
diff --git "a/05-Web\346\241\206\346\236\266/Django/09-Django - Model QuerySet API.md" b/docs/django/model-queryset-api.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/09-Django - Model QuerySet API.md"
rename to docs/django/model-queryset-api.md
index 1259be071..34f860d07 100644
--- "a/05-Web\346\241\206\346\236\266/Django/09-Django - Model QuerySet API.md"
+++ b/docs/django/model-queryset-api.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
我们知道Django中存在着大量的接口 , 而跟QuerySet 就是一个Model相关的接口 , 它建立在 [model](https://docs.djangoproject.com/en/1.11/topics/db/models/) 和 [database query](https://docs.djangoproject.com/en/1.11/topics/db/queries/) 指南的基础上 , 而这两个指南已经在前面的文章整理完成了 , 但是对于QuerySet API的整理还不完全
@@ -45,7 +45,7 @@
- bool() , 测试布尔值 , 例如使用`bool()` , and , or 或者if语句将导致查询集的执行
-## Pickling QuerySet 🍀
+## Pickling QuerySet
如果你pickle一个`QuerySet` , 它将在pickle之前强制将所有的结果加载到内存中 ; pickle通常用于缓存之前 , 并且当缓存的查询集重新加载时 , 你希望结果已经存在随时准备使用 ; 不过注意 , pickle的数据只是pickle时的 , 也就是说pickle的数据不是即时的
@@ -62,7 +62,7 @@ query是一个不透明的对象 , 它表示查询的内部构造 , 不属于公
注意 : `QuerySet` 的pickle在不同的Django版本中是不保证兼容的 , 所以pickle不可用于归档的长期策略
-## QuerySet API 🍀
+## QuerySet API
```python
class QuerySet(model=None, query=None, using=None):
@@ -84,7 +84,7 @@ QuerySet API 中有非常多的方法供我们使用 , 分为如下几种 :
- field查找
- 聚合函数
-## 返回QuerySet 🍀
+## 返回QuerySet
Django提供了一系列的QuerySet筛选方法 , 用于改变QuerySet返回的结果类型或者SQL查询执行的方式
@@ -585,7 +585,7 @@ raw(raw_query,params=None,translations=None):
`raw()` 永远触发一个新的查询 , 而与之前的filter无关 ; 因此 , 它通常应该从Manager或一个全新的QuerySet实例调用
-## 不返回QuerySet 🍀
+## 不返回QuerySet
以下方法对QuerySet进行求值并返回 , 返回结果不是QuerySet
@@ -817,7 +817,7 @@ if some_queryset.filter(pk=entry.pk).exists():
类方法 , 返回Manager的实例与QuerySet的方法的副本
-## Field查询 🍀
+## Field查询
字段查询是指如何指定SQL WHERE子句的内容 , 它通过`QuerySet的filter()` , `exclude()` 和 `get()` 的关键字参数指定 , 即使用双下划线时后的参数
@@ -1110,7 +1110,7 @@ SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
```
-## 聚合函数 🍀
+## 聚合函数
Django的`django.db.models` 模块提供以下聚合函数 , 关于如果使用这些聚合函数的细节 , 参考 [the topic guide on aggregation](https://docs.djangoproject.com/en/1.11/topics/db/aggregation/) , 如何创建聚合函数 , 参考 [`Aggregate`](https://docs.djangoproject.com/en/1.11/ref/models/expressions/#django.db.models.Aggregate)
diff --git "a/05-Web\346\241\206\346\236\266/Django/06-Django - Model.md" b/docs/django/model.md
similarity index 94%
rename from "05-Web\346\241\206\346\236\266/Django/06-Django - Model.md"
rename to docs/django/model.md
index cf4145967..ed0baa57c 100644
--- "a/05-Web\346\241\206\346\236\266/Django/06-Django - Model.md"
+++ b/docs/django/model.md
@@ -1,15 +1,15 @@
# Django - Model
-
-
-
-
-
-
-
-
-
-## 介绍 🍀
+
+
+
+
+
+
+
+
+
+## 介绍
在我们的Web应用中 , 与数据库的交互不可避免 ; 数据库驱动网站在后台链接数据库服务器 , 从中取出一些数据 , 然后在Web页面用漂亮的格式展示这些数据 , 这就是我们需要的模型(Model)
@@ -25,7 +25,7 @@
注意 : 我们创建模型前 , 需要将数据库相关配置完成 , 方法见settings整理文章
-## 简单示例 🍀
+## 简单示例
首先创建一个应用
@@ -135,7 +135,7 @@ CREATE TABLE myapp_userinfo (
}
```
-## 添加数据 🍀
+## 添加数据
添加数据需要先创建对象 , 然后再执行save函数 , 相当于SQL中的INSERT
@@ -170,7 +170,7 @@ urlpatterns = [
访问http://127.0.0.1:8000/testdb/ 完成添加
-## 查询数据 🍀
+## 查询数据
myapp/views.py
@@ -206,7 +206,7 @@ urlpatterns = [
]
```
-## 删除数据 🍀
+## 删除数据
myapp/views.py
@@ -227,7 +227,7 @@ urlpatterns = [
]
```
-## 更新数据 🍀
+## 更新数据
myapp/views.py
diff --git "a/05-Web\346\241\206\346\236\266/Django/02-Django - Django\345\210\235\350\257\206.md" b/docs/django/quickstart.md
similarity index 96%
rename from "05-Web\346\241\206\346\236\266/Django/02-Django - Django\345\210\235\350\257\206.md"
rename to docs/django/quickstart.md
index e6c2515e0..3807553cc 100644
--- "a/05-Web\346\241\206\346\236\266/Django/02-Django - Django\345\210\235\350\257\206.md"
+++ b/docs/django/quickstart.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
通过上一篇整理 , 对于Web框架应该清晰了很多 , 当然上一篇仅仅是自定义了一个最low , 最底端的Web框架 , 基本仅能处理特定的HTTP请求 , 那么这一章就开始学习Python Web框架中的王牌——Django
@@ -43,7 +43,7 @@ $pip install django
C:\Python3.5\Scripts - 具体路径自行添加
```
-## 创建一个Django项目 🍀
+## 创建一个Django项目
我们使用命令行来进行创建 , 命令如下
@@ -67,7 +67,7 @@ mysite
**PS : 如果我们使用`Pycharm` 来完成这项操作 , 那么其还会为我们自动创建一个`templates` 文件夹 , 用于存放模板**
-## 启动Django项目 🍀
+## 启动Django项目
创建完成后我们就可以通过以下命令启动Django项目了
@@ -83,7 +83,7 @@ python manage.py runserver 0.0.0.0:8000
![runserver](http://oux34p43l.bkt.clouddn.com/runserver.png?imageMogr2/blur/1x0/quality/75|watermark/2/text/bHlvbi55YW5nQHFxLmNvbQ==/font/YXBhcmFqaXRh/fontsize/560/fill/Izk0ODI4Mg==/dissolve/100/gravity/SouthEast/dx/10/dy/10)
-## 创建一个Django模型 🍀
+## 创建一个Django模型
Django规定 , 如果要使用应用模型 , 必须要创建一个app
@@ -124,7 +124,7 @@ INSTALLED_APPS = [
]
```
-## 同步数据库 🍀
+## 同步数据库
在同步数据库之前需要先生成同步数据库的脚本 , 一般我们创建一个模型时这一步都自动为我们生成了 , 如果没有 , 则可以使用如下命令生成同步数据库的脚本
@@ -138,7 +138,7 @@ python manage.py makemigrations
python manage.py migrate
```
-## 访问admin 🍀
+## 访问admin
django admin是django提供的一个后台管理页面 , 如果我们使用django admin则需要提前创建好后台管理员 (超级用户) , 以及url的配置
diff --git "a/05-Web\346\241\206\346\236\266/02-REST.md" b/docs/django/rest.md
similarity index 96%
rename from "05-Web\346\241\206\346\236\266/02-REST.md"
rename to docs/django/rest.md
index 80f7b7f81..4c73d6a04 100644
--- "a/05-Web\346\241\206\346\236\266/02-REST.md"
+++ b/docs/django/rest.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
REST 是 Representational State Transfer (表征状态转移) 的缩写
@@ -17,7 +17,7 @@ REST 是 Representational State Transfer (表征状态转移) 的缩写
用一个 URI (统一资源定位符) 指向资源 , 使用 HTTP 请求方法操作资源 , URL 可进一步划分为统一资源名 (URN , 代表资源的名字) 和统一资源定位符 (URL , 代表资源的地址) , 其中 URL 可以定位 HTTP 网址 , FTP 服务器和文件路径等 , 符合绝大多数场景 , 所以一般都可以用 URL 代替 URI
-## REST架构约束 🍀
+## REST架构约束
REST 架构风格最重要的架构约束有如下 5 个 :
@@ -32,9 +32,9 @@ REST 架构风格最重要的架构约束有如下 5 个 :
如果一个架构符合 REST 原则 , 就称它为 RESTful 架构
-## RESTful API设计指南 🍀
+## RESTful API设计指南
-### 使用名词表示资源 🍀
+### 使用名词表示资源
URI 不应该包含动词 , 动词应该通过不同的 HTTP 方法来体现
@@ -54,11 +54,11 @@ DELETE /users/1
PUT /users/1
```
-### 关注请求头 🍀
+### 关注请求头
一定要看请求头信息 , 并给予正确的状态码 , 例如 , 假设服务端只能返回 JSON 格式 , 如果客户端的头信息的 Accept 字段要求返回 `application/xml` , 这个时候就不应该返回 `application/json` 类型的数据 , 而应该返回 406 错误
-### 合理使用请求方法和状态码 🍀
+### 合理使用请求方法和状态码
方法语义说明
@@ -72,7 +72,7 @@ PUT /users/1
| PATCH | 用于局部更新资源 :
1. 完成请求后 , 返回状态码 200 OK
2. 完成请求后 , 需要返回被修改的资源详细信息 |
| DELETE | 用于删除某个资源 , 完成请求后返回状态码 204 NO Content |
-### 使用嵌套对象序列化 🍀
+### 使用嵌套对象序列化
对象应该合理地嵌套 , 不应该都在一个层次上 , 如下的格式是不正确的 :
@@ -98,7 +98,7 @@ PUT /users/1
}
```
-### 版本 🍀
+### 版本
常见的区分版本方法有三种 :
@@ -108,11 +108,11 @@ PUT /users/1
推荐使用第一种方法
-### URI失效和迁移 🍀
+### URI失效和迁移
随着业务发展 , 会出现一些 API 失效或者迁移 , 对失效的 API , 应该返回 "404 not found" 或 "401 gone" ; 对迁移的 API , 返回 301 重定向
-## 速度限制 🍀
+## 速度限制
为了避免请求泛滥 , 给 API 设置速度限制很重要 , 为此 RFC 6585 引入了 HTTP 状态码 429 (too many requests)
@@ -138,7 +138,7 @@ X-RateLimit-Reset: 1530220396
...
```
-## 缓存 🍀
+## 缓存
数据内容在一段时间不会变动 , 这个时候我们就可以合理地减少 HTTP 响应内容 , 应该在响应头中携带 Last-Modified , ETag , Vary , Date 等信息 , 客户端可以在随后请求这些资源时 , 在请求头中使用 `If-Modified-Since` , `If-None-Match` 等来确认资源是否进过修改 , 如果资源没有做过修改 , 那么就可以响应 `"304 Not Modified"` , 并且不在响应实体中返回任何内容
@@ -172,7 +172,7 @@ Vary: Accept-Encoding
>http https://api.github.com/users/lyonyang "If-Modified-Since: Thu, 04 Feb 2016 14:05:03 GMT" --headers
```
-## 并发控制 🍀
+## 并发控制
缺少并发控制的 PUT 和 PATCH 请求可能导致 "更新丢失" , 这个时候可以使用 Last-Modified 和 ETag 头来实现条件请求 , 具体原则如下 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/15-Django - Sessions.md" b/docs/django/sessions.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django/15-Django - Sessions.md"
rename to docs/django/sessions.md
index 3c71d4880..6e59d95d7 100644
--- "a/05-Web\346\241\206\346\236\266/Django/15-Django - Sessions.md"
+++ b/docs/django/sessions.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
基于 Internet的各种服务系统应运而生 , 建立商业站点或者功能比较完善的个人站点 , 常常需要记录访问者的一些信息 ; 论坛作为 Internet发展的产物之一 , 在 Internet 中发挥着越来越重要的作用 , 是用户获取、交流、传递信息的主要场所之一 , 论坛常常也需要记录访问者的一些基本信息 (如身份识别号码、密码、用户在 Web 站点购物的方式或用户访问该站点的次数) ; 目前公认的是 , 通过 Cookie 和 Session 技术来实现记录访问者的一些基本信息
@@ -77,7 +77,7 @@ Django支持所有的匿名会话 , 简单说就是使用跨网页之间可以
它将数据存储在服务端 , 并以Cookies的形式进行发送和接收数据 , Cookies包含一个Session ID , 而不是数据本身 (除非你使用的基于Cookie的后端)
-## 启用Sessions 🍀
+## 启用Sessions
Django中的Sessions是通过中间件实现的
@@ -86,17 +86,17 @@ Django中的Sessions是通过中间件实现的
- 编辑`settings.py`中的`MIDDLEWARE` , 确保其中包含`django.contrib.sessions.middleware.SessionMiddleware` ; 默认在我们使用`django-admin startproject` 命令时 , `settings.py`中已经启用该中间件
- 如果你不想使用Sessions , 你可以将`MIDDLEWARE`中的`SessionMiddleware`移除以及将`INSTALLED_APPS`中的`django.contrib.sessions`移除 , 它能够为你节省一点开销
-## 配置Session引擎 🍀
+## 配置Session引擎
默认情况下 , Django存储会话到你的数据库中 (使用`django.contrib.sessions.models.Session`) , 尽管这很方便 , 但是在某些情况下 , 在其他地方存储会话数据的速度更快 , 因此Django可以配置为在文件系统或缓存中存储会话数据
-### 数据库 🍀
+### 数据库
如果你想使用数据库支持的会话 , 你需要添加`django.contrib.sessions` 到你`settings.py`中的INSTALLED_APP设置中 , 默认就是使用的数据库
在配置完成之后 , 需要执行`manage.py migrate` 来安装村粗会话数据的一张数据库表
-### 缓存 🍀
+### 缓存
为了更好的性能 , 我们可以使用一个基于缓存的会话后端
@@ -115,13 +115,13 @@ Django中的Sessions是通过中间件实现的
注意使用`cached_db`会话后端 , 需要遵循 [using database-backed sessions](https://docs.djangoproject.com/en/1.11/topics/http/sessions/#using-database-backed-sessions)
-### 文件 🍀
+### 文件
要使用基于文件的会话 , 将`SESSION_ENGINE`为`django.contrib.sessions.backends.file`
你可以设置`SESSION_FILE_PATH`来控制Djanog存储会话文件的地址 , 默认来自`tempfile.gettempdir()` ,大多数情况下为`/tmp` , 当然请确保你的Web服务器具有读取和写入这个位置的权限
-### Cookie 🍀
+### Cookie
同样 , 使用基于Cookie的会话 , 设置`SESSION_ENGINE`为`django.contrib.sessions.backends.signed_cookies` , 此时 , 会话数据的存储将使用Django的工具进行[cryptographic signing](http://python.usyiyi.cn/documents/Django_111/topics/signing.html) 和 [SECRET_KEY](https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-SECRET_KEY) 设置
@@ -152,7 +152,7 @@ Django中的Sessions是通过中间件实现的
最后 , Cookie的大小对你网站的速度有影响
-## 视图中使用Session 🍀
+## 视图中使用Session
当`SessionMiddleware`激活时 , 每个HttpRequest对象 , 也就是传递给Django视图函数的第一个参数 , 将会具有一个`session`属性 , 它是一个类似字典对象
@@ -242,7 +242,7 @@ class backends.base.SessionBase
'''
```
-### 序列化 🍀
+### 序列化
默认情况下 , Django使用JSON序列化会话数据 , 你额可以使用`SESSION_SERIALIZER`设置顶顶亿会话序列化格式 , 即使是使用我们写自己的序列化器 , 同样强烈建议使用JSON , 特别是在使用Cookie后端时 ; 自定义序列化器 : [Write your own serializer](https://docs.djangoproject.com/en/1.11/topics/http/sessions/#custom-serializers)
@@ -250,7 +250,7 @@ class backends.base.SessionBase
在因特网上这个攻击技术很简单并且很容易差到 , 尽管Cookie会话的存储对Cookie保存的数据进行了签名以防止篡改 , `SECRET_KEY`的泄漏会立即使得可以执行远程代码
-### 捆绑序列化器 🍀
+### 捆绑序列化器
```python
class serializers.JSONSerializer:
@@ -279,7 +279,7 @@ class serializers.PickleSerializer:
"""支持任意Python对象,但是可能导致远程执行代码的漏洞,如果攻击者知道了SECRET_KEY"""
```
-### 自定义序列化器 🍀
+### 自定义序列化器
对于`PickleSerializer`与`JSONSerializer`两者的差别 , 这是常见的情况 , 需要我们在便利性和安全性之间权衡
@@ -287,13 +287,13 @@ class serializers.PickleSerializer:
我们自定义序列化器时 , 必须实现两个方法 , `dumps(self, obj)`和`loads(self,data)` 来分别序列化和反序列化会话数据的字典
-### 会话对象 🍀
+### 会话对象
- 在`request.session`上使用普通的Python字符串作为字典的键 , 这主要是为了方便而不是一条必须遵守的规则
- 以一个下划线开始的会话字典的键被Django保留作为内部使用
- 不要用新的对象覆盖`request.session` , 且不要访问或设置它的属性 , 要像Python中的字典一样使用它
-## 设置Cookie测试 🍀
+## 设置Cookie测试
为了方便 , Django提供了一个简单的方法来测试用户的浏览器是否支持Cookie ; 只需要在一个视图中调用`request.session`中的`set_cookie_worked()` , 并在下一个视图中调用`test_cookie_worked()` , 注意不是在同一个视图中调用
@@ -318,7 +318,7 @@ def login(request):
return render(request, 'foo/login_form.html')
```
-##视图外使用Sessions 🍀
+##视图外使用Sessions
这一节中的示例直接从`django.contrib.session.backends.db`导入`SessionStore` , 在我们的代码中应该从`SESSION_ENGINE`中导入SessionStore , 如下 :
@@ -365,7 +365,7 @@ datetime.datetime(2005, 8, 20, 13, 35, 12)
{'user_id': 42}
```
-## 会话保存 🍀
+## 会话保存
默认情况下 , Django只有在会话被修改时才会保存会话到数据库中 , 即它的字典中的任何值被修改时
@@ -398,7 +398,7 @@ request.session.modified = True
如果响应的状态是500 , 则会话不会保存
-## 会话时长 🍀
+## 会话时长
你可以通过`SESSION_EXPIRE_AT_BROWSER_CLOSE`配置来控制会话框架使用浏览器时长的会话 , 还是持久的会话
@@ -410,7 +410,7 @@ request.session.modified = True
注意 : 某些浏览器 (如Chrome) 提供一种设置 , 允许用户在关闭并重新打开浏览器后继续使用会话 , 在某些情况下 , 这可能干扰`SESSION_EXPIRE_AT_BROWSER_CLOSE`设置并导致会话在浏览器关闭后不过期 , 在测试启用`SESSION_EXPIRE_AT_BROWSER_CLOSE`设置的Django应用时需要特别注意这一点
-## 清除会话存储 🍀
+## 清除会话存储
随着用户在你的网站上创建新的会话 , 会话数据可能会在你的会话存储仓库中积累 , 如果你正在使用数据库作为后端 , `django_session`数据库表将持续增长 ; 如果你正在使用文件作为后端 , 你的临时目录包含的文件数量将持续增长
diff --git "a/05-Web\346\241\206\346\236\266/Django/03-Django - Settings.md" b/docs/django/settings.md
similarity index 95%
rename from "05-Web\346\241\206\346\236\266/Django/03-Django - Settings.md"
rename to docs/django/settings.md
index 8e3d30f70..4dc3598cc 100644
--- "a/05-Web\346\241\206\346\236\266/Django/03-Django - Settings.md"
+++ b/docs/django/settings.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
Django项目的配置信息在Django项目建立时就已经为我们创建完成 , 也就是目录下的`settings.py` 文件
@@ -19,13 +19,13 @@ Django项目的配置信息在Django项目建立时就已经为我们创建完
本章配置文件根据Django 1.11x 描述 , 并仅为初始基本配置
-## SECRET_KEY 🍀
+## SECRET_KEY
`SECRET_KEY` 为一个特定的Django安装密钥 , 用于提供加密签名
使用`django-admin startproject` 命令时为每一个项目随机生成 , 如果`SECRET_KEY` 没有设置 , Django将拒绝启动
-## DEBUG 🍀
+## DEBUG
`DEBUG` 配置默认为`True` , 在此状态下会暴露出一些错误信息或者配置信息以方便调试 , 但是上线后应该将其关掉 , 防止配置信息或者敏感错误信息泄漏
@@ -33,7 +33,7 @@ Django项目的配置信息在Django项目建立时就已经为我们创建完
DEBUG = False
```
-## ALLOWED_HOSTS 🍀
+## ALLOWED_HOSTS
`ALLOWED_HOSTS` 是为了限定请求中的host值 , 以防止黑客构造包来发送请求 , 只有在列表中的host才能访问 , 建议不要使用通配符去配置
@@ -48,7 +48,7 @@ ALLOWED_HOSTS = [
]
```
-## INSTALLED_APPS 🍀
+## INSTALLED_APPS
`INSTALLED_APPS` 是一个列表 , 里面是应用中需要加载的自带或者自定义的app包路经列表 , 所以我们每创建一个应用都需要在这里进行添加 , 如下 :
@@ -64,7 +64,7 @@ INSTALLED_APPS = [
]
```
-## MIDDLEWARE 🍀
+## MIDDLEWARE
`MIDDLEWARE` 是一个列表 , 里面为要使用的中间件列表 , 默认如下 :
@@ -80,7 +80,7 @@ MIDDLEWARE = [
]
```
-## ROOT_URLCONF 🍀
+## ROOT_URLCONF
`ROOT_URLCONF` 为一个字符串 , 代表你的根URLconf的模块名 , 如下 :
@@ -88,7 +88,7 @@ MIDDLEWARE = [
ROOT_URLCONF = 'mydjango.urls'
```
-## TEMPLATES 🍀
+## TEMPLATES
`TEMPLATES` 为一个包含所有模板引擎设置的列表 , 列表中的每一项都是一个包含单个引擎选项的字典 , 如下 :
@@ -118,7 +118,7 @@ TEMPLATES = [
]
```
-## WSGI_APPLICATION 🍀
+## WSGI_APPLICATION
`WSGI_APPLICATION` 为Django内置服务器 (如runserver) 的应用程序对象的完整Python路径
@@ -128,7 +128,7 @@ TEMPLATES = [
WSGI_APPLICATION = 'mydjango.wsgi.application'
```
-## DATABASES 🍀
+## DATABASES
`DATABASES` 为一个包含所有数据库配置的字典 , 它是一个嵌套的字典 , 其内容将数据库别名映射到包含单个数据库选项的字典
@@ -147,7 +147,7 @@ DATABASES = {
}
```
-## AUTH_PASSWORD_VALIDATORS 🍀
+## AUTH_PASSWORD_VALIDATORS
`AUTH_PASSWORD_VALIDATORS` 是一个列表 , 用于检查用户密码强度验证程序的列表
@@ -168,7 +168,7 @@ AUTH_PASSWORD_VALIDATORS = [
]
```
-## LANGUAGE_CODE 🍀
+## LANGUAGE_CODE
`LANGEUAGE_CODE` 是一个字符串 , 默认为 `'en-us'` , 即一个表示安装的语言代码的字符串 , 为标准语言ID格式 , 美国英语是 `'en-us'`
@@ -178,7 +178,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us'
```
-## TIME_ZONE 🍀
+## TIME_ZONE
`TIME_ZONE` 表示此安装时区的字符串 , 新版本默认为`'UTC'` , 这不一定是服务器的时区 , 因为一个服务器可以服务多个Django支持的站点 , 每个站点都有一个单独的时区设置
@@ -188,7 +188,7 @@ LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
```
-## USE_I18N 🍀
+## USE_I18N
`USE_I18N` 为一个bool值 , 指定Django的翻译系统是否应该启动 , 如果设置为`False` , Django将进行一些优化 , 以避免加载翻译器
@@ -196,7 +196,7 @@ TIME_ZONE = 'UTC'
USE_I18N = True
```
-## USE_L10N 🍀
+## USE_L10N
`USE_L10N` 为一个bool值 , 它指定了默认的数据的本地化格式是否可以在默认情况下使用 , 如果为`True` , Django将用当前的语言环境来显示数字和日期
@@ -204,7 +204,7 @@ USE_I18N = True
USE_L10N = True
```
-## USE_TZ 🍀
+## USE_TZ
`USE_TZ` 为一个bool值 , 指定日期时间默认情况下是否是时区感知的 , 如果设置为`True` , Django将在内部使用时区感知的日期时间
@@ -212,7 +212,7 @@ USE_L10N = True
USE_TZ = True
```
-## STATIC_URL 🍀
+## STATIC_URL
`STATIC_URL` 为一个引用名 , 引用位于`STATIC_ROOT`的静态文件 , `STATIC_ROOT` 如下 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/54-Django - \346\272\220\347\240\201\344\271\213admin.md" b/docs/django/source-admin.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/54-Django - \346\272\220\347\240\201\344\271\213admin.md"
rename to docs/django/source-admin.md
index 9912861d7..81ca370e6 100644
--- "a/05-Web\346\241\206\346\236\266/Django/54-Django - \346\272\220\347\240\201\344\271\213admin.md"
+++ b/docs/django/source-admin.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
Django为我们提供了一个强大的后台管理页面 , 也就是admin
@@ -33,7 +33,7 @@ url(r'^admin/', admin.site.urls)
- /admin/application/table/1/delete/ # 删除数据
```
-## admin.site.urls 🍀
+## admin.site.urls
在源码目录中 , `admin` 下的 `sites.py` 中使用了一个全局对象
@@ -109,7 +109,7 @@ def get_urls(self):
return urlpatterns
```
-## register 🍀
+## register
注册model到`self._registry` , 是通过`register()`实现的 , 如 : `admin.site.register(models.UserInfo)`
@@ -163,7 +163,7 @@ def register(self, model_or_iterable, admin_class=None, **options):
`self._registry` 是一个字典 , 最后注册完成后 , 字典的元素的key 为 `modes.UserInfo` , 而value则是一个ModelAdmin对象 , 对于model的url生成 , 就藏在ModelAdmin中
-## ModelAdmin 🍀
+## ModelAdmin
提取ModelAdmin中的部分内容
@@ -248,7 +248,7 @@ class ModelAdmin(BaseModelAdmin):
pass
```
-## 自定制Admin 🍀
+## 自定制Admin
当我们在`admin.py` 中间注册我们的model时 , 一般我们只需要传入一个参数 , 就是我们的model , 因为django为我们默认是用了ModelAdmin , 也就是`admin_class`参数 , 当然我们可以自己传入这个`admin_class` , 这样我们就可以完全定制属于我们自己admin了
diff --git "a/05-Web\346\241\206\346\236\266/Django/52-Django - \346\272\220\347\240\201\344\271\213middleware.md" b/docs/django/source-middleware.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/52-Django - \346\272\220\347\240\201\344\271\213middleware.md"
rename to docs/django/source-middleware.md
index ddd8ff68b..6356d4753 100644
--- "a/05-Web\346\241\206\346\236\266/Django/52-Django - \346\272\220\347\240\201\344\271\213middleware.md"
+++ b/docs/django/source-middleware.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
在关于上一篇`runserver`命令的分析中 , 实际上我们跳过了一步 , 那就是关于中间件加载的
@@ -55,7 +55,7 @@ def __init__(self, *args, **kwargs):
self.load_middleware()
```
-## load_middleware 🍀
+## load_middleware
```python
def load_middleware(self):
@@ -174,7 +174,7 @@ def __init__(self, *args, **kwargs):
而在新版本中 , 请求经过的中间件和响应经过的中间件层数是一样的 , 也就是说 , 一旦发生短路 , 响应就会按照相反的顺序返回 , 根本不会到达后面的中间件 , 所以这也是为什么在下部分代码中 , 只有视图中间件 , 模板中间件和异常中间件相关的内容了
-## self._get_response 🍀
+## self._get_response
那么接下来我们就需要看看关于这后部分三个中间件的细节内容了 , 它们在`self._get_response()`中 , 该方法在初始化时就已经被传入各个中间件中 :
@@ -347,7 +347,7 @@ def get_response(self, request):
到这里 , 对于中间件的分析就差不多了 , 是时候理一理了
-## 小结 🍀
+## 小结
首先 , 中间件的加载是在启动时就已经加载完成 , 也就是还没有执行`httpd.serve_forever()`之前就已经完成
diff --git "a/05-Web\346\241\206\346\236\266/Django/51-Django - \346\272\220\347\240\201\344\271\213runserver.md" b/docs/django/source-runserver.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/51-Django - \346\272\220\347\240\201\344\271\213runserver.md"
rename to docs/django/source-runserver.md
index c7ab6eb3e..5e5cccaba 100644
--- "a/05-Web\346\241\206\346\236\266/Django/51-Django - \346\272\220\347\240\201\344\271\213runserver.md"
+++ b/docs/django/source-runserver.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
上一篇中 , 我们分析了Django项目从无到有的过程 , 也就是`django-admin startproject`命令 , 随后我们要做的就是启动这个项目 , 也就是执行`django-admin runserver`命令
@@ -47,7 +47,7 @@ def execute(self):
实际上执行runserver与startproject是一样的 , 只不过在配置时 , runserver会进行一些错误检查 , 主要是为了检查其兼容性 , 随后像其他命令一样 , 实例化各自模块中的Command类 , 随后调用`execute()` → `handle()` , 我们直接从`handle()`开始
-## handle 🍀
+## handle
`django/core/management/commands/runserver.py`
@@ -154,7 +154,7 @@ def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGISe
httpd.serve_forever()
```
-## 处理请求 🍀
+## 处理请求
调用`serve_forver()`之后 , 我们的服务端就已经做好随时 "接客" (HTTP请求) 的准备了
@@ -346,7 +346,7 @@ def finish_response(self):
self.close()
```
-## 小结 🍀
+## 小结
分析过程中 , 为了避免派生类重写了基类中的方法而导致分析出错 , 不妨将所有方法整合到一个类中 , 虽然这个工作也不好做 , 但是却是不会出错
diff --git "a/05-Web\346\241\206\346\236\266/Django/50-Django - \346\272\220\347\240\201\344\271\213startproject.md" b/docs/django/source-startproject.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/50-Django - \346\272\220\347\240\201\344\271\213startproject.md"
rename to docs/django/source-startproject.md
index f053d471f..4db663ee9 100644
--- "a/05-Web\346\241\206\346\236\266/Django/50-Django - \346\272\220\347\240\201\344\271\213startproject.md"
+++ b/docs/django/source-startproject.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
django是Python中的一个Web框架 , 它的本质其实就是一个别人已经为我们写好了的 , Python第三方库
@@ -71,7 +71,7 @@ django
分析时 , 源码省略部分以pass带过
-## 开始 🍀
+## 开始
在我们使用命令行安装django时 , 通常都会自动为我们添加一个环境变量 , 也就是`django/bin/django-admin.py`这个文件 , 我们可是在命令行输入`django-admin`命令来测试是否已经添加了环境变量
@@ -138,7 +138,7 @@ if __name__ == "__main__":
在这个入口中 , 我们看到了django真正的入口 , 也就是在这个`management`里面 , 接下来我们看看我们在命令行输出的命令django是如何解析的
-## startproject 🍀
+## startproject
以`django-admin startprojec`为例 , 首先我们切换到要存放项目的目录 , 然后在命令行输入一下命令
@@ -338,7 +338,7 @@ def execute(self):
接下来我们看看最后的这个`fetch_command(subcommand)` 和 `run_from_argv(self.argv) `
-## fetch_command() 🍀
+## fetch_command()
`management/__init__.py`
@@ -382,7 +382,7 @@ def execute(self):
下面详细的解释一下`load_command_class()`
-## load_command_class( ) 🍀
+## load_command_class( )
`management/__init__.py`
@@ -401,7 +401,7 @@ def load_command_class(app_name, name):
return module.Command()
```
-## run_from_argv( ) 🍀
+## run_from_argv( )
那么到这里 , 准备工作已经全部完成 , 现在就是真正的执行时刻了 , :koala:
@@ -466,7 +466,7 @@ def handle(self, *args, **options):
最后TemplateCommand类中的`handle()`会为我们进行Django项目的布局到指定目录 , 至此 , 命令执行完毕 , 我们所看到的所有默认目录也已经创建完毕
-## 小结 🍀
+## 小结
到这里对于django项目的开始已经有了基本的了解了 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/53-Django - \346\272\220\347\240\201\344\271\213url.md" b/docs/django/source-url.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/53-Django - \346\272\220\347\240\201\344\271\213url.md"
rename to docs/django/source-url.md
index ece70027c..2dba6e787 100644
--- "a/05-Web\346\241\206\346\236\266/Django/53-Django - \346\272\220\347\240\201\344\271\213url.md"
+++ b/docs/django/source-url.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
上一篇对中间件的源码进行了阅读 , 我们知道了 , 当请求到来时 , 首先会应用请求中间件 , 随后就是进行URL匹配 , 去寻找对应的视图了
@@ -54,7 +54,7 @@ def _get_response(self, request):
由上可知 , 在`_get_response()` 中构造了RegexURLResolver对象 , 随后调用该对象的 `resolve()` 方法 , 最后从返回值中获取视图函数与参数
-## resolve 🍀
+## resolve
```python
def resolve(self, path):
@@ -126,7 +126,7 @@ def url(regex, view, kwargs=None, name=None):
首先我们来看看第二种 , 也就是view为函数的情况 , 其返回一个RegexURLPattern对象
-## RegexURLPattern 🍀
+## RegexURLPattern
```python
class RegexURLPattern(LocaleRegexProvider):
@@ -193,7 +193,7 @@ class ResolverMatch(object):
接下来就是第二种情况了 , 也就是view为`include()` 返回的结果 , 它是一个元组 , 形式 : `(list,tuple)`
-## include 🍀
+## include
首先我们需要弄清楚 , include返回的元组中到底有什么内容 , 其源码如下 :
@@ -302,7 +302,7 @@ urlpatterns = [
]
```
-## 小结 🍀
+## 小结
在这一章关于URL的源码中 , 印象最深刻的还属 `__get__` 的使用 , 构造描述器类 ( `LocaleRegexDescriptor` )来完成需求 , 以及以解包的方式获取 `__gitItem__` 中的相关值
diff --git "a/05-Web\346\241\206\346\236\266/Django/13-Django - Template Language.md" b/docs/django/template-language.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django/13-Django - Template Language.md"
rename to docs/django/template-language.md
index 0eee59dda..3ed8a34cd 100644
--- "a/05-Web\346\241\206\346\236\266/Django/13-Django - Template Language.md"
+++ b/docs/django/template-language.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
模板只是一个文本文件 , 它能够生成以下文本格式的文件 , 如 : HTML , XML , CSV , etv等
@@ -33,7 +33,7 @@
**模板包括在使用时会被替换掉的变量 , 以及控制模板逻辑的标签**
-## 变量 🍀
+## 变量
**定义变量**
@@ -80,7 +80,7 @@ My first name is John. My last name is Doe.
# 由于字典查找首先发生,该行为将启动并提供一个默认值,而不是使用预期的iteritems()方法,在这种情况下,我们应该考虑先转换成字典
```
-## 过滤器 🍀
+## 过滤器
可以通过过滤器来修改变量的显示 , 使用 "|" 来应用过滤器
@@ -131,7 +131,7 @@ Django中提供了大约60个内置的模板过滤器 , 以下是一些常用的
更多内置过滤器 : [built-in filter reference](https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ref-templates-builtins-filters)
-## 标签 🍀
+## 标签
标签比变量更复杂 : 标签可以在输出中创建文本 ; 执行循环或逻辑控制 ; 将外部信息加载到模板中以供以后的变量使用
@@ -196,7 +196,7 @@ Django附带大约二十个内置模板标签 , 以下是一些常用标签 :
自定义模板标签和过滤器 : [Custom template tags and filters](https://docs.djangoproject.com/en/1.10/howto/custom-template-tags/)
-## 注释 🍀
+## 注释
要在模板中注释行的一部分 , 可以使用注释语法 :
@@ -209,7 +209,7 @@ Django附带大约二十个内置模板标签 , 以下是一些常用标签 :
{% endcomment %}
```
-## 模板继承 🍀
+## 模板继承
Django模板引擎中最强大 , 也是最复杂的部分是模板继承 , 模板继承允许你创建一个基本 "框架" 模板 , 其中包含网站所有常用元素 , 并定义子模板可以覆盖的块
@@ -294,7 +294,7 @@ base.html
{% endblock content %}
```
-## 自动HTML转义 🍀
+## 自动HTML转义
为了避免变量值中带有的HTML字符被解析 , 我们有两种方式 :
diff --git "a/05-Web\346\241\206\346\236\266/Django/12-Django - Template.md" b/docs/django/template.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Django/12-Django - Template.md"
rename to docs/django/template.md
index b69af69fc..0c59a85c6 100644
--- "a/05-Web\346\241\206\346\236\266/Django/12-Django - Template.md"
+++ b/docs/django/template.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
本篇相当于一个引子 , 了解即可 , 我们一般不这样去使用
@@ -91,7 +91,7 @@ Python使用模板系统是一个三步过程 :
**注意 : 这一篇主要对于模板引擎的配置 , Template对象 , Context对象进行描述 ; 但是我们一般不会自己创建Template和Context对象 , 因为Django已经帮我们做了这些工作 , 所以我们主要还是直接使用`render()`**
-## Engine 🍀
+## Engine
模板引擎使用`TEMPLATES` 设置进行配置 , 位于`settings.py` 中 , 如下 :
@@ -124,7 +124,7 @@ TEMPLATES = [
]
```
-### 用法 🍀
+### 用法
在`django.template.loader` 模块中定义了两个函数来加载模板
@@ -223,7 +223,7 @@ django_engine = engines['django']
template = django_engine.from_string("Hello {{ name }}!")
```
-### 内置后端 🍀
+### 内置后端
**DjangoTemplates**
@@ -325,7 +325,7 @@ Jinja2 : http://jinja.pocoo.org/docs/2.10/
origin API : https://docs.djangoproject.com/en/1.11/topics/templates/#origin-api-and-3rd-party-integration
-## Template 🍀
+## Template
通过上文我们就可以配置好一个Engine了 , 那么接下来就是将模板代码编译成Template对象了
@@ -350,7 +350,7 @@ template = Template("My name is {{ my_name }}.")
注意 : 创建Template对象时 , 系统只解析一次原始模板代码 , 从那时起 , 它就被存储在内部 , 作为一个树形结构来提高性能
-## Context 🍀
+## Context
一旦我们拥有了一个Template对象 , 我们就可以用它来渲染一个上下文 ; 并且可以重复使用相同的模板 , 使用不同的上下文多次渲染它
diff --git "a/05-Web\346\241\206\346\236\266/Django/04-Django - Urls.md" b/docs/django/urls.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django/04-Django - Urls.md"
rename to docs/django/urls.md
index 5241328c8..c5daad5aa 100644
--- "a/05-Web\346\241\206\346\236\266/Django/04-Django - Urls.md"
+++ b/docs/django/urls.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
如`settings.py` 一样 , `django-admin startproject` 或者`python manage.py startproject` 执行创建时 , 会为我们自动创建其一个名为**URLconf** (URL配置) 的Python模块 , 即`urls.py` 通常把它称为路由系统
@@ -42,7 +42,7 @@ name:可选参数name,具体可以查看源码
"""
```
-## 请求处理 🍀
+## 请求处理
**Django如何处理一个请求**
@@ -57,7 +57,7 @@ name:可选参数name,具体可以查看源码
- 关键字参数由任何与正则表达式匹配的命名组组成 , 在可选的kwargs参数中指定的任何参数覆盖到`django.url.urls.url()`
5. 如果没有正则表达式匹配 , 或者在这个过程中的任何一点引发异常 , Django就会调用一个合适的错误处理视图进行处理
-## 基本示例 🍀
+## 基本示例
```python
# 导入url函数
@@ -84,7 +84,7 @@ urlpatterns = [
**注意 : 捕获的值是作为位置参数**
-## 分组命名 🍀
+## 分组命名
```python
# 导入url函数
@@ -112,7 +112,7 @@ urlpatterns = [
1. 如果有命名参数 , 则使用命名参数 , 忽略非命名参数
2. 否则 , 它将传递所有非命名参数作为位置参数
-## 额外参数 🍀
+## 额外参数
`django.conf.urls.url()` 函数可以接收一个可选的第三个参数 (kwargs) , 它应该是一个额外的关键字参数的字典 , 如下 :
@@ -129,7 +129,7 @@ urlpatterns = [
**处理冲突 :** 可能有一个URL模式捕获命名的关键字参数 , 并且还在其额外参数的字典中传递具有相同名称的参数 , 发生这种情况时 , 将使用字典中的参数 , 而不是在URL中捕获的参数
-## 反向解析 🍀
+## 反向解析
`django.conf.urls.url()` 函数中的第四个可选参数`name` , 我们可以利用该参数进行反向解析 , 相当于为我们配置的第一个参数 (regex) 取一个别名
@@ -177,7 +177,7 @@ class NewType(models.Model):
return reverse('NewType.Detail', kwargs={'nid': self.id})
```
-## 路由分发 🍀
+## 路由分发
如果所有应用的url都放在`urls.py` 这一个文件中 , 这无疑会对我们管理url造成麻烦 , Django中提供了一个`django.conf.urls.include()` 函数 , 可以为我们提供一个url之间的映射 , 我们把这叫做路由分发 , 如下 :
@@ -209,7 +209,7 @@ urlpatterns = [
]
```
-## 命名空间 🍀
+## 命名空间
**mydjango.urls.py**
diff --git "a/05-Web\346\241\206\346\236\266/Django/05-Django - Views.md" b/docs/django/views.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django/05-Django - Views.md"
rename to docs/django/views.md
index ae7b9c8d3..28e2eca5c 100644
--- "a/05-Web\346\241\206\346\236\266/Django/05-Django - Views.md"
+++ b/docs/django/views.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
在前面的文章中已经整理了关于*URLconf* 的相关内容 , 我们知道`url()` 的第二个位置参数是一个视图函数 , 简称视图 , 视图函数其实就是一个简单的Python函数 , 它的作用就是接收Web请求并且返回Web响应
@@ -19,7 +19,7 @@
Django对于`views.py` 的文件命名没有特别的要求 , 不在乎这个文件叫什么 , 但是根据约定 , 把它命名成`views.py` 是个好主意 , 这样有利于其他开发者读懂你的代码
-## 一个简单视图 🍀
+## 一个简单视图
我们编写一个简单的视图 , Hello视图
@@ -53,7 +53,7 @@ urlpatterns = [
注意 : 当访问`URL/hello/` 时 , Django根据settings.py中的`ROOT_URLCONF` 的设置装载URLconf , 然后按顺序逐个匹配URLconf里的URLpatterns , 直到找到一个匹配的
-## HttpRequest 🍀
+## HttpRequest
Django使用请求和响应对象来通过系统传递状态
@@ -61,7 +61,7 @@ Django使用请求和响应对象来通过系统传递状态
`HttpRequest`对象的属性如果没有特别说明 , 都被认为是只读的 , 下面对`HttpRequest`对象的属性进行说明
-### HttpRequest属性 🍀
+### HttpRequest属性
*class* HttpRequest [[source]](https://docs.djangoproject.com/en/1.11/_modules/django/http/request/#HttpRequest)
@@ -82,7 +82,7 @@ Django使用请求和响应对象来通过系统传递状态
| `HttpRequest.META` | 包含所有可用HTTP标头的字典 |
| `HttpRequest.resolver_match` | 一个ResolverMatch的实例 , 它表示已解析的URL
这个属性只在URL解析发生之后才被设置 , 这意味着它在所有的视图中都可用 , 但在解析发生之前执行的中间件中是不可用的 |
-### 应用程序设置的属性 🍀
+### 应用程序设置的属性
Django本身没有设置这些属性 , 但是如果你的应用程序设置了这些属性 , 就可以使用它们
@@ -91,7 +91,7 @@ Django本身没有设置这些属性 , 但是如果你的应用程序设置了
| `HttpRequest.current_app` | url模板标签将使用它的值作为`reverse()` 的`current_app`参数 |
| `HttpRequest.urlconf` | 这将用作当前请求的根URLconf , 会覆盖`ROOT_URLCONF`设置
`urlconf`可以设置为`None`恢复以前中间件所做的任何更改并返回到使用`ROOT_URLCONF` |
-### 中间件设置的属性 🍀
+### 中间件设置的属性
包含在Django的contrib应用程序中的一些中间件在请求中设置了属性 , 如果在请求中看不到该属性,请确保列出了相应的中间件类[`MIDDLEWARE`](https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-MIDDLEWARE)
@@ -109,13 +109,13 @@ HttpRequest对象的方法点这里 : [Methods](https://docs.djangoproject.com/e
"/music/bands/the_beatles/?print=true"
```
-## HttpResponse 🍀
+## HttpResponse
`HttpRequest`对象是由Django自动创建的 , 而`HttpResponse` 对象是由我们自己来创建的 , 我们写的视图负责实例化 , 填充和返回一个`HttpResponse` 对象
这个`HttpResponse` 类定义在 ` django.http`模块中
-### 用法 🍀
+### 用法
**传递字符串**
@@ -164,7 +164,7 @@ HttpRequest对象的方法点这里 : [Methods](https://docs.djangoproject.com/e
>>> response['Content-Disposition'] = 'attachment; filename="foo.xls"'
```
-### 属性 🍀
+### 属性
HttpResponse属性
@@ -179,7 +179,7 @@ HttpResponse属性
HttpResponse对象方法可见 : [Method](https://docs.djangoproject.com/en/1.11/ref/request-response/#id3)
-### HttpResponse子类 🍀
+### HttpResponse子类
Django包含许多HttpResponse处理不同类型HTTP响应的子类 , 这些子类都在`django.http` 中 , 子类如下 :
@@ -201,7 +201,7 @@ Django包含许多HttpResponse处理不同类型HTTP响应的子类 , 这些子
https://docs.djangoproject.com/en/1.11/_modules/django/http/response/
-## render 🍀
+## render
为了方便 , Django中有一个shortcuts模块 , 其中收集了跨越多个级别的MVC的帮助函数和类
@@ -253,7 +253,7 @@ def my_view(request):
return HttpResponse(t.render(c, request), content_type='application/xhtml+xml')
```
-## redirect 🍀
+## redirect
```python
def redirect(to, *args, **kwargs):
diff --git "a/05-Web\346\241\206\346\236\266/README.md" b/docs/django/web-framework-introduction.md
similarity index 94%
rename from "05-Web\346\241\206\346\236\266/README.md"
rename to docs/django/web-framework-introduction.md
index fde9be3c9..5ba7f0dd5 100644
--- "a/05-Web\346\241\206\346\236\266/README.md"
+++ b/docs/django/web-framework-introduction.md
@@ -1,64 +1,64 @@
-# Web框架介绍
-
-
-
-
-
-
-
-
-
-
-## 主流Web框架 🍀
-
-### Django 🍀
-
-Django 是当前 Python 世界中最负盛名且最成熟的网络框架 , 最初用来制作在线新闻的 Web 站点 , 目前已经发展为应用最广泛的 Python 网络框架
-
-Django 的各模块之间结合得比较紧密 , 所以在功能强大的同时又是一个相对封闭的系统 , 但是它提供了非常齐备的官方文档 , 提供了译站式的解决方案 , 其中包含缓存 , ORM , 管理后台 , 验证 , 表单处理等 , 使得开发复杂的数据库驱动的网站变得很简单 ; 当然也因为系统耦合度太高 , 替换掉内置的功能往往需要花费一些功夫 , 所以学习曲线也相当陡峭
-
-### Flask 🍀
-
-Flask 是一个轻量级 Web 应用框架 , 它基于 Werkzeug 实现的 WSGI 和 Jinjia2 模板引擎
-
-Flask 的作者是 Armin Ronacher , 本来这只是作者愚人节开的一个玩笑 , 但是开源之后却受到 Python 程序员的喜爱 , 目前在 GitHub 上的 Star 数量已经超过了 Django . 设计上 , 它只保留核心 , 通过扩展机制来增加其他功能 , Flask 用到的依赖都是 Pocoo 团队开发的 , Pocoo 团队其他的项目还有 Pygments , Sphinx , 以及 lodgeit . Flask 的扩展环境非常繁荣 , 基本上 Web 应用的每个环节都有对应的扩展供选择 , 就算没有对应的扩展也能很方便的自己实现一个
-
-### Pyramid 🍀
-
-Pyramid 在国内知名度并不高 , 主要原因是中文文档匮乏 , 其高级用法需要通过阅读源代码获取灵感 , 尽管被 Django 和 Flask 的光芒遮蔽 , 但是它的性能要比 Flask 高 . Pyramid 的灵感来源于 Zope , Pylons 1.0 和 Django . Pyramid 在努力朝着胜任不同级别应用的框架的方向在走 , 虽然它默认使用 Chameleon 和 Mako 模块 , 但很容易切换成 Jinja2 , 甚至可以让多种模板引擎共存 , 通过文件后缀名来识别
-
-豆瓣赞赏和豆瓣钱包等产品就是基于此框架实现的 , 代码量级和 Flask 相同 , 性能比 Flask 要略高
-
-### Bottle 🍀
-
-Bottle 也是一个轻量级的 Web 框架 , 它的特点是单文件 , 代码只使用了 Python 标准库 , 而不需要额外依赖其他的第三方库 , 它更符合微框架的定义 , 截止到今天只有 4100 多行的代码
-
-### Tornado 🍀
-
-Tornado 全称 Tornado Web Server , 最初是由 FriendFeed 开发的非阻塞式 Web 服务器 , 现在我们看到的是被 Fackbook 收购后开源出来的版本 , 它和其他主流框架有个明显的区别 : 它是非阻塞式服务器 , 而且速度相当快 , 得益于其非阻塞的方式和对 epoll 的运用 , Tornado 每秒可以处理数以千计的连接 , 这意味着对于长轮询 , WebSocket 等实时 Web 服务来说 , Tornado 是一个理想的 Web 框架
-
-### Web.py 🍀
-
-Web.py 也是一个微框架 , 由 Reddit 联合创始人 , RSS 规格合作创造者 , 著名计算机黑客 Aaron Swartz 开发 , Web.py 使用基于类的视图 , 简单易学却功能强大
-
-### Twisted 🍀
-
-Twisted 是一个有着十多年历史的开源事件驱动框架 , 它适用于从传输层到自定义应用协议的所有类型的网络程序的开发 , 而不着眼于网络 HTTP 应用开发 , 并且它能在不同的操作系统上提供很高的运行效率
-
-## 小众的Web框架 🍀
-
-### Quixote 🍀
-
-Quixote 是由美国全国研究创新联合会的工程师 A.M.Kuchling , Neil Schemenauer 和 Greg Ward 开发的一个轻量级 Web 框架 , 它简单 , 高校 , 代码简洁 , 豆瓣的大部分用户产品都使用定制版的 Quixote 作为 Web 框架
-
-它使用目录式的 URL 分发规则 , 用 Python 来写模板 , PTL 模板更适合程序员 , 但是并不适合美工参与前端代码的编写和修改 , 豆瓣在开发中使用了 Mako 替代 PTL ; 不建议在生产环境中选用 Quixote
-
-### Klein 🍀
-
-Klein 是 Twisted 组织开源出来的基于 werkzeug 和 twisted.web 的为框架 , Flask 很不错 , 但是不能使用异步非阻塞的方式编程 , 根本原因是它和 Django , Pyramid 一样 , 都基于 WSGI , 而WSGI 的接口是同步阻塞的 , Klein 用法非常像 Flask , 却可以使用异步的方式开发 Web 应用
-
-## 选择 Web 框架时应遵循的原则 🍀
-
-1. 选择更主流的 Web 框架 , 因为他们文档齐全 , 技术积累更多 , 社区更繁盛 , 能得到更好的支持
-2. 关注框架的活跃情况 , 如果一个框架长时间没有更新 , 或者有一堆的问题需要解决但是没有得到回应 , 就不应该将这样的框架放在生产环境中
-3. 确认框架是否足够满足需求 , 没有最好的框架 , 只有最合适的框架
+# Web框架介绍
+
+
+
+
+
+
+
+
+
+
+## 主流Web框架
+
+### Django
+
+Django 是当前 Python 世界中最负盛名且最成熟的网络框架 , 最初用来制作在线新闻的 Web 站点 , 目前已经发展为应用最广泛的 Python 网络框架
+
+Django 的各模块之间结合得比较紧密 , 所以在功能强大的同时又是一个相对封闭的系统 , 但是它提供了非常齐备的官方文档 , 提供了译站式的解决方案 , 其中包含缓存 , ORM , 管理后台 , 验证 , 表单处理等 , 使得开发复杂的数据库驱动的网站变得很简单 ; 当然也因为系统耦合度太高 , 替换掉内置的功能往往需要花费一些功夫 , 所以学习曲线也相当陡峭
+
+### Flask
+
+Flask 是一个轻量级 Web 应用框架 , 它基于 Werkzeug 实现的 WSGI 和 Jinjia2 模板引擎
+
+Flask 的作者是 Armin Ronacher , 本来这只是作者愚人节开的一个玩笑 , 但是开源之后却受到 Python 程序员的喜爱 , 目前在 GitHub 上的 Star 数量已经超过了 Django . 设计上 , 它只保留核心 , 通过扩展机制来增加其他功能 , Flask 用到的依赖都是 Pocoo 团队开发的 , Pocoo 团队其他的项目还有 Pygments , Sphinx , 以及 lodgeit . Flask 的扩展环境非常繁荣 , 基本上 Web 应用的每个环节都有对应的扩展供选择 , 就算没有对应的扩展也能很方便的自己实现一个
+
+### Pyramid
+
+Pyramid 在国内知名度并不高 , 主要原因是中文文档匮乏 , 其高级用法需要通过阅读源代码获取灵感 , 尽管被 Django 和 Flask 的光芒遮蔽 , 但是它的性能要比 Flask 高 . Pyramid 的灵感来源于 Zope , Pylons 1.0 和 Django . Pyramid 在努力朝着胜任不同级别应用的框架的方向在走 , 虽然它默认使用 Chameleon 和 Mako 模块 , 但很容易切换成 Jinja2 , 甚至可以让多种模板引擎共存 , 通过文件后缀名来识别
+
+豆瓣赞赏和豆瓣钱包等产品就是基于此框架实现的 , 代码量级和 Flask 相同 , 性能比 Flask 要略高
+
+### Bottle
+
+Bottle 也是一个轻量级的 Web 框架 , 它的特点是单文件 , 代码只使用了 Python 标准库 , 而不需要额外依赖其他的第三方库 , 它更符合微框架的定义 , 截止到今天只有 4100 多行的代码
+
+### Tornado
+
+Tornado 全称 Tornado Web Server , 最初是由 FriendFeed 开发的非阻塞式 Web 服务器 , 现在我们看到的是被 Fackbook 收购后开源出来的版本 , 它和其他主流框架有个明显的区别 : 它是非阻塞式服务器 , 而且速度相当快 , 得益于其非阻塞的方式和对 epoll 的运用 , Tornado 每秒可以处理数以千计的连接 , 这意味着对于长轮询 , WebSocket 等实时 Web 服务来说 , Tornado 是一个理想的 Web 框架
+
+### Web.py
+
+Web.py 也是一个微框架 , 由 Reddit 联合创始人 , RSS 规格合作创造者 , 著名计算机黑客 Aaron Swartz 开发 , Web.py 使用基于类的视图 , 简单易学却功能强大
+
+### Twisted
+
+Twisted 是一个有着十多年历史的开源事件驱动框架 , 它适用于从传输层到自定义应用协议的所有类型的网络程序的开发 , 而不着眼于网络 HTTP 应用开发 , 并且它能在不同的操作系统上提供很高的运行效率
+
+## 小众的Web框架
+
+### Quixote
+
+Quixote 是由美国全国研究创新联合会的工程师 A.M.Kuchling , Neil Schemenauer 和 Greg Ward 开发的一个轻量级 Web 框架 , 它简单 , 高校 , 代码简洁 , 豆瓣的大部分用户产品都使用定制版的 Quixote 作为 Web 框架
+
+它使用目录式的 URL 分发规则 , 用 Python 来写模板 , PTL 模板更适合程序员 , 但是并不适合美工参与前端代码的编写和修改 , 豆瓣在开发中使用了 Mako 替代 PTL ; 不建议在生产环境中选用 Quixote
+
+### Klein
+
+Klein 是 Twisted 组织开源出来的基于 werkzeug 和 twisted.web 的为框架 , Flask 很不错 , 但是不能使用异步非阻塞的方式编程 , 根本原因是它和 Django , Pyramid 一样 , 都基于 WSGI , 而WSGI 的接口是同步阻塞的 , Klein 用法非常像 Flask , 却可以使用异步的方式开发 Web 应用
+
+## 选择 Web 框架时应遵循的原则
+
+1. 选择更主流的 Web 框架 , 因为他们文档齐全 , 技术积累更多 , 社区更繁盛 , 能得到更好的支持
+2. 关注框架的活跃情况 , 如果一个框架长时间没有更新 , 或者有一堆的问题需要解决但是没有得到回应 , 就不应该将这样的框架放在生产环境中
+3. 确认框架是否足够满足需求 , 没有最好的框架 , 只有最合适的框架
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 4 Authentication & Permissions.md" b/docs/drf/authentication-permissions.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 4 Authentication & Permissions.md"
rename to docs/drf/authentication-permissions.md
index 07d0cbe10..11c35e4b2 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 4 Authentication & Permissions.md"
+++ b/docs/drf/authentication-permissions.md
@@ -16,7 +16,7 @@
-## 添加信息到模型中 🍀
+## 添加信息到模型中
我们需要对我们的 `Snippet` 模型类做一些修改 , 首先 , 添加两个字段 , 一个用来代表代码片段的创建者 , 另一个用来存储高亮显示的HTML代码
@@ -68,7 +68,7 @@ python manage.py migrate
python manage.py createsuperuser
```
-## 为我们的模型添加端口 🍀
+## 为我们的模型添加端口
现在我们已经创建了一些用户 , 我们最好将用户添加到我们的 API , 我们很容易创建一个新的序列 , 在`serializers.py` 文件中添加 :
@@ -114,7 +114,7 @@ url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view()),
```
-## 将Snippets与Users关联 🍀
+## 将Snippets与Users关联
现在 , 如果我们创建一个 `snippet` , 我们没法将用户和创建的 `snippet` 实例联系起来 , 虽然用户不是序列表示的部分 , 但是它代表传入请求的一个属性
@@ -129,7 +129,7 @@ def perform_create(self, serializer):
现在 , 我们序列的 `create()` 方法将会传入一个有效请求数据的 `owner` 字段
-## 更新我们的serializer 🍀
+## 更新我们的serializer
现在 , `snippets` 和创建他们的用户已经建立了联系 , 更新我们的 `SnippetSerializer` 来表示用户 , 在 `serializers.py` 中添加字段
@@ -143,7 +143,7 @@ owner = serializers.ReadOnlyField(source='owner.username')
我们添加的字段是无类型的 `ReadOnlyField` 类 , 与其他类型字段 , 如 `CharField` , `BooleanField` 等相比 , 无类型的 `ReadOnlyfField` 总是只读的 , 它用于序列化表示 , 但是不能用于数据反序列化时更新模型实例 , 在这里我们也可以使用 `CharField(read_only=True)`
-## 为视图添加权限 🍀
+## 为视图添加权限
现在 , `snippets` 与 `users` 已经相关联 , 我们希望确保只有经过身份验证的用户才能创建 , 更新和删除 `snippets`
@@ -161,7 +161,7 @@ from rest_framework import permissions
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
```
-## 在可浏览API中添加登录 🍀
+## 在可浏览API中添加登录
如果你打开浏览器并操控可浏览的API , 你将发现你不再有创建新的 `snippets` 的权限 , 为了做到这一点 , 我们需要以用户的身份登录
@@ -187,7 +187,7 @@ urlpatterns += [
一旦你创建了一些 `snippets` , 访问 `'/user/'` 端 , 你会注意到在每个用户的 `snippets` 字段 , 会显示跟用户有关的 `snippets` id
-## 对象级别权限 🍀
+## 对象级别权限
虽然我们希望所有 `snippets` 都能被任何人看到 , 但是也要确保只有创建该 `snippets` 的用户才能更新或删除它
@@ -229,7 +229,7 @@ from snippets.permissions import IsOwnerOrReadOnly
现在 , 如果你再使用浏览器 , 你会发现只有你登录与创建 `snippets` 一致的用户 , 你才有权限使用 `DELETE` 和 `PUT` 动作
-## 验证API 🍀
+## 验证API
由于现在 API 有权限集合 , 在我们需要编辑任何 `snippets` 的时候 , 需要认证我们的请求 , 我们没有设置他任何认证类 ( `authentication classes` ) , 默认情况下只有 `SessionAuthentication` 和 `BasicAuthentication`
@@ -263,7 +263,7 @@ http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"
}
```
-## 概要 🍀
+## 概要
我们的 `API` 已经具有一个相当精细的权限集合 , 同时为系统用户和他们创建的 `snippets` 提供了端点
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 3 Class-based Views.md" b/docs/drf/class-based-views.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 3 Class-based Views.md"
rename to docs/drf/class-based-views.md
index 0e292874d..7c42910e2 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 3 Class-based Views.md"
+++ b/docs/drf/class-based-views.md
@@ -11,7 +11,7 @@
-## 用基于类的视图重构我们的API 🍀
+## 用基于类的视图重构我们的API
重构 `views.py`
@@ -90,7 +90,7 @@ urlpatterns = format_suffix_patterns(urlpatterns)
至此 , 如果你运行你的开发服务器 , 那么一切还是和之前的一样
-## 使用mixins 🍀
+## 使用mixins
使用基于类的视图的一大优势是 , 它允许我们轻松地创建可重用的行为
@@ -141,7 +141,7 @@ class SnippetDetail(mixins.RetrieveModelMixin,
类似地 , 我们使用 `GenericAPIView` 类提供核心功能 , 添加 `mixins` 提供 `.retrieve()` , `.update()` and `.destroy()` 动作
-## 使用基于generic类的视图 🍀
+## 使用基于generic类的视图
我们使用 `mixin` 类使用比之前较少的代码编写视图 , 但我们可以更进一步 , `REST framework` 提供了一组已经混合的 `generics` 视图 , 我们可以使用它来进一步缩减 `views.py` 模块
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Quickstart.md" b/docs/drf/quickstart.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Quickstart.md"
rename to docs/drf/quickstart.md
index d98f08f8f..cec6a473b 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Quickstart.md"
+++ b/docs/drf/quickstart.md
@@ -11,7 +11,7 @@
-## 创建项目 🍀
+## 创建项目
```shell
# 创建项目目录
@@ -63,7 +63,7 @@ $ find .
python manage.py migrate
```
-## 模型 🍀
+## 模型
我们使用Django默认的两个模型 , 用户` (User) `和组 ` (Group) ` , 你可以使用 `Admin` 来进行管理
@@ -74,7 +74,7 @@ python manage.py createsuperuser --emaill Lyon@example.com --username Lyon
python manage.py createsuperuser --emaill Kenneth@example.com --username Kenneth
```
-## 序列化器 🍀
+## 序列化器
我们需要定制一些序列化器来决定我们数据的表现形式
@@ -101,7 +101,7 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer):
这里使用超链接模型序列化器 , 因为超链接是非常好的RESTful设计 , 当然你也可以使用其他的序列化器
-## 视图 🍀
+## 视图
`tutorial/quickstart/views.py`
@@ -127,7 +127,7 @@ class GroupViewSet(viewsets.ModelViewSet):
serializer_class = GroupSerializer
```
-## 路由 🍀
+## 路由
`tutorial/urls.py`
@@ -151,7 +151,7 @@ urlpatterns = [
]
```
-## 配置 🍀
+## 配置
在 `tutorial/settings.py` 的 `INSTALLED_APPS` 中 , 添加 `rest_framework`
@@ -168,7 +168,7 @@ INSTALLED_APPS = [
]
```
-## 测试API 🍀
+## 测试API
首先我们运行我们的项目程序 , 随后使用浏览器访问项目服务器地址 , 或者使用命令行工具 , 如 : [httpie](https://github.com/jakubroztocil/httpie) 等
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 5 Relationships & Hyperlinked APIs.md" b/docs/drf/relationships-hyperlinked-api.md
similarity index 96%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 5 Relationships & Hyperlinked APIs.md"
rename to docs/drf/relationships-hyperlinked-api.md
index 685cd6f4d..e421a831a 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 5 Relationships & Hyperlinked APIs.md"
+++ b/docs/drf/relationships-hyperlinked-api.md
@@ -11,7 +11,7 @@
-## 为我们的根API创建一个端点 🍀
+## 为我们的根API创建一个端点
现在我们有了 `'snippets'` 和 `'users'` 的端点 , 但是没有为我们的API设置单独的入口 . 为了创建一个单独的入口 , 我们将使用一个常规的基于函数的视图以及 `@api_view` 装饰器创建一个入口端点 . 在文件 `snippets/views.py` 中添加 :
@@ -31,7 +31,7 @@ def api_root(request, format=None):
在这里我们需要注意两点 , 首先我们使用 `REST framework` 的 `reverse` 方法限定返回的 `URLs` , 其次 , `URL` 格式使用方便的名字作为标识符 , 稍后会在 `snippets/urls.py` 中声明
-## 创建一个高亮的snippets断点 🍀
+## 创建一个高亮的snippets断点
还有一个明显的事情就是我们的 `pastebin API` 缺乏代码高亮的端点
@@ -66,7 +66,7 @@ url(r'^$', views.api_root),
url(r'^snippets/(?P[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
```
-## 为我们的API添加超链接 🍀
+## 为我们的API添加超链接
在Web API设计中 , 处理实体之间的关系是一项非常有挑战的事情 , 代表一种关系可以有很多种方式
@@ -112,7 +112,7 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
因为我们已经配置了 `URLs` 后缀 , 比如 `'.json'` , 同时我们需要在 `highlight` 字段中指明后缀 , `.html`
-## 确保我们的URL模式均已命名 🍀
+## 确保我们的URL模式均已命名
如果我们要使用超链接 API , 我们必须确保对 `URL` 模型进行命名 , 让我们看看哪些链接需要命名 :
@@ -149,7 +149,7 @@ urlpatterns = format_suffix_patterns([
])
```
-## 添加分页 🍀
+## 添加分页
`users` 和 `snippets` 的列表视图可能会返回大量的实例 , 所以我们要对返回的结果进行分页 , 并允许客户端访问每个页面
@@ -166,7 +166,7 @@ REST_FRAMEWORK = {
同时 , 我们也可以自定义分页的样式 , 在这里 , 我们使用默认方式
-## 浏览API 🍀
+## 浏览API
如果我们打开浏览器 , 并访问可浏览的 `API` , 你会发现你可以使用下面的链接使用 `API`
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 2 Requests and Responses.md" b/docs/drf/requests-and-responses.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 2 Requests and Responses.md"
rename to docs/drf/requests-and-responses.md
index 6063a69d2..41e1f2ba7 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 2 Requests and Responses.md"
+++ b/docs/drf/requests-and-responses.md
@@ -11,7 +11,7 @@
-## Request对象 🍀
+## Request对象
`REST framework` 引入了一个 `Request` 对象 , 它扩展了常规的 `HttpRequest` , 并提供了灵活的请求解析 . `Request` 对象的核心功能是 `request.data` 属性 , 它和 `request.POST` 属性很相似 , 但是它对 `Web APIs` 更加有用
@@ -20,7 +20,7 @@ request.POST # 只处理表单数据,仅用于 'POST' 方法.
request.data # 处理任意数据,可以用于 'POST', 'PUT' 和 'PATCH' 方法.
```
-## Response对象 🍀
+## Response对象
`REST framework` 也引入了 `Response` 对象 , 它是一类用为渲染和使用内容协商来决定返回给客户端的正确内容类型的 `TemplateResponse `
@@ -28,11 +28,11 @@ request.data # 处理任意数据,可以用于 'POST', 'PUT' 和 'PATCH' 方法
return Response(data) # 按照客户的需求类型来渲染内容
```
-## 状态码 🍀
+## 状态码
在视图中使用HTTP状态码并不总是易读的 , 错误代码很容易被忽略 . `REST framework` 为每一个状态码提供了更明确的标识符,例如状态模块中的 `HTTP_400_BAD_REQUEST` , 使用这些标识符代替纯数字标识符是一个不错的注意
-## 装饰API视图 🍀
+## 装饰API视图
`REST framework` 提供了两个装饰器来编写API视图
@@ -43,7 +43,7 @@ return Response(data) # 按照客户的需求类型来渲染内容
同时还提供一些行为 , 例如在合适的时候返回 `405 Method Not Allowed` 响应 , 例如处理在访问错误输入的 `request.data` 时出现的 `ParseError` 异常
-## 协同工作 🍀
+## 协同工作
好了 , 让我们开始使用这些新组件来写一些视图吧
@@ -110,7 +110,7 @@ def snippet_detail(request, pk):
请注意 , 我们不再明确指定请求或响应的上下文类型 , `request.data` 可以处理的 `json` 格式的请求 , 同样也可以处理其他格式 . 同样的 , 我们允许 `REST framework` 将响应对象的数据渲染成正确的内容类型返回给客户端
-## 在URLs中添加可选格式后缀 🍀
+## 在URLs中添加可选格式后缀
为了充分利用我们的响应不再是单一内容类型的事实 , 我们可以在API尾部添加格式后缀 , 格式后缀为我们提供了一个参考的格式 , 这意味着我们的API将能够处理诸如 `http://example.com/api/items/4.json` 之类的url
@@ -143,7 +143,7 @@ urlpatterns = format_suffix_patterns(urlpatterns)
我们并不需要添加这些额外的url , 但是它为我们提供了一种简单明了的方式来指定特定的格式
-## 进行测试 🍀
+## 进行测试
继续像我们在教程第1部分中所做的那样 , 通过命令行测试API , 所有的工作都是类似的 , 同时我们可以很好地处无效请求产生的错误
@@ -220,7 +220,7 @@ http --json POST http://127.0.0.1:8000/snippets/ code="print 456"
使用浏览器打开 `http://127.0.0.1:8000/snippets/`
-## 浏览可视化 🍀
+## 浏览可视化
由于 `API` 响应类型是根据客户端的请求进行选择的 , 因此 , 当使用 `web` 浏览器请求的时候 , 默认会使用 `HTML` 格式来表示资源 , 这允许 `API` 返回一个完整的浏览器可视的 `HTML` 表示
@@ -228,6 +228,6 @@ http --json POST http://127.0.0.1:8000/snippets/ code="print 456"
查看 [`browsable api`](http://www.django-rest-framework.org/topics/browsable-api/) 主题获取更更多关于 `browsable API` 的信息 , 比如 特性 , 定制
-## 下一步 🍀
+## 下一步
在教程的第3部分, 我们将开始使用基于类的视图`(CBV)` , 并介绍如何使用通用的视图来减少代码量
\ No newline at end of file
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 7 Schemas & client libraries.md" b/docs/drf/schemas-client-libraries.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 7 Schemas & client libraries.md"
rename to docs/drf/schemas-client-libraries.md
index d8b7e2d46..857e76052 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 7 Schemas & client libraries.md"
+++ b/docs/drf/schemas-client-libraries.md
@@ -13,7 +13,7 @@
-## Core API 🍀
+## Core API
为了提供 `schema` 支持, `REST` 框架使用 [Core API](http://www.coreapi.org/)
@@ -23,7 +23,7 @@
当用于客户端 , `Core API` 允许动态驱动的客户端库与任何支持 `schema` 或超媒体格式的 `API` 交互
-## 添加一个schema 🍀
+## 添加一个schema
`REST framework` 支持明确定义的 `schema` 视图 , 或自动生成的 `schemas`. 由于我们使用 `ViewSets` 和`Routers` , 我们可以很简单的自动生成 `schema`
@@ -70,7 +70,7 @@ Content-Type: application/coreapi+json
其他的 `schema` 格式 , 比如 [Open API](https://openapis.org/) (以前称作Swagger) , 同样支持
-## 使用命令行客户端 🍀
+## 使用命令行客户端
现在 , 我们的 API 暴露了一个 `schema` 端点 , 我们可以使用动态客户端库与 API 交互 , 为了证明这点 , 我们是用 `Core API` 命令行客户端
@@ -148,7 +148,7 @@ $ coreapi action snippets highlight --param id=1
```
-## 认证我们的客户端 🍀
+## 认证我们的客户端
如果我们想要创建 , 编辑 , 删除 `snippets` , 我们需要认证一个有效的用户 , 这种情况下 , 我们只使用基本身份验证
@@ -207,7 +207,7 @@ coreapi action snippets delete --param id=7
有关定义 `schema` 生成和使用 `Core API` 客户端库 , 你可以参考完整的文档
-## 回到我们的工作 🍀
+## 回到我们的工作
我们使用很少的代码 , 拥有了一个完整的可浏览的 `pastebin Web API` , 它包含一个 `schema-driven` 客户端库 , 完整的身份认证 , 对象级权限和多格式渲染器
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 1 Serialization.md" b/docs/drf/serialization.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 1 Serialization.md"
rename to docs/drf/serialization.md
index 71436f41a..ca83cddfe 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 1 Serialization.md"
+++ b/docs/drf/serialization.md
@@ -9,11 +9,11 @@
-## 介绍 🍀
+## 介绍
本教程将会通过一些简单的代码来实现 Web API. 这个过程将会介绍 `REST framework` 的各个组件, 带你深入理解各个组件是如何一起工作
-## 创建一个新的环境 🍀
+## 创建一个新的环境
为了确保我们的包配置与我们正在进行的其他项目保持良好的隔离 , 我们将使用 `virtualenv` 来创建一个新的虚拟环境
@@ -32,7 +32,7 @@ pip install pygments # 我们将使用这个模块来提高代码高亮
友情链接 : [`virtualenv`](https://virtualenv.pypa.io/en/stable/) , [`pygments`](http://pygments.org/)
-## 开始 🍀
+## 开始
首先我们创建一个新的项目
@@ -58,7 +58,7 @@ INSTALLED_APPS = [
]
```
-## 创建一个Model 🍀
+## 创建一个Model
我们首先创建一个简单的模型
@@ -96,7 +96,7 @@ python manage.py makemigrations snippets
python manage.py migrate
```
-## 创建一个序列化类 🍀
+## 创建一个序列化类
我们在Web API上首先需要做的一件事是提供一种将 `Snippet` 实例序列化和反序列化的方法 , 使之成为诸如`json`之类的表示形式的方式
@@ -147,7 +147,7 @@ class SnippetSerializer(serializers.Serializer):
我们还可以通过使用 `ModelSerializer` (`相当于ModelForm`) 类来节省一些时间 , 稍后我们将会看到 , 但是现在我们将显式的定义序列化器
-## 使用序列化器 🍀
+## 使用序列化器
在我们进一步讨论之前 , 我们将熟悉使用新的序列化器类 , 让我们先进入 `Django shell`
@@ -224,7 +224,7 @@ serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]
```
-## 使用ModelSerializers 🍀
+## 使用ModelSerializers
我们的 `SnippetSerializer` 类复制了 `Snippet` 模型中的许多信息 , 如果我们能让代码更简洁一些 , 那就太好了
@@ -259,7 +259,7 @@ print(repr(serializer))
- 一组自动确定的字段
- 简单默认实现的 `create()` 和 `update()` 方法
-## 用序列化器写常规的Django视图 🍀
+## 用序列化器写常规的Django视图
让我们看看如何使用我们的序列化器类来编写一些API视图 , 目前 , 我们不会使用REST框架的其他特性 , 只是写一些常规的Django视图
@@ -352,7 +352,7 @@ urlpatterns = [
值得注意的是 , 我们目前还有一些边界情况没有进行处理 , 如果我们发送错误的 `json` 数据 , 或者一个请求是用一个视图无法处理的方法进行的 , 那么我们将得到一个500的错误 , `“Server Error”`
-## 测试我们的API 🍀
+## 测试我们的API
首先退出 `shell`
diff --git "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 6 ViewSets & Routers.md" b/docs/drf/viewsets-routers.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 6 ViewSets & Routers.md"
rename to docs/drf/viewsets-routers.md
index 3f142db87..d0ff31478 100644
--- "a/05-Web\346\241\206\346\236\266/Django-Rest-Framework/Tutorial 6 ViewSets & Routers.md"
+++ b/docs/drf/viewsets-routers.md
@@ -15,7 +15,7 @@
-## 使用ViewSets重构 🍀
+## 使用ViewSets重构
首先使用单个 `UserViewSet` 视图重构 `UserList` 和 `UserDetail` 视图
@@ -68,7 +68,7 @@ class SnippetViewSet(viewsets.ModelViewSet):
自定义动作的默认 `URLs` 取决于它们的名字 , 如果你想改变 url 构建方法 , 你可以在使用装饰器的时候传入 `url_path` 关键字参数
-## 将ViewSets绑定到URLs 🍀
+## 将ViewSets绑定到URLs
视图的处理方法仅会按照我们的 `URL conf` 对相应方法进行绑定 , 现在我们为我们为您的 `ViewSets` 显示地创建一个视图集合 , 来看看发生了什么
@@ -114,7 +114,7 @@ urlpatterns = format_suffix_patterns([
])
```
-## 使用Routers 🍀
+## 使用Routers
因为我们使用 `ViewSet` 代替 `View` , 实际上我们不需要自己设计 URL 配置 , 我们可以通过 `Router` 类 , 将资源 (`resources`) , 视图 (`views`) , urls自动联系起来 , 我们只需要使用 `Router` 类注册合适的视图集合
@@ -140,7 +140,7 @@ urlpatterns = [
我们使用默认 `DefaultRouter` 类也会自动为我们创建API根视图 , 现在我们可以从 `views` 模块中删除 `api_root` 方法
-## 权衡使用views和viewsets 🍀
+## 权衡使用views和viewsets
`viewsets` 是一个非常有用的抽象 , 它可以确保 `URL` 原型和你的 `API` 保持一致 , 最大限度的减少代码量 , 允许你将精力放在 API 的交互和表示上 , 而不是放在编写 `URL conf` 上
diff --git "a/05-Web\346\241\206\346\236\266/Flask/README.md" b/docs/flask/README.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Flask/README.md"
rename to docs/flask/README.md
index f9a551cae..b4c413bc1 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/README.md"
+++ b/docs/flask/README.md
@@ -12,7 +12,7 @@
-## 介绍 🍀
+## 介绍
Flask是一个微型框架 , 它基于Python , 并且依赖着两个外部库 : Jinja2模板引擎和Werkzeug WSGI工具集
@@ -22,7 +22,7 @@ Flask的 "微" (Micro) 并不是意味着把整个Web应用放入到一个Python
Flask可能是 "微" 型的 , 但是它已经能够在各种各样的需求中生产使用
-## 配置和约定 🍀
+## 配置和约定
Flask有许多带有合理默认值的配置项 , 也遵循一些惯例 , 比如 : 按惯例 , 模板和静态文件存储在应用Python源代码树下的子目录中 , 模板文件夹名称与Django一样 "templates" , 静态文件夹名称 "static" 等等
diff --git "a/05-Web\346\241\206\346\236\266/Flask/06-Flask - \346\272\220\347\240\201\344\271\213\350\223\235\345\233\276.md" b/docs/flask/blueprint.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/06-Flask - \346\272\220\347\240\201\344\271\213\350\223\235\345\233\276.md"
rename to docs/flask/blueprint.md
index 5e32cb2b4..6627a8d72 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/06-Flask - \346\272\220\347\240\201\344\271\213\350\223\235\345\233\276.md"
+++ b/docs/flask/blueprint.md
@@ -9,13 +9,13 @@
-## 介绍 🍀
+## 介绍
首先 , 我们得说说蓝图的作用
蓝图 `(Blueprint)` 实现了应用的**模块化** , 使用蓝图让应用层次清晰 , 开发者可以更容易的开发和维护项目 , 蓝图通常作用于相同的 URL 前缀 , 比如`/user/:id` , `/user/profile` 这样的地址都以 `/user` 开头 , 那么他们就可以放在一个模块中
-## 构建蓝图 🍀
+## 构建蓝图
我们从示例开始 :
@@ -79,7 +79,7 @@ def record(self, func):
至此 , 我们已经完成了一个蓝图的构建 , 但是此时路由并没有注册 , 它仅仅将注册路由的函数放入 `deferred_functions` 中 , 等待蓝图注册时被调用
-## 注册蓝图 🍀
+## 注册蓝图
现在我们需要把构建好的蓝图注册到我们的应用中 , 如下 :
@@ -195,11 +195,11 @@ app.register_blueprint(simple_page, url_prefix='/pages')
simple_page.show>
```
-## 蓝图资源 🍀
+## 蓝图资源
蓝图也可以提供资源 , 有时候你会只为他提供的资源而引入一个蓝图
-### 蓝图资源文件夹 🍀
+### 蓝图资源文件夹
我们可以通过访问 `Blueprint` 对象的 `root_path` 属性来访问蓝图资源文件夹 :
@@ -215,7 +215,7 @@ with simple_page.open_resource('static/style.css') as f:
code = f.read()
```
-### 静态文件 🍀
+### 静态文件
与 `Flask` 一样 , `Blueprint` 可以通过 `static_folder` 关键字参数提供一个指向文件系统上文件夹的路径 , 这可以是一个绝对路径 , 也可以是相对于蓝图文件夹的相对路径 :
@@ -223,7 +223,7 @@ with simple_page.open_resource('static/style.css') as f:
admin = Blueprint('admin', __name__, static_folder='static')
```
-### 模板 🍀
+### 模板
同样的 , 蓝图也提供模板 :
diff --git "a/05-Web\346\241\206\346\236\266/Flask/08-Flask - \346\272\220\347\240\201\344\271\213\344\270\212\344\270\213\346\226\207.md" b/docs/flask/context.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Flask/08-Flask - \346\272\220\347\240\201\344\271\213\344\270\212\344\270\213\346\226\207.md"
rename to docs/flask/context.md
index 03824b96d..aa9b1bd25 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/08-Flask - \346\272\220\347\240\201\344\271\213\344\270\212\344\270\213\346\226\207.md"
+++ b/docs/flask/context.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
阅读本文时 , 请先了解[ Flask 本地线程](https://lyonyang.github.io/blogs/04-Web-Framework/02-Flask/07-Flask%E6%BA%90%E7%A0%81%E4%B9%8B%E6%9C%AC%E5%9C%B0%E7%BA%BF%E7%A8%8B.html) 相关内容
@@ -29,7 +29,7 @@
请求上下文发生在 HTTP 请求开始 , WSGIServer 调用 `Flask.__call__()` 之后
-## 开始示例 🍀
+## 开始示例
先看一个简单的例子
@@ -144,7 +144,7 @@ def push(self):
也就是说 , 事实上在 Web 应用环境中 , 请求上下文和应用上下文是一一对应的 , 请求上下文和应用上下文都是本地线程的
-## 全局变量 🍀
+## 全局变量
Flask 中有 6 个全局变量 : 2 个本地线程变量和 4 个上下文变量
@@ -237,7 +237,7 @@ if __name__ == '__main__':
服务启动后 , 我们多次访问 `http://127.0.0.1:5000/user` 可观察响应
-## 请求上下文 🍀
+## 请求上下文
在我们使用 `flask.request` 之前 , 我们必须保证在 `_request_ctx_stack` 中有 `RequestContext` 对象 , 因为在 Flask 中 , 请求的处理是从创建 `RequestContext` 对象 , 并将该对象压入 `_request_ctx_stack` 栈开始的
@@ -312,7 +312,7 @@ with app.test_request_context('/?next=http://example.com/') as rqc:
"""
```
-### 回调与错误 🍀
+### 回调与错误
在 Flask 中 , 请求处理时如果发生了一个错误将会发生什么事 ? 这个特殊的行为如下:
@@ -323,7 +323,7 @@ with app.test_request_context('/?next=http://example.com/') as rqc:
在生产模式中 , 如果一个异常没有被捕获 , 将调用 500 internal server 的处理 , 在生产模式中 , 即便异常没有被处理过 , 也会冒泡给 WSGI 服务器 , 如此 , 像交互式调试器这样的东西可以提供丰富的调试信息
-## 应用上下文 🍀
+## 应用上下文
应用上下文会按需自动创建和销毁 , 如在将请求上下文对象压入栈中时 , 如果应用上下文栈中没有 , 则会先创建应用上下文 , 它不会在线程间移动 , 并且也不会在请求间共享
diff --git "a/05-Web\346\241\206\346\236\266/Flask/DBUtils.md" b/docs/flask/dbutils.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/DBUtils.md"
rename to docs/flask/dbutils.md
index 029b5e71a..aff20931a 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/DBUtils.md"
+++ b/docs/flask/dbutils.md
@@ -9,11 +9,11 @@
-## 介绍 🍀
+## 介绍
DBUtils 是 Python 的一个用于实现数据库连接池的模块 , 此连接池有两种连接模式
-## 模式一 🍀
+## 模式一
为每个线程创建一个连接 , 线程即使调用了 close 方法 , 也不会关闭 , 只是把连接重新放到连接池 , 供自己线程再次使用 , 当线程终止时 , 连接自动关闭
@@ -66,7 +66,7 @@ def func():
func()
```
-## 模式二 🍀
+## 模式二
创建一批连接到连接池 , 供所有线程共享使用 (由于 pymysql , MySQLdb 等 threadsafety 值为 1 , 所以该模式连接池中的线程会被所有线程共享)
diff --git "a/05-Web\346\241\206\346\236\266/Flask/10-Flask - \346\211\251\345\261\225.md" b/docs/flask/ext.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/10-Flask - \346\211\251\345\261\225.md"
rename to docs/flask/ext.md
index 72f33f38c..d024ef7f4 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/10-Flask - \346\211\251\345\261\225.md"
+++ b/docs/flask/ext.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
Flask 扩展多方面地扩充了 Flask 功能 , 例如它们添加了数据库支持以及其他常见任务
@@ -17,7 +17,7 @@ Flask 扩展的生态非常繁荣 , Flask 扩展被列出在 [Flask Extension R
下面介绍一些常用的扩展以及它们的使用方式
-## Flask-Script 🍀
+## Flask-Script
Django 提供了如下管理命令 :
@@ -66,7 +66,7 @@ optional arguments:
-?, --help show this help message and exit
```
-### 创建命令 🍀
+### 创建命令
接下来我们需要创建我们自己的命令 , 创建命令有三种方式 :
@@ -126,7 +126,7 @@ optional arguments:
-?, --help show this help message and exit
```
-### 添加参数 🍀
+### 添加参数
大多数命令都采用了在命令行中传递许多命名参数或者位置参数 , 为了方便这一点 , 我们可以使用 Command 类中的 `option_list` 属性 :
@@ -198,7 +198,7 @@ def hello(name, url):
Documentation : [Read docs @ pythonhosted.org](http://pythonhosted.org/Flask-Script/)
-## Flask-DebugToolbar 🍀
+## Flask-DebugToolbar
Django 有非常知名的 Django-DebugToolbar , 而 Flask 也有对应的替代工具 Flask-DebugToolbar
@@ -251,7 +251,7 @@ Flask-DebugToolbar 内置了很多面板 , 如下 :
Documentation : [Read docs @ github.com](https://github.com/mgood/flask-debugtoolbar)
-## Flask-Migrate 🍀
+## Flask-Migrate
使用关系型数据库时 , 修改数据库模型和更新数据库这样的工作时有发生 , 而且很重要
@@ -328,7 +328,7 @@ INFO [alembic.runtime.migration] Running upgrade -> d121144e719e, empty messag
Documentation : [Read docs @ pythonhosted.org](http://pythonhosted.org/Flask-Migrate/)
-## Flask-RESTful 🍀
+## Flask-RESTful
Flask-RESTful 帮助你快速创建 REST API 服务
@@ -451,7 +451,7 @@ Server: Werkzeug/0.12.2 Python/3.5.2
Documentation : [Read docs @ flask-restful.readthedocs.org](https://flask-restful.readthedocs.org/)
-## Flask-Admin 🍀
+## Flask-Admin
有了 Flask-Admin 的帮助 , 我们用很少的代码就能像 Django 那样实现一个管理后台 , 它支持 Pymongo , Peewee , Mongoengine , SQLAlchemy 等数据库使用方法 , 自带了基于模型的数据管理 , 文件管理 , Redis 的页面命令行等类型后台 , 尤其是模型的管理后台 , 甚至可以细粒度定制字段级别的权限
diff --git "a/05-Web\346\241\206\346\236\266/Flask/01-Flask - \346\272\220\347\240\201\347\256\200\350\246\201\350\257\264\346\230\216.md" b/docs/flask/introduction.md
similarity index 97%
rename from "05-Web\346\241\206\346\236\266/Flask/01-Flask - \346\272\220\347\240\201\347\256\200\350\246\201\350\257\264\346\230\216.md"
rename to docs/flask/introduction.md
index cbf6cc2b5..971f8eff0 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/01-Flask - \346\272\220\347\240\201\347\256\200\350\246\201\350\257\264\346\230\216.md"
+++ b/docs/flask/introduction.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
内容概况
@@ -38,7 +38,7 @@ flask
└── wrappers.py # 实现了WSGI包装器,即request和response
```
-## 阅读指引 🍀
+## 阅读指引
本目录下为 Flask 源码阅读相关 , 读者应该对 WSGI 和 socketserver 有一定的了解 , 因为在某些部分这可能成为阻碍 , 相对而言 , Flask 的源码比 Django 要简单得多 , 因为 Django 过于庞大 , 并且耦合度高
diff --git "a/05-Web\346\241\206\346\236\266/Flask/07-Flask - \346\272\220\347\240\201\344\271\213\346\234\254\345\234\260\347\272\277\347\250\213.md" b/docs/flask/local-threading.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Flask/07-Flask - \346\272\220\347\240\201\344\271\213\346\234\254\345\234\260\347\272\277\347\250\213.md"
rename to docs/flask/local-threading.md
index bdc8acd87..65a38e2f7 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/07-Flask - \346\272\220\347\240\201\344\271\213\346\234\254\345\234\260\347\272\277\347\250\213.md"
+++ b/docs/flask/local-threading.md
@@ -9,13 +9,13 @@
-## 介绍 🍀
+## 介绍
Flask 中的一条设计原则是保持任务的简单 , 任务的实现不需要花费太多的代码 , 也不会限制到你 ; 例如 , 为了保持线程安全 , Flask 使用了本地线程 `(thread-local)` , 所以在一个请求中你不需要在函数之间传递对象
本地线程 `(thread-local)` : 希望不同的线程对于内容的修改只在线程内发挥作用 , 线程之间互不影响
-## Threading的Local 🍀
+## Threading的Local
我们可以通过一个例子来看看 , 本地线程是如何实现的 , 示例如下 :
@@ -166,7 +166,7 @@ object.__setattr__(self, name, value)
本地线程的实现原理就是 , 数据的改变是在线程内部进行的 , 在每一个线程内部都有一个独立的字典 , 存放着那些数据 , 并且通过线程 id 和 dicts 属性 , 保存了不同线程的状态
-## Werkzeug的Local 🍀
+## Werkzeug的Local
总而言之 , 本地线程的实现 , 相当于在线程内部建立了一个数据副本 , 只不过我们需要一些手段来保存好这些线程的状态
@@ -238,7 +238,7 @@ except ImportError:
如果已经安装了 `Greenlet` , 会优先使用 `Greenlet` , 否则将使用系统线程 ; `Greenlet` 是以 C 扩展模块形式接入 Python 的轻量级协程 , 它运行在操作系统进程的内部 , 但是会被协作式地调度
-## 小结 🍀
+## 小结
Werkzeug 基于自己实现的 `Local` 还实现了两种数据结果 :
diff --git "a/05-Web\346\241\206\346\236\266/Flask/04-Flask - \346\272\220\347\240\201\344\271\213\350\267\257\347\224\261.md" b/docs/flask/router.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/04-Flask - \346\272\220\347\240\201\344\271\213\350\267\257\347\224\261.md"
rename to docs/flask/router.md
index fc22a32e7..656332fa3 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/04-Flask - \346\272\220\347\240\201\344\271\213\350\267\257\347\224\261.md"
+++ b/docs/flask/router.md
@@ -9,11 +9,11 @@
-## 介绍 🍀
+## 介绍
在分析 Flask 的请求处理流程中 , 已经碰到了一些路由相关的代码了 , 但是并未深入 , 现在就来看看吧
-## 添加路由 🍀
+## 添加路由
通常我们使用 Flask 中的装饰器 `route` 来完成路由注册 , 实际上 , 它也仅仅是一个中介 , 方便我们使用 ; 本质上它只是帮我们调用了 Flask 对象中的 `add_url_rule` 方法 , 如下 :
@@ -92,7 +92,7 @@ def add_url_rule(self, rule, endpoint=None, view_func=None,
self.view_functions[endpoint] = view_func
```
-## 绑定路由 🍀
+## 绑定路由
我们已经知道 , 路由的转换是利用`Map` 对象来实现的 , `self.url_map.add(rule)` 源码如下 :
@@ -192,7 +192,7 @@ def compile(self):
self._regex = re.compile(regex, re.UNICODE)
```
-## 转换器 🍀
+## 转换器
在上面这段代码中 , 主要流程为 : 根据 `url` 中的信息 , 解析使用什么转换器 , 以及含有的变量等 , 再利用转换器的规则 , 生成路由放入 `regex_parts` 中 ; `Map` 对象中提供了一些默认的转换器 :
@@ -265,7 +265,7 @@ def string_view(lang_code):
return lang_code
```
-## 自定义转换器 🍀
+## 自定义转换器
在 Flask 默认的转换器中 , 并没有支持正则的 , 如果我们需要像 Django 一样 , 支持正则 , 那就需要我们自己来增加这个规则了 , 也就是自定义一个转换器
@@ -296,7 +296,7 @@ def index(nid):
return "Index"
```
-## 反向生成URL 🍀
+## 反向生成URL
在 Django 中 , 利用 `reverse()` 来反向生成 URL , 而在 Flask 中 , 也提供了一个函数可以反向生成 URL : `url_for()`
@@ -381,7 +381,7 @@ def url_for(endpoint, **values):
return rv
```
-## 补充 🍀
+## 补充
关于路由默认的 `methods` 属性 , `Rule` 对象实例化时 , 会完成3次添加 :
diff --git "a/05-Web\346\241\206\346\236\266/Flask/03-Flask - \346\272\220\347\240\201\344\271\213\351\205\215\347\275\256.md" b/docs/flask/settings.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/03-Flask - \346\272\220\347\240\201\344\271\213\351\205\215\347\275\256.md"
rename to docs/flask/settings.md
index 2759839e1..5a0ac0bd1 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/03-Flask - \346\272\220\347\240\201\344\271\213\351\205\215\347\275\256.md"
+++ b/docs/flask/settings.md
@@ -9,11 +9,11 @@
-## 介绍 🍀
+## 介绍
Flask 中的配置主要使用 `flask/config.py` 中的两个对象 : `Config` , `ConfigAttribute`
-## Config 🍀
+## Config
Config 是 dict 的子类 , 所以它的一些行为跟 dict 一样
@@ -136,7 +136,7 @@ class TestingConfig(Config):
app.config.from_object('configmodule.ProductionConfig')
```
-## ConfigAttribute 🍀
+## ConfigAttribute
该类的作用就是为config设置一些属性
@@ -176,7 +176,7 @@ class ConfigAttribute(object):
obj.config[self.__name__] = value
```
-## defaults_config 🍀
+## defaults_config
接下来我们看看关于 Flask 的一些默认的设置 , 首先是 Flask 对象中的 `defaults_config` , 它是一个 `ImmutableDict` 对象
@@ -289,7 +289,7 @@ instance_relative_config=False,
root_path=None
```
-## 配置加载 🍀
+## 配置加载
那么了解了 `config.py` 中的内容后 , 我们应该想的是 , Flask 到底是如何去加载的
diff --git "a/05-Web\346\241\206\346\236\266/Flask/09-Flask - \346\272\220\347\240\201\344\271\213\344\277\241\345\217\267.md" b/docs/flask/signal.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/09-Flask - \346\272\220\347\240\201\344\271\213\344\277\241\345\217\267.md"
rename to docs/flask/signal.md
index f8102c674..9ef65ba6b 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/09-Flask - \346\272\220\347\240\201\344\271\213\344\277\241\345\217\267.md"
+++ b/docs/flask/signal.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
项目功能越复杂 , 代码量越大 , 就越需要在其之上做开发和维护是很痛苦的 , 尤其是对于团队的新人 ; 而信号就是在框架核心功能或者一些 Flask 扩展发生动作时发送的通知 , 利用信号可以实现一部分的业务解藕
@@ -82,7 +82,7 @@ for round in range(1,4):
Flask 中有一些钩子 , 如 `before_request` 和 `after_request` , 这些钩子不需要 `Blinker` 库并且允许你改变请求对象 (request) 或者响应对象 (response) , 而信号和钩子做的事情很像 , 只不过信号并不对请求对象和响应对象做改变 , 仅承担记录和通知的工作
-## 内置信号 🍀
+## 内置信号
在 `flask.signals.py` 中我们可以看到 , Flask 内置了 10 个信号 :
@@ -118,7 +118,7 @@ appcontext_popped = _signals.signal('appcontext-popped')
message_flashed = _signals.signal('message-flashed')
```
-### 创建信号 🍀
+### 创建信号
我们以 `request_started` 为例来看看其内部实现 :
@@ -151,7 +151,7 @@ class Namespace(dict):
return self.setdefault(name, NamedSignal(name, doc))
```
-### 订阅信号 🍀
+### 订阅信号
如果我们要使用内置信号 , 那么首先我们需要订阅信号 , 也就是使用 `Signal.connect()` 方法
@@ -244,7 +244,7 @@ def connect(self, receiver, sender=ANY, weak=True):
return receiver
```
-### 发送信号 🍀
+### 发送信号
信号的发送是通过 `Signal.send()` 来完成的 , 而这一步早已经被定义在 `Flask` 对象中了 , 如下 :
@@ -395,7 +395,7 @@ from .signals import message_flashed
这里就不再分析其它信号了
-## 自定义信号 🍀
+## 自定义信号
在我们的应用中 , 我们可以直接使用 `Blinker` 创建信号 , 如下 , 定义一中对于上传大文件的信号 :
@@ -407,7 +407,7 @@ large_file_saved = web_signals.signal('large-file-saved')
简直不要太简单
-## 装饰器方式 🍀
+## 装饰器方式
在 `Signal` 对象中还有一个 `connect_via()` 装饰器订阅信号 , 如下 :
diff --git "a/05-Web\346\241\206\346\236\266/Flask/02-Flask - \346\272\220\347\240\201\344\271\213\345\274\200\345\247\213.md" b/docs/flask/start.md
similarity index 99%
rename from "05-Web\346\241\206\346\236\266/Flask/02-Flask - \346\272\220\347\240\201\344\271\213\345\274\200\345\247\213.md"
rename to docs/flask/start.md
index 3d23c3b2c..070464109 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/02-Flask - \346\272\220\347\240\201\344\271\213\345\274\200\345\247\213.md"
+++ b/docs/flask/start.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
Flask 中文文档比较齐全 , 阅读源码最好的方式应该是从最简单的应用开始
@@ -30,7 +30,7 @@ if __name__ == '__main__':
app.run()
```
-## 绑定路由 🍀
+## 绑定路由
我们首先实例化了 Flask 对象 , 我们传入了一个参数 `import_name` , 该参数的概念是给 Flask 一个属于你的应用程序的概念 , 它用于查找文件系统上的资源 , 可以由扩展名用于改进调试信息等
@@ -122,7 +122,7 @@ def add_url_rule(self, rule, endpoint=None, view_func=None,
self.view_functions[endpoint] = view_func
```
-## 启动WSGI服务器 🍀
+## 启动WSGI服务器
到这里 , 好像路由与视图函数都准备好了 , 那么接下来就是启动该应用了 , `app.run()`
@@ -208,7 +208,7 @@ def serve_forever(self, poll_interval=0.5):
而在 Flask 中 , 如上 , 也继承了 `http.server.HTTPServer`
-## 创建服务器实例 🍀
+## 创建服务器实例
在 `BaseWSGIServer` 进行实例化时 , 与 Django 一样 , 都传入了一个 `RequestHandlerClass` 参数 , 这个参数听名字就知道 , 它是处理请求的核心 , 源码如下 :
@@ -250,7 +250,7 @@ def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self)
```
-## 实例化WSGI请求处理类 🍀
+## 实例化WSGI请求处理类
至此 , 在创建服务器实例 , 也就是 `BaseWSGIServer` 时 , 已经将该类传入 , 即 `WSGIRequestHandler` ; 重点来了 , `WSGIRequestHandler` 自身根本没有构造函数 , 它的基类 `socketserver.TCPServer` 还是没有 , 继续往上发现 , 关于 `RequestHandlerClass` 初始化的函数在继承链的顶部 `socketserver.BaseServer` 中 , 其构造函数如下 :
@@ -312,7 +312,7 @@ def handle_one_request(self):
return self.run_wsgi()
```
-## 视图调度 🍀
+## 视图调度
摘取 `run_wsgi()` 部分代码如下 :
@@ -527,7 +527,7 @@ def finalize_request(self, rv, from_error_handler=False):
到这里其实我们已经分析的差不多了 , 当 response 对象获取之后 , 一步步往外返回 , 将会返回到 werkzeug 层次 , 当然 werkzeug 也是使用 socketserver 的一部分功能来完成这些操作 , 这一部分就不再分析了
-## 小结 🍀
+## 小结
首先 , 从整体来讲 , 我们可以通过与 Django 进行对比 :
diff --git "a/05-Web\346\241\206\346\236\266/Flask/05-Flask - \346\272\220\347\240\201\344\271\213\350\247\206\345\233\276.md" b/docs/flask/views.md
similarity index 98%
rename from "05-Web\346\241\206\346\236\266/Flask/05-Flask - \346\272\220\347\240\201\344\271\213\350\247\206\345\233\276.md"
rename to docs/flask/views.md
index f95e70ac2..437865ca4 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/05-Flask - \346\272\220\347\240\201\344\271\213\350\247\206\345\233\276.md"
+++ b/docs/flask/views.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
在 Flask 请求处理流程中 , 视图的调用是由 `dispatch_request()` 方法来控制的
@@ -38,7 +38,7 @@ class MethodView(with_metaclass(MethodViewType, View)):
```
-## View 🍀
+## View
```python
class View(object):
@@ -122,7 +122,7 @@ if __name__ == '__main__':
app.run()
```
-## MethodViewType 🍀
+## MethodViewType
```python
class MethodViewType(type):
@@ -147,7 +147,7 @@ class MethodViewType(type):
cls.methods = methods
```
-## MethodView 🍀
+## MethodView
```python
class MethodView(with_metaclass(MethodViewType, View)):
diff --git "a/05-Web\346\241\206\346\236\266/Flask/virtualenv\345\237\272\346\234\254\344\275\277\347\224\250.md" b/docs/flask/virtualenv.md
similarity index 92%
rename from "05-Web\346\241\206\346\236\266/Flask/virtualenv\345\237\272\346\234\254\344\275\277\347\224\250.md"
rename to docs/flask/virtualenv.md
index e34f3710b..3feb7c925 100644
--- "a/05-Web\346\241\206\346\236\266/Flask/virtualenv\345\237\272\346\234\254\344\275\277\347\224\250.md"
+++ b/docs/flask/virtualenv.md
@@ -9,13 +9,13 @@
-## 介绍 🍀
+## 介绍
随着我们所开发或者管理的项目越来越多 , 这就导致了有可能存在不同版本的Python , 又或者是不同版本的Python库 , 于是问题就出现了 , 库的版本问题颇快了向后兼容性的情况相当常见 , 而且零依赖的正式应用也不大可能存在 , 所以项目中的两个或者更多出现依赖性冲突就会频繁出现
所以 , 为了解决这些冲突 , virtualenv出现了 , virtualenv能够允许多个不同版本的Python安装 , 每一个服务与各自的项目 , 但是它并不是分别独立安装一个Python的副本 , 而是提供了一种方式使得环境保持独立
-## 安装virtualenv 🍀
+## 安装virtualenv
实际上 , virtualenv就是一个Python库 , 所以我们可以使用pip等命令进行安装
@@ -39,7 +39,7 @@ $ pip install virtualenv
-## 创建虚拟环境 🍀
+## 创建虚拟环境
通常我们会先创建一个项目文件夹 , 在其下创建venv虚拟环境 :
@@ -57,7 +57,7 @@ Installing distribute............done.
$ virtualenv -p /usr/bin/python2.7 venv
```
-## 激活虚拟环境 🍀
+## 激活虚拟环境
在OS X 和Linux 下
@@ -78,7 +78,7 @@ $ source venv/bin/activate
```
-## 退出虚拟环境 🍀
+## 退出虚拟环境
在OS X 和Linux 下
diff --git "a/04-\345\211\215\347\253\257/README.md" b/docs/front-end/README.md
similarity index 100%
rename from "04-\345\211\215\347\253\257/README.md"
rename to docs/front-end/README.md
diff --git "a/04-\345\211\215\347\253\257/11-Web\345\274\200\345\217\221 - Ajax.md" b/docs/front-end/ajax.md
similarity index 98%
rename from "04-\345\211\215\347\253\257/11-Web\345\274\200\345\217\221 - Ajax.md"
rename to docs/front-end/ajax.md
index 14bf49c03..73d39b93c 100644
--- "a/04-\345\211\215\347\253\257/11-Web\345\274\200\345\217\221 - Ajax.md"
+++ b/docs/front-end/ajax.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
Ajax : `Asynchronous JavaScript and XML` , 意思就是用JavaScript执行异步网络请求
@@ -27,7 +27,7 @@ Ajax是基于现有的Internet标准 , 并且联合使用它们 :
AJAX应用程序与浏览器和平台无关的
-## XHR创建对象 🍀
+## XHR创建对象
`XMLHttpRequest`是Ajax的基础 , 所有现代浏览器均支持XMLHttpRequest对象 (IE5 和 IE6使用ActiveXObject)
@@ -56,7 +56,7 @@ else
}
```
-## XHR请求 🍀
+## XHR请求
将请求发送到服务器 , 使用XMLHttpRequest对象的open() 和 send()
@@ -97,7 +97,7 @@ xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Henry&lname=Ford");
```
-## XHR响应 🍀
+## XHR响应
获取服务器的响应 , 可以使用XMLHttpRequest对象的`responseText`或`responseXML`属性
@@ -125,7 +125,7 @@ for (i=0;i
-## 前言 🍀
+## 前言
为避免上一篇篇幅过长 , body部分在这一篇进行整理 , 主要介绍常用标签
-## < h > 🍀
+## < h >
定义标题 , < h1 > ~ < h6 > , 标题从大到小
@@ -26,7 +26,7 @@
标题六
```
-## < p > and < br > 🍀
+## < p > and < br >
< p > 标签用于定义段落 , 默认段落之间是有间隔的 , 并且浏览器会自动地在段落前后添加空行(块级标签)
@@ -38,7 +38,7 @@
这是第三个段落
```
-## < b > and < i > 🍀
+## < b > and < i >
定义文本粗体和斜体
@@ -54,7 +54,7 @@
我是删除线
```
-## < ul > < ol > < dl > 🍀
+## < ul > < ol > < dl >
定义列表 , 区别如下 :
@@ -85,7 +85,7 @@
```
-## < select > 🍀
+## < select >
定义下拉列表 , < select > 元素中的 < option > 标签定义了列表中的可用选项
@@ -123,7 +123,7 @@
```
-## < img > 🍀
+## < img >
插入图像
@@ -137,7 +137,7 @@
```
-## < table > 🍀
+## < table >
定义表格 , 每个表格均有若干行(< tr > 标签定义) , 每行分为若干单元格(< td > 标签定义) , 以及表格的标头(由< th > 标签定义)
@@ -156,7 +156,7 @@
```
-## < div > and < span > 🍀
+## < div > and < span >
HTML可以通过< div > 和 < span >将元素组合起来
@@ -189,7 +189,7 @@ HTML可以通过< div > 和 < span >将元素组合起来
```
-## < form > 🍀
+## < form >
< form >为表单标签 , 表单是一个包含表单元素的区域
@@ -213,7 +213,7 @@ password:
```
-## < input > 🍀
+## < input >
< input >标签规定了用户可以在其中输入数据的输入字段 , 输入字段可以通过多种方式改变 , 取决于type属性
@@ -238,7 +238,7 @@ password:
以上简单的介绍了几个属性 , 更多input元素属性可以通过访问[W3school](http://www.w3school.com.cn/tags/tag_input.asp)进行学习
-## < lable > 🍀
+## < lable >
< label > 标签为input元素定义标注(标记)
@@ -254,7 +254,7 @@ lable元素不会向用户呈现任何特殊效果 , 不过当鼠标点击时 ,
```
-## < textarea > 🍀
+## < textarea >
用于定义多行文本
@@ -267,7 +267,7 @@ lable元素不会向用户呈现任何特殊效果 , 不过当鼠标点击时 ,
```
-## < fieldset > 🍀
+## < fieldset >
< fieldset >标签用于将表单内容的一部分打包 , 生成一组相关表单的字段 , 浏览器会以特殊方式来显示 , 它们可能有特殊的边界 , 3D效果 , 或者甚至可创建一个子表单来处理这些元素
diff --git "a/04-\345\211\215\347\253\257/07-Web\345\274\200\345\217\221 - BOM.md" b/docs/front-end/bom.md
similarity index 99%
rename from "04-\345\211\215\347\253\257/07-Web\345\274\200\345\217\221 - BOM.md"
rename to docs/front-end/bom.md
index 725a14716..01a0210ba 100644
--- "a/04-\345\211\215\347\253\257/07-Web\345\274\200\345\217\221 - BOM.md"
+++ b/docs/front-end/bom.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
由于JavaScript的出现就是为了能在浏览器中运行 , BOM , 即浏览器对象模型(Browser Object Model) , BOM使JavaScript有能力与浏览器进行"对话"
@@ -19,7 +19,7 @@
下面就开始介绍浏览器对象啦
-## Window 🍀
+## Window
所有的浏览器都支持`window`对象 , 它表示浏览器窗口 , 所有JavaScript全局对象 , 函数以及变量均自动成为window对象的成员 , 也就是说Window对象是客户端JavaScript最高层对象之一
@@ -84,7 +84,7 @@ alert('window inner size:' + window.innerWidth + 'x' + window.innerHeight);
// 直接在浏览器中consle下执行
```
-## document 🍀
+## document
每个载入浏览器的HTML文档都会成为document对象 , document对象使我们可以从脚本中对HTML页面中的所有元素进行访问
@@ -121,7 +121,7 @@ document对象方法
document.title = '努力学习JavaScript!';
```
-## navigator 🍀
+## navigator
navigator对象包含有关浏览器的信息 , 所有浏览器中都支持 , navigator对象的实例是唯一的 , 它是Window对象的子对象 , 所以可以用Window对象的navigator属性来引用它 , 即`window.navigator` , 当然也可以直接`navigator`
@@ -159,7 +159,7 @@ alert('appName = ' + navigator.appName + '\n' +
'userAgent = ' + navigator.userAgent);
```
-## screen 🍀
+## screen
screen对象中存放着有关显示浏览器屏幕的信息 , 可用Window对象中的screen属性直接引用 , 即`window.screen` , 或者`screen` , 所有浏览器都支持
@@ -187,7 +187,7 @@ screen对象属性
alert('screen size = ' + screen.width + ' x ' + screen.height);
```
-## history 🍀
+## history
history对象最初设计来表示窗口的浏览历史 , 但出于隐私方面的原因 , history对象不在允许脚本访问已经访问过的实际URL , 唯一保持使用的功能只有[back()](http://www.w3school.com.cn/jsref/met_his_back.asp)、[forward()](http://www.w3school.com.cn/jsref/met_his_forward.asp) 和 [go()](http://www.w3school.com.cn/jsref/met_his_go.asp) 方法
@@ -215,7 +215,7 @@ history.back()
// 返回结果:undefined
```
-## location 🍀
+## location
location对象包含有关当前URL的信息 , location对象是Window对象的一部分 , 可通过`window.location`属性来访问 , 或者`location`
diff --git "a/04-\345\211\215\347\253\257/05-Web\345\274\200\345\217\221 - CSS.md" b/docs/front-end/css.md
similarity index 97%
rename from "04-\345\211\215\347\253\257/05-Web\345\274\200\345\217\221 - CSS.md"
rename to docs/front-end/css.md
index 9d9d6e1a1..6109e7d5c 100644
--- "a/04-\345\211\215\347\253\257/05-Web\345\274\200\345\217\221 - CSS.md"
+++ b/docs/front-end/css.md
@@ -9,7 +9,7 @@
-## 介绍 🍀
+## 介绍
CSS指的是**层叠样式表(Cascading Style Sheets)** , 用于定义如何显示HTML元素
@@ -49,7 +49,7 @@ CSS是在HTML 4 开始使用的 , 是为了更好的渲染HTML元素而引入的
```
-## 选择器 🍀
+## 选择器
CSS规则由两个主要的部分构成 : 选择器 , 以及一条或多条声明 , 如下 :
@@ -59,7 +59,7 @@ selector {declaration1;declaration2;... declarationN}
选择器的种类有很多 , 下面就开始介绍各种选择器
-### 元素选择器 🍀
+### 元素选择器
元素选择器又称标签选择器
@@ -69,7 +69,7 @@ selector {declaration1;declaration2;... declarationN}
div {background-color:red;}
```
-### Class选择器 🍀
+### Class选择器
class选择器用于描述一组元素的样式 , class可以在多个元素中使用
@@ -84,7 +84,7 @@ p.center {text-align:center;}
类名的第一个字符不能使用数字 , 它无法在Mozilla或Firefox中起作用/
-### ID选择器 🍀
+### ID选择器
ID选择器可以为标有特定id的HTML元素指定特定的样式
@@ -98,7 +98,7 @@ CSS中ID选择器以"#"来定义
ID属性不要以数字开头 , 数字开头的ID在Mozilla/Firefox浏览器中不起作用
-### 属性选择器 🍀
+### 属性选择器
选择拥有某些属性的元素 , 也可设置特定属性
@@ -113,7 +113,7 @@ p[class="important warning"] {color: red;}
p[class~="important"] {color: red;}
```
-### 后代选择器 🍀
+### 后代选择器
后代选择器又称包含选择器 , 后代选择器可以选择作为**某元素后代**的元素
@@ -122,7 +122,7 @@ p[class~="important"] {color: red;}
h1 em {color:red;}
```
-### 子元素选择器 🍀
+### 子元素选择器
与后代选择器相比 , 子元素选择器只能选择作为某元素子元素中的元素
@@ -131,7 +131,7 @@ h1 em {color:red;}
h1 > strong {color:red;}
```
-### 相邻兄弟选择器 🍀
+### 相邻兄弟选择器
相邻兄弟选择器可以选择紧接在另一元素后的元素 , 且二者有相同父元素
@@ -140,7 +140,7 @@ h1 > strong {color:red;}
h1 + p {margin-top:50px;}
```
-### 伪类 🍀
+### 伪类
伪类用于向某些选择器添加特殊的效果
@@ -160,7 +160,7 @@ a.red : visited {color: #FF0000}
CSS Syntax
```
-### 伪元素 🍀
+### 伪元素
伪元素用于向某些选择器设置特殊效果
@@ -196,9 +196,9 @@ input,div,p { background-color:red; }
```
-## 常用属性 🍀
+## 常用属性
-### background 🍀
+### background
**背景色**
@@ -270,7 +270,7 @@ body {
}
```
-### border 🍀
+### border
border属性允许规定元素边框的样式 , 宽度和颜色
@@ -284,7 +284,7 @@ p.aside {border-style: solid dotted dashed double;}
更多边框样式及边框相关 , [在我这里](http://www.w3school.com.cn/css/css_border.asp)
-### margin 🍀
+### margin
margin属性可以用来设置外边距 , 接受任何长度单位 , 百分数甚至负值
@@ -316,7 +316,7 @@ p {margin: 1px;} /* 等价于 1px 1px 1px 1px */
- [margin-bottom](http://www.w3school.com.cn/cssref/pr_margin-bottom.asp)
- [margin-left](http://www.w3school.com.cn/cssref/pr_margin-left.asp)
-### padding 🍀
+### padding
padding属性可以设置内边距 , 接受长度值或百分比值 , 但不允许使用负值
@@ -335,7 +335,7 @@ h1 {padding: 10px 0.25em 2ex 20%;}
- [padding-bottom](http://www.w3school.com.cn/cssref/pr_padding-bottom.asp)
- [padding-left](http://www.w3school.com.cn/cssref/pr_padding-left.asp)
-### display 🍀
+### display
display属性规定元素应该生成的框的类型
@@ -355,7 +355,7 @@ display属性常用的值 :
更多[display属性](http://www.w3school.com.cn/cssref/pr_class_display.asp)
-### cursor 🍀
+### cursor
cursor属性规定要显示的光标的类型
@@ -421,7 +421,7 @@ cursor属性规定要显示的光标的类型