|
@ -0,0 +1,3 @@
|
|||
tasks:
|
||||
- before: gp open Day01-15/Day01/code/hello.py
|
||||
command: python3 Day01-15/Day01/code/hello.py
|
|
@ -180,25 +180,32 @@ jupyter notebook
|
|||
|
||||
![](./res/python-jupyter-2.png)
|
||||
|
||||
#### Anaconda - 一站式的数据科学神器
|
||||
Anaconda是专注于数据科学的Python发行版本,其包含了conda、Python等190多个科学包及其依赖项。因为包含的内容较多,Anaconda的下载文件比较大,如果只需要其中一部分的包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和 Python)。对于学习数据科学的人来说,Anaconda是绝对的神器,有兴趣的读者可以阅读[《致Python初学者们 - Anaconda入门使用指南》](https://www.jianshu.com/p/169403f7e40c)一文进行了解。
|
||||
|
||||
#### Sublime - 文本编辑神器
|
||||
|
||||
![](./res/python-sublime.png)
|
||||
|
||||
- 首先可以通过[官方网站](https://www.sublimetext.com/)下载安装程序安装Sublime 3或Sublime 2。
|
||||
|
||||
- 安装包管理工具。通过快捷键Ctrl+`或者在View菜单中选择Show Console打开控制台,输入下面的代码。
|
||||
- 安装包管理工具。
|
||||
1. 通过快捷键Ctrl+`或者在View菜单中选择Show Console打开控制台,输入下面的代码。
|
||||
|
||||
- Sublime 3
|
||||
|
||||
```Python
|
||||
import urllib.request,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib.request.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read())
|
||||
```
|
||||
|
||||
- Sublime 2
|
||||
|
||||
```Python
|
||||
import urllib2,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();os.makedirs(ipp)ifnotos.path.exists(ipp)elseNone;urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read());print('Please restart Sublime Text to finish installation')
|
||||
```
|
||||
2. 手动安装浏览器输入 https://sublime.wbond.net/Package%20Control.sublime-package 下载这个文件
|
||||
下载好以后,打开sublime text,选择菜单Preferences->Browse Packages... 打开安装目录
|
||||
此时会进入到一个叫做Packages的目录下,点击进入上一层目录Sublime Text3,在此目录下有一个文件夹叫做Installed Packages,把刚才下载的文件放到这里就可以了。然后重启sublime text3,观察Preferences菜单最下边是否有Package Settings 和Package Control两个选项,如果有,则代表安装成功了。
|
||||
|
||||
|
||||
- 安装插件。通过Preference菜单的Package Control或快捷键Ctrl+Shift+P打开命令面板,在面板中输入Install Package就可以找到安装插件的工具,然后再查找需要的插件。我们推荐大家安装以下几个插件:
|
||||
|
||||
|
@ -214,9 +221,15 @@ PyCharm的安装、配置和使用我们在后面会进行介绍。
|
|||
|
||||
![](./res/python-pycharm.png)
|
||||
|
||||
#### Gitpod - 一键式在线开发工具
|
||||
|
||||
只需单击即可在GitHub上打开任何Python项目。
|
||||
|
||||
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/jackfrued/Python-100-Days)
|
||||
|
||||
### 练习
|
||||
|
||||
1. 在Python交互环境中下面的代码查看结果并将内容翻译成中文。
|
||||
1. 在Python交互环境中查看下面的代码结果,并将内容翻译成中文。
|
||||
|
||||
```Python
|
||||
import this
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
### 变量和类型
|
||||
|
||||
在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。计算机能处理的数据有很多中类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。
|
||||
在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。计算机能处理的数据有很多种类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。
|
||||
|
||||
- 整型:Python中可以处理任意大小的整数(Python 2.x中有int和long两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(如`0b100`,换算成十进制是4)、八进制(如`0o100`,换算成十进制是64)、十进制(`100`)和十六进制(`0x100`,换算成十进制是256)的表示法。
|
||||
- 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`)。
|
||||
|
@ -99,11 +99,11 @@ print(type(e))
|
|||
|
||||
在对变量类型进行转换时可以使用Python的内置函数(准确的说下面列出的并不是真正意义上的函数,而是后面我们要讲到的创建对象的构造方法)。
|
||||
|
||||
- int():将一个数值或字符串转换成整数,可以指定进制。
|
||||
- float():将一个字符串转换成浮点数。
|
||||
- str():将指定的对象转换成字符串形式,可以指定编码。
|
||||
- chr():将整数转换成该编码对应的字符串(一个字符)。
|
||||
- ord():将字符串(一个字符)转换成对应的编码(整数)。
|
||||
- `int()`:将一个数值或字符串转换成整数,可以指定进制。
|
||||
- `float()`:将一个字符串转换成浮点数。
|
||||
- `str()`:将指定的对象转换成字符串形式,可以指定编码。
|
||||
- `chr()`:将整数转换成该编码对应的字符串(一个字符)。
|
||||
- `ord()`:将字符串(一个字符)转换成对应的编码(整数)。
|
||||
|
||||
### 运算符
|
||||
|
||||
|
@ -118,15 +118,15 @@ Python支持多种运算符,下表大致按照优先级从高到低的顺序
|
|||
| `+` `-` | 加,减 |
|
||||
| `>>` `<<` | 右移,左移 |
|
||||
| `&` | 按位与 |
|
||||
| `^` `|` | 按位异或,按位或 |
|
||||
| `^` `\|` | 按位异或,按位或 |
|
||||
| `<=` `<` `>` `>=` | 小于等于,小于,大于,大于等于 |
|
||||
| `==` `!=` | 等于,不等于 |
|
||||
| `is` `is not` | 身份运算符 |
|
||||
| `in` `not in` | 成员运算符 |
|
||||
| `not` `or` `and` | 逻辑运算符 |
|
||||
| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `|=` `^=` `>>=` `<<=` | (复合)赋值运算符 |
|
||||
| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `\|=` `^=` `>>=` `<<=` | (复合)赋值运算符 |
|
||||
|
||||
>**说明:**在实际开发中,如果搞不清楚优先级可以使用括号来确保运算的执行顺序。
|
||||
>**说明:** 在实际开发中,如果搞不清楚优先级可以使用括号来确保运算的执行顺序。
|
||||
|
||||
下面的例子演示了运算符的使用。
|
||||
|
||||
|
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -31,7 +31,7 @@ else:
|
|||
|
||||
当然如果要构造出更多的分支,可以使用`if…elif…else…`结构,例如下面的分段函数求值。
|
||||
|
||||
$$f(x)=\begin{cases} 3x-5&\text{(x>1)}\\x+2&\text{(-1}\leq\text{x}\leq\text{1)}\\5x+3&\text {(x<-1)}\end{cases}$$
|
||||
![$$f(x)=\begin{cases} 3x-5&\text{(x>1)}\\x+2&\text{(-1}\leq\text{x}\leq\text{1)}\\5x+3&\text {(x<-1)}\end{cases}$$](./res/formula_1.png)
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -79,7 +79,7 @@ else:
|
|||
print('f(%.2f) = %.2f' % (x, y))
|
||||
```
|
||||
|
||||
> **说明:**大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的Python之禅中有这么一句话“Flat is better than nested.”,之所以提出这个观点是因为嵌套结构的嵌套层次多了之后会严重的影响代码的可读性,如果可以使用扁平化的结构就不要去用嵌套,因此之前的写法是更好的做法。
|
||||
> **说明:** 大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的Python之禅中有这么一句话“Flat is better than nested.”,之所以提出这个观点是因为嵌套结构的嵌套层次多了之后会严重的影响代码的可读性,如果可以使用扁平化的结构就不要去用嵌套,因此之前的写法是更好的做法。
|
||||
|
||||
### 练习
|
||||
|
||||
|
@ -130,7 +130,7 @@ else:
|
|||
result = '讲冷笑话'
|
||||
print(result)
|
||||
```
|
||||
> **说明:**上面的代码中使用了random模块的randint函数生成指定范围的随机数来模拟掷骰子。
|
||||
> **说明:** 上面的代码中使用了random模块的randint函数生成指定范围的随机数来模拟掷骰子。
|
||||
|
||||
#### 练习3:百分制成绩转等级制
|
||||
|
||||
|
@ -184,7 +184,7 @@ if a + b > c and a + c > b and b + c > a:
|
|||
else:
|
||||
print('不能构成三角形')
|
||||
```
|
||||
> **说明:**上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
|
||||
> **说明:** 上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
|
||||
|
||||
#### 练习5:个人所得税计算器。
|
||||
|
||||
|
@ -227,4 +227,4 @@ tax = abs(diff * rate - deduction)
|
|||
print('个人所得税: ¥%.2f元' % tax)
|
||||
print('实际到手收入: ¥%.2f元' % (diff + 3500 - tax))
|
||||
```
|
||||
>**说明:**上面的代码中使用了Python内置的`abs()`函数取绝对值来处理`-0`的问题。
|
||||
>**说明:** 上面的代码中使用了Python内置的`abs()`函数取绝对值来处理`-0`的问题。
|
||||
|
|
|
@ -8,6 +8,5 @@ Date: 2018-03-01
|
|||
|
||||
sum = 0
|
||||
for x in range(1, 101):
|
||||
if x % 2 == 0:
|
||||
sum += x
|
||||
sum += x
|
||||
print(sum)
|
||||
|
|
After Width: | Height: | Size: 487 B |
|
@ -6,7 +6,7 @@
|
|||
|
||||
### for-in循环
|
||||
|
||||
如果明确的知道循环执行的次数或者是要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算$\sum_{n=1}^{100}n$。
|
||||
如果明确的知道循环执行的次数或者是要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算![$\sum_{n=1}^{100}n$](./res/formula_1.png)。
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -94,7 +94,7 @@ if counter > 7:
|
|||
print('你的智商余额明显不足')
|
||||
```
|
||||
|
||||
> **说明:**上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
|
||||
> **说明:** 上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
|
||||
|
||||
和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。
|
||||
|
||||
|
|
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 1.2 KiB |
|
@ -2,11 +2,11 @@
|
|||
|
||||
在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。
|
||||
|
||||
$$x_1 + x_2 + x_3 + x_4 = 8$$
|
||||
![$$x_1 + x_2 + x_3 + x_4 = 8$$](./res/formula_1.png)
|
||||
|
||||
事实上,上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。
|
||||
|
||||
$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$
|
||||
![$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$](./res/formula_2.png)
|
||||
|
||||
可以用Python的程序来计算出这个值,代码如下所示。
|
||||
|
||||
|
@ -59,7 +59,7 @@ n = int(input('n = '))
|
|||
print(factorial(m) // factorial(n) // factorial(m - n))
|
||||
```
|
||||
|
||||
> **说明:**Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
|
||||
> **说明:** Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
|
||||
|
||||
|
||||
### 函数的参数
|
||||
|
@ -337,7 +337,7 @@ if __name__ == '__main__':
|
|||
|
||||
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8))。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对[迪米特法则](https://zh.wikipedia.org/zh-hans/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在函数调用结束后依然可以访问,这时候就需要使用[闭包](https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)),这个我们在后续的内容中进行讲解。
|
||||
|
||||
> **说明**:很多人经常会将“闭包”一词和[“匿名函数”](https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)混为一谈,但实际上它们是不同的概念,如果想提前了解这个概念,推荐看看[维基百科](https://zh.wikipedia.org/wiki/)或者[知乎](https://www.zhihu.com/)上对这个概念的讨论。
|
||||
> **说明:** 很多人经常会将“闭包”一词和[“匿名函数”](https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)混为一谈,但实际上它们是不同的概念,如果想提前了解这个概念,推荐看看[维基百科](https://zh.wikipedia.org/wiki/)或者[知乎](https://www.zhihu.com/)上对这个概念的讨论。
|
||||
|
||||
说了那么多,其实结论很简单,从现在开始我们可以将Python代码按照下面的格式进行书写,这一点点的改进其实就是在我们理解了函数和作用域的基础上跨出的巨大的一步。
|
||||
|
||||
|
|
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 311 B |
After Width: | Height: | Size: 798 B |
|
@ -2,7 +2,7 @@
|
|||
|
||||
### 使用字符串
|
||||
|
||||
第二次世界大战促使了现代电子计算机的诞生,当初的想法很简单,就是用计算机来计算导弹的弹道,因此在计算机刚刚诞生的那个年代,计算机处理的信息主要是数值,而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然对数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机处理得更多的数据都是以文本信息的方式存在的,而Python表示文本信息的方式我们在很早以前就说过了,那就是字符串类型。所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为[$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](https://wikimedia.org/api/rest_v1/media/math/render/svg/e29bf631b090323edd6889f810e6cff29538b161)。
|
||||
第二次世界大战促使了现代电子计算机的诞生,当初的想法很简单,就是用计算机来计算导弹的弹道,因此在计算机刚刚诞生的那个年代,计算机处理的信息主要是数值,而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然对数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机处理得更多的数据都是以文本信息的方式存在的,而Python表示文本信息的方式我们在很早以前就说过了,那就是字符串类型。所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_1.png)。
|
||||
|
||||
我们可以通过下面的代码来了解字符串的使用。
|
||||
|
||||
|
@ -183,11 +183,11 @@ if __name__ == '__main__':
|
|||
|
||||
除了上面提到的生成器语法,Python中还有另外一种定义生成器的方式,就是通过`yield`关键字将一个普通函数改造成生成器函数。下面的代码演示了如何实现一个生成[斐波拉切数列](https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97)的生成器。所谓斐波拉切数列可以通过下面[递归](https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92)的方法来进行定义:
|
||||
|
||||
$${\displaystyle F_{0}=0}$$
|
||||
![$${\displaystyle F_{0}=0}$$](./res/formula_2.png)
|
||||
|
||||
$${\displaystyle F_{1}=1}$$
|
||||
![$${\displaystyle F_{1}=1}$$](./res/formula_3.png)
|
||||
|
||||
$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$
|
||||
![$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$](./res/formula_4.png)
|
||||
|
||||
![](./res/fibonacci-blocks.png)
|
||||
|
||||
|
@ -307,7 +307,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:Python中允许通过一些特殊的方法来为某种类型或数据结构自定义运算符(后面的章节中会讲到),上面的代码中我们对集合进行运算的时候可以调用集合对象的方法,也可以直接使用对应的运算符,例如`&`运算符跟intersection方法的作用就是一样的,但是使用运算符让代码更加直观。
|
||||
> **说明:** Python中允许通过一些特殊的方法来为某种类型或数据结构自定义运算符(后面的章节中会讲到),上面的代码中我们对集合进行运算的时候可以调用集合对象的方法,也可以直接使用对应的运算符,例如`&`运算符跟intersection方法的作用就是一样的,但是使用运算符让代码更加直观。
|
||||
|
||||
### 使用字典
|
||||
|
||||
|
@ -530,7 +530,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:上面使用random模块的sample函数来实现从列表中选择不重复的n个元素。
|
||||
> **说明:** 上面使用random模块的sample函数来实现从列表中选择不重复的n个元素。
|
||||
|
||||
#### 综合案例2:[约瑟夫环问题](https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98)
|
||||
|
||||
|
@ -609,4 +609,4 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
>**说明**:最后这个案例来自[《Python编程快速上手:让繁琐工作自动化》](https://item.jd.com/11943853.html)一书(这本书对有编程基础想迅速使用Python将日常工作自动化的人来说还是不错的选择),对代码做了一点点的调整。
|
||||
>**说明:** 最后这个案例来自[《Python编程快速上手:让繁琐工作自动化》](https://item.jd.com/11943853.html)一书(这本书对有编程基础想迅速使用Python将日常工作自动化的人来说还是不错的选择),对代码做了一点点的调整。
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
![](./res/oop-zhihu.png)
|
||||
|
||||
> **说明**:以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。
|
||||
> **说明:** 以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。
|
||||
|
||||
之前我们说过“程序是指令的集合”,我们在程序中书写的语句在执行时会变成一条或多条指令然后由CPU去执行。当然为了简化程序的设计,我们引入了函数的概念,把相对独立且经常重复使用的代码放置到函数中,在需要使用这些功能的时候只要调用函数即可;如果一个函数的功能过于复杂和臃肿,我们又可以进一步将函数继续切分为子函数来降低系统的复杂性。但是说了这么多,不知道大家是否发现,所谓编程就是程序员按照计算机的工作方式控制计算机完成各种任务。但是,计算机的工作方式与正常人类的思维模式是不同的,如果编程就必须得抛弃人类正常的思维方式去迎合计算机,编程的乐趣就少了很多,“每个人都应该学习编程”这样的豪言壮语就只能说说而已。当然,这些还不是最重要的,最重要的是当我们需要开发一个复杂的系统时,代码的复杂性会让开发和维护工作都变得举步维艰,所以在上世纪60年代末期,“[软件危机](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%8D%B1%E6%9C%BA)”、“[软件工程](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B)”等一系列的概念开始在行业中出现。
|
||||
|
||||
当然,程序员圈子内的人都知道,现实中并没有解决上面所说的这些问题的“[银弹](https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9)”,真正让软件开发者看到希望的是上世纪70年代诞生的[Smalltalk](https://zh.wikipedia.org/wiki/Smalltalk)编程语言中引入的面向对象的编程思想(面向对象编程的雏形可以追溯到更早期的[Simula](https://zh.wikipedia.org/wiki/Simula)语言)。按照这种编程理念,程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。
|
||||
|
||||
> **说明**:当然面向对象也不是解决软件开发中所有问题的最后的“银弹”,所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持,Python也不例外。
|
||||
> **说明:** 当然面向对象也不是解决软件开发中所有问题的最后的“银弹”,所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持,Python也不例外。
|
||||
|
||||
### 类和对象
|
||||
|
||||
|
@ -44,10 +44,10 @@ class Student(object):
|
|||
if self.age < 18:
|
||||
print('%s只能观看《熊出没》.' % self.name)
|
||||
else:
|
||||
print('%s正在观看岛国爱情动作片.' % self.name
|
||||
print('%s正在观看岛国爱情动作片.' % self.name)
|
||||
```
|
||||
|
||||
> **说明**:写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。
|
||||
> **说明:** 写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。
|
||||
|
||||
### 创建和使用对象
|
||||
|
||||
|
@ -237,4 +237,4 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:本章中的插图来自于Grady Booch等著作的[《面向对象分析与设计》](https://item.jd.com/20476561918.html)一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。
|
||||
> **说明:** 本章中的插图来自于Grady Booch等著作的[《面向对象分析与设计》](https://item.jd.com/20476561918.html)一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。
|
|
@ -636,7 +636,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
>**说明**:大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏,例如21点(Black Jack),游戏的规则可以自己在网上找一找。
|
||||
>**说明:** 大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏,例如21点(Black Jack),游戏的规则可以自己在网上找一找。
|
||||
|
||||
#### 案例3:工资结算系统
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
####加载图像
|
||||
#### 加载图像
|
||||
|
||||
如果需要直接加载图像到窗口上,可以使用pygame中image模块的函数来加载图像,再通过之前获得的窗口对象的`blit`方法渲染图像,代码如下所示。
|
||||
|
||||
|
@ -164,7 +164,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
####实现动画效果
|
||||
#### 实现动画效果
|
||||
|
||||
说到[动画](https://zh.wikipedia.org/wiki/%E5%8A%A8%E7%94%BB)这个词大家都不会陌生,事实上要实现动画效果,本身的原理也非常简单,就是将不连续的图片连续的播放,只要每秒钟达到了一定的帧数,那么就可以做出比较流畅的动画效果。如果要让上面代码中的小球动起来,可以将小球的位置用变量来表示,并在循环中修改小球的位置再刷新整个窗口即可。
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
要将文本信息写入文件文件也非常简单,在使用`open`函数时指定好文件名并将文件模式设置为`'w'`即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为`'a'`。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示了如何将1-9999直接的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。
|
||||
要将文本信息写入文件文件也非常简单,在使用`open`函数时指定好文件名并将文件模式设置为`'w'`即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为`'a'`。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示了如何将1-9999之间的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。
|
||||
|
||||
```Python
|
||||
from math import sqrt
|
||||
|
@ -174,14 +174,14 @@ if __name__ == '__main__':
|
|||
|
||||
```JSON
|
||||
{
|
||||
'name': '骆昊',
|
||||
'age': 38,
|
||||
'qq': 957658,
|
||||
'friends': ['王大锤', '白元芳'],
|
||||
'cars': [
|
||||
{'brand': 'BYD', 'max_speed': 180},
|
||||
{'brand': 'Audi', 'max_speed': 280},
|
||||
{'brand': 'Benz', 'max_speed': 320}
|
||||
"name": "骆昊",
|
||||
"age": 38,
|
||||
"qq": 957658,
|
||||
"friends": ["王大锤", "白元芳"],
|
||||
"cars": [
|
||||
{"brand": "BYD", "max_speed": 180},
|
||||
{"brand": "Audi", "max_speed": 280},
|
||||
{"brand": "Benz", "max_speed": 320}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
| \| | 分支 | foo\|bar | 可以匹配foo或者bar |
|
||||
| (?#) | 注释 | | |
|
||||
| (exp) | 匹配exp并捕获到自动命名的组中 | | |
|
||||
| (?<name>exp) | 匹配exp并捕获到名为name的组中 | | |
|
||||
| (? <name>exp) | 匹配exp并捕获到名为name的组中 | | |
|
||||
| (?:exp) | 匹配exp但是不捕获匹配的文本 | | |
|
||||
| (?=exp) | 匹配exp前面的位置 | \\b\\w+(?=ing) | 可以匹配I'm dancing中的danc |
|
||||
| (?<=exp) | 匹配exp后面的位置 | (?<=\\bdanc)\\w+\\b | 可以匹配I love dancing and reading中的第一个ing |
|
||||
|
@ -44,7 +44,7 @@
|
|||
| {M,N}? | 重复M到N次,但尽可能少重复 | | |
|
||||
| {M,}? | 重复M次以上,但尽可能少重复 | | |
|
||||
|
||||
> **说明:**如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\\进行转义处理,例如想匹配小数点可以写成\\.就可以了,因为直接写.会匹配任意字符;同理,想匹配圆括号必须写成\\(和\\),否则圆括号被视为正则表达式中的分组。
|
||||
> **说明:** 如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\\进行转义处理,例如想匹配小数点可以写成\\.就可以了,因为直接写.会匹配任意字符;同理,想匹配圆括号必须写成\\(和\\),否则圆括号被视为正则表达式中的分组。
|
||||
|
||||
### Python对正则表达式的支持
|
||||
|
||||
|
@ -64,7 +64,7 @@ Python提供了re模块来支持正则表达式相关操作,下面是re模块
|
|||
| re.I / re.IGNORECASE | 忽略大小写匹配标记 |
|
||||
| re.M / re.MULTILINE | 多行匹配标记 |
|
||||
|
||||
> **说明:**上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。
|
||||
> **说明:** 上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。
|
||||
|
||||
下面我们通过一系列的例子来告诉大家在Python中如何使用正则表达式。
|
||||
|
||||
|
@ -98,7 +98,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **提示**:上面在书写正则表达式时使用了“原始字符串”的写法(在字符串前面加上了r),所谓“原始字符串”就是字符串中的每个字符都是它原始的意义,说得更直接一点就是字符串中没有所谓的转义字符啦。因为正则表达式中有很多元字符和需要进行转义的地方,如果不使用原始字符串就需要将反斜杠写作\\\\,例如表示数字的\\d得书写成\\\\d,这样不仅写起来不方便,阅读的时候也会很吃力。
|
||||
> **提示:** 上面在书写正则表达式时使用了“原始字符串”的写法(在字符串前面加上了r),所谓“原始字符串”就是字符串中的每个字符都是它原始的意义,说得更直接一点就是字符串中没有所谓的转义字符啦。因为正则表达式中有很多元字符和需要进行转义的地方,如果不使用原始字符串就需要将反斜杠写作\\\\,例如表示数字的\\d得书写成\\\\d,这样不仅写起来不方便,阅读的时候也会很吃力。
|
||||
|
||||
#### 例子2:从一段文字中提取出国内手机号码。
|
||||
|
||||
|
@ -136,7 +136,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:上面匹配国内手机号的正则表达式并不够好,因为像14开头的号码只有145或147,而上面的正则表达式并没有考虑这种情况,要匹配国内手机号,更好的正则表达式的写法是:`(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)`,国内最近好像有19和16开头的手机号了,但是这个暂时不在我们考虑之列。
|
||||
> **说明:** 上面匹配国内手机号的正则表达式并不够好,因为像14开头的号码只有145或147,而上面的正则表达式并没有考虑这种情况,要匹配国内手机号,更好的正则表达式的写法是:`(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)`,国内最近好像有19和16开头的手机号了,但是这个暂时不在我们考虑之列。
|
||||
|
||||
#### 例子3:替换字符串中的不良内容
|
||||
|
||||
|
@ -155,7 +155,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:re模块的正则表达式相关函数中都有一个flags参数,它代表了正则表达式的匹配标记,可以通过该标记来指定匹配时是否忽略大小写、是否进行多行匹配、是否显示调试信息等。如果需要为flags参数指定多个值,可以使用[按位或运算符](http://www.runoob.com/python/python-operators.html#ysf5)进行叠加,如`flags=re.I | re.M`。
|
||||
> **说明:** re模块的正则表达式相关函数中都有一个flags参数,它代表了正则表达式的匹配标记,可以通过该标记来指定匹配时是否忽略大小写、是否进行多行匹配、是否显示调试信息等。如果需要为flags参数指定多个值,可以使用[按位或运算符](http://www.runoob.com/python/python-operators.html#ysf5)进行叠加,如`flags=re.I | re.M`。
|
||||
|
||||
#### 例子4:拆分长字符串
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ if __name__ == '__main__':
|
|||
|
||||
除了计算密集型任务,其他的涉及到网络、存储介质I/O的任务都可以视为I/O密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待I/O操作完成(因为I/O的速度远远低于CPU和内存的速度)。对于I/O密集型任务,如果启动多任务,就可以减少I/O等待时间从而让CPU高效率的运转。有一大类的任务都属于I/O密集型任务,这其中包括了我们很快会涉及到的网络应用和Web应用。
|
||||
|
||||
> **说明:**上面的内容和例子来自于[廖雪峰官方网站的《Python教程》](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000),因为对作者文中的某些观点持有不同的看法,对原文的文字描述做了适当的调整。
|
||||
> **说明:** 上面的内容和例子来自于[廖雪峰官方网站的《Python教程》](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000),因为对作者文中的某些观点持有不同的看法,对原文的文字描述做了适当的调整。
|
||||
|
||||
### 单线程+异步I/O
|
||||
|
||||
|
|
|
@ -70,9 +70,9 @@ JSON的例子:
|
|||
|
||||
```JSON
|
||||
{
|
||||
'from': 'Alice',
|
||||
'to': 'Bob',
|
||||
'content': 'Will you marry me?'
|
||||
"from": "Alice",
|
||||
"to": "Bob",
|
||||
"content": "Will you marry me?"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -291,7 +291,7 @@ if __name__ == '__main__':
|
|||
|
||||
在这个案例中,我们使用了JSON作为数据传输的格式(通过JSON格式对传输的数据进行了序列化和反序列化的操作),但是JSON并不能携带二进制数据,因此对图片的二进制数据进行了Base64编码的处理。Base64是一种用64个字符表示所有二进制数据的编码方式,通过将二进制数据每6位一组的方式重新组织,刚好可以使用0~9的数字、大小写字母以及“+”和“/”总共64个字符表示从`000000`到`111111`的64种状态。[维基百科](https://zh.wikipedia.org/wiki/Base64)上有关于Base64编码的详细讲解,不熟悉Base64的读者可以自行阅读。
|
||||
|
||||
> **说明**:上面的代码主要为了讲解网络编程的相关内容因此并没有对异常状况进行处理,请读者自行添加异常处理代码来增强程序的健壮性。
|
||||
> **说明:** 上面的代码主要为了讲解网络编程的相关内容因此并没有对异常状况进行处理,请读者自行添加异常处理代码来增强程序的健壮性。
|
||||
|
||||
#### UDP套接字
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ Pillow中最为重要的是Image类,读取和处理图像都要通过这个类
|
|||
|
||||
```Python
|
||||
>>> image = Image.open('./res/guido.png')
|
||||
>>> image.rotata(180).show()
|
||||
>>> image.rotate(180).show()
|
||||
>>> image.transpose(Image.FLIP_LEFT_RIGHT).show()
|
||||
```
|
||||
|
||||
|
|
|
@ -198,7 +198,8 @@
|
|||
- 常用算法:
|
||||
|
||||
- 穷举法 - 又称为暴力破解法,对所有的可能性进行验证,直到找到正确答案。
|
||||
- 贪婪法 - 在对问题求解时,总是做出在当前看来是最好的选择,不追求最优解,快速找到满意解。
|
||||
- 贪婪法 - 在对问题求解时,总是做出在当前看来
|
||||
- 最好的选择,不追求最优解,快速找到满意解。
|
||||
- 分治法 - 把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到可以直接求解的程度,最后将子问题的解进行合并得到原问题的解。
|
||||
- 回溯法 - 回溯法又称为试探法,按选优条件向前搜索,当搜索到某一步发现原先选择并不优或达不到目标时,就退回一步重新选择。
|
||||
- 动态规划 - 基本思想也是将待求解问题分解成若干个子问题,先求解并保存这些子问题的解,避免产生大量的重复运算。
|
||||
|
@ -218,7 +219,7 @@
|
|||
# 第二天A第一个醒来 他将鱼分为5份 扔掉多余的1条 拿走自己的一份
|
||||
# B第二个醒来 也将鱼分为5份 扔掉多余的1条 拿走自己的一份
|
||||
# 然后C、D、E依次醒来也按同样的方式分鱼 问他们至少捕了多少条鱼
|
||||
fish = 1
|
||||
fish = 6
|
||||
while True:
|
||||
total = fish
|
||||
enough = True
|
||||
|
@ -231,7 +232,7 @@
|
|||
if enough:
|
||||
print(fish)
|
||||
break
|
||||
fish += 1
|
||||
fish += 5
|
||||
```
|
||||
|
||||
贪婪法例子:假设小偷有一个背包,最多能装20公斤赃物,他闯入一户人家,发现如下表所示的物品。很显然,他不能把所有物品都装进背包,所以必须确定拿走哪些物品,留下哪些物品。
|
||||
|
@ -555,6 +556,7 @@
|
|||
|
||||
```Python
|
||||
from functools import wraps
|
||||
from threading import Lock
|
||||
|
||||
|
||||
def singleton(cls):
|
||||
|
@ -767,6 +769,8 @@
|
|||
main()
|
||||
```
|
||||
|
||||
> 说明:上面的代码中使用了Emoji字符来表示扑克牌的四种花色,在某些不支持Emoji字符的系统上可能无法显示。
|
||||
|
||||
- 对象的复制(深复制/深拷贝/深度克隆和浅复制/浅拷贝/影子克隆)
|
||||
|
||||
- 垃圾回收、循环引用和弱引用
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
"""
|
||||
多进程和进程池的使用
|
||||
多线程因为GIL的存在不能够发挥CPU的多核特性
|
||||
对于计算密集型任务应该考虑使用多进程
|
||||
time python3 example22.py
|
||||
real 0m11.512s
|
||||
user 0m39.319s
|
||||
sys 0m0.169s
|
||||
"""
|
||||
import concurrent.futures
|
||||
import math
|
||||
|
||||
PRIMES = [
|
||||
1116281,
|
||||
1297337,
|
||||
104395303,
|
||||
472882027,
|
||||
533000389,
|
||||
817504243,
|
||||
982451653,
|
||||
112272535095293,
|
||||
112582705942171,
|
||||
112272535095293,
|
||||
115280095190773,
|
||||
115797848077099,
|
||||
1099726899285419
|
||||
] * 5
|
||||
|
||||
|
||||
def is_prime(n):
|
||||
"""判断素数"""
|
||||
if n % 2 == 0:
|
||||
return False
|
||||
|
||||
sqrt_n = int(math.floor(math.sqrt(n)))
|
||||
for i in range(3, sqrt_n + 1, 2):
|
||||
if n % i == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
with concurrent.futures.ProcessPoolExecutor() as executor:
|
||||
for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
|
||||
print('%d is prime: %s' % (number, prime))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Before Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 282 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -489,7 +489,7 @@ connecting to: mongodb://172.18.61.250:27017/
|
|||
|
||||
使用MongoDB可以非常方便的配置数据复制,通过冗余数据来实现数据的高可用以及灾难恢复,也可以通过数据分片来应对数据量迅速增长的需求。关于MongoDB更多的操作可以查阅[官方文档](https://mongodb-documentation.readthedocs.io/en/latest/) ,同时推荐大家阅读Kristina Chodorow写的[《MongoDB权威指南》](http://www.ituring.com.cn/book/1172)。
|
||||
|
||||
####在Python程序中操作MongoDB
|
||||
#### 在Python程序中操作MongoDB
|
||||
|
||||
可以通过pip安装pymongo来实现对MongoDB的操作。
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ select stuname as 姓名, year(now())-year(stubirth) as 年龄 from tb_student w
|
|||
);
|
||||
|
||||
-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
|
||||
select stuname from tb_student where stuid=(
|
||||
select stuname from tb_student where stuid in (
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
drop database if exists fangtx;
|
||||
|
||||
create database fangtx default charset utf8 collate utf8_bin;
|
||||
|
||||
use fangtx;
|
||||
|
||||
/* 创建用户表 */
|
||||
create table `tb_user`
|
||||
(
|
||||
`userid` int auto_increment comment '编号',
|
||||
`username` varchar(20) not null comment '用户名',
|
||||
`password` char(32) not null comment '用户口令',
|
||||
`realname` varchar(20) not null comment '真实姓名',
|
||||
`sex` bool default 1 comment '性别',
|
||||
`tel` varchar(20) not null comment '手机号',
|
||||
`email` varchar(255) default '' comment '邮箱',
|
||||
`regdate` datetime default now() comment '注册日期',
|
||||
`point` int default 0 comment '积分',
|
||||
`lastvisit` datetime default now() comment '最后访问时间',
|
||||
`is_authenticated` bit default 0 comment '是否认证',
|
||||
primary key (`userid`)
|
||||
);
|
||||
|
||||
/* 创建地区表 */
|
||||
create table `tb_district`
|
||||
(
|
||||
`distid` int not null comment '编号',
|
||||
`pid` int comment '父级行政单位',
|
||||
`name` varchar(255) not null comment '名称',
|
||||
`ishot` bool default 0 comment '是否为热门城市',
|
||||
`intro` varchar(255) default '' comment '介绍',
|
||||
primary key (distid)
|
||||
);
|
||||
|
||||
/* 创建经理人表 */
|
||||
create table `tb_agent`
|
||||
(
|
||||
`agentid` int not null auto_increment comment '编号',
|
||||
`name` varchar(255) not null comment '姓名',
|
||||
`tel` varchar(20) not null comment '电话',
|
||||
`servstar` int not null default 0 comment '满意度星级',
|
||||
`realstar` int not null default 0 comment '真实度星级',
|
||||
`profstar` int not null default 0 comment '专业度星级',
|
||||
`certificated` bool not null default 0 comment '是否持有专业认证',
|
||||
primary key (`agentid`)
|
||||
);
|
||||
|
||||
/* 创建用户登录日志表 */
|
||||
create table `tb_login_log`
|
||||
(
|
||||
`logid` bigint auto_increment comment '编号',
|
||||
`userid` int not null comment '用户',
|
||||
`ipaddr` varchar(255) not null comment 'IP地址',
|
||||
`logdate` datetime default now() comment '登录时间日期',
|
||||
`devcode` varchar(255) default '' comment '设备代码',
|
||||
primary key (`logid`)
|
||||
);
|
||||
|
||||
/* 创建楼盘表 */
|
||||
create table `tb_estate`
|
||||
(
|
||||
`estateid` int not null auto_increment comment '编号',
|
||||
`distid` int not null comment '所在三级行政区域',
|
||||
`name` varchar(255) not null comment '名称',
|
||||
`hot` int default 0 comment '热度',
|
||||
`intro` varchar(511) default '' comment '介绍',
|
||||
primary key (`estateid`)
|
||||
);
|
||||
|
||||
/* 创建经理人楼盘中间表 */
|
||||
create table `tb_agent_estate`
|
||||
(
|
||||
`agent_estate_id` int not null auto_increment comment '编号',
|
||||
`agentid` int not null comment '经理人',
|
||||
`estateid` int not null comment '楼盘',
|
||||
primary key (`agent_estate_id`)
|
||||
);
|
||||
|
||||
/* 创建户型表 */
|
||||
create table `tb_house_type`
|
||||
(
|
||||
`typeid` int comment '编号',
|
||||
`name` varchar(255) not null comment '名称',
|
||||
primary key (`typeid`)
|
||||
);
|
||||
|
||||
/* 创建房源信息表 */
|
||||
create table `tb_house_info`
|
||||
(
|
||||
`houseid` int not null auto_increment comment '编号',
|
||||
`title` varchar(50) not null comment '标题',
|
||||
`area` int not null comment '面积',
|
||||
`floor` int not null comment '楼层',
|
||||
`totalfloor` int not null comment '总楼层',
|
||||
`direction` varchar(10) not null comment '朝向',
|
||||
`price` int not null comment '价格',
|
||||
`priceunit` varchar(10) not null comment '价格单位',
|
||||
`detail` varchar(511) default '' comment '详情',
|
||||
`mainphoto` varchar(255) not null comment '主图',
|
||||
`pubdate` date not null comment '发布日期',
|
||||
`street` varchar(255) not null comment '街道',
|
||||
`hassubway` bool default 0 comment '是否有地铁',
|
||||
`isshared` bool default 0 comment '是否支持合租',
|
||||
`hasagentfees` bool default 0 comment '是否有中介费',
|
||||
`typeid` int not null comment '户型',
|
||||
`userid` int not null comment '发布用户',
|
||||
`distid2` int not null comment '所在二级行政区域',
|
||||
`distid3` int not null comment '所在三级行政区域',
|
||||
`estateid` int comment '楼盘',
|
||||
`agentid` int comment '经理人',
|
||||
primary key (`houseid`)
|
||||
);
|
||||
|
||||
/* 创建房源照片表 */
|
||||
create table `tb_house_photo`
|
||||
(
|
||||
`photoid` int not null auto_increment comment '编号',
|
||||
`houseid` int not null comment '房源',
|
||||
`path` varchar(255) not null comment '资源路径',
|
||||
primary key (`photoid`)
|
||||
);
|
||||
|
||||
/* 创建标签表 */
|
||||
create table `tb_tag`
|
||||
(
|
||||
`tagid` int auto_increment comment '编号',
|
||||
`content` varchar(20) not null comment '内容',
|
||||
primary key (`tagid`)
|
||||
);
|
||||
|
||||
/* 创建房源标签中间表 */
|
||||
create table `tb_house_tag`
|
||||
(
|
||||
`house_tag_id` int auto_increment comment '编号',
|
||||
`houseid` int not null comment '房源',
|
||||
`tagid` int not null comment '标签',
|
||||
primary key (`house_tag_id`)
|
||||
);
|
||||
|
||||
|
||||
/* 创建用户浏览历史记录表 */
|
||||
create table `tb_record`
|
||||
(
|
||||
`recordid` bigint auto_increment comment '编号',
|
||||
`userid` int not null comment '用户',
|
||||
`houseid` int not null comment '房源',
|
||||
`recorddate` datetime not null comment '浏览时间日期',
|
||||
primary key (`recordid`)
|
||||
);
|
||||
|
||||
/* 创建用户令牌表 */
|
||||
create table `tb_user_token`
|
||||
(
|
||||
`tokenid` int auto_increment comment '编号',
|
||||
`token` char(32) not null comment '令牌',
|
||||
`userid` int not null comment '用户',
|
||||
primary key (`tokenid`)
|
||||
);
|
||||
|
||||
/* 创建角色表 */
|
||||
create table `tb_role`
|
||||
(
|
||||
`roleid` int auto_increment comment '编号',
|
||||
`rolename` varchar(255) not null comment '角色名',
|
||||
primary key (`roleid`)
|
||||
);
|
||||
|
||||
/* 创建权限表 */
|
||||
create table `tb_privilege`
|
||||
(
|
||||
`privid` int auto_increment comment '编号',
|
||||
`method` varchar(15) not null comment '请求方法',
|
||||
`url` varchar(1024) not null comment '资源的URL',
|
||||
PRIMARY KEY (`privid`)
|
||||
);
|
||||
|
||||
/* 创建用户角色中间表 */
|
||||
create table `tb_user_role`
|
||||
(
|
||||
`urid` int auto_increment comment '编号',
|
||||
`userid` int not null comment '用户',
|
||||
`roleid` int not null comment '角色',
|
||||
primary key (`urid`)
|
||||
);
|
||||
|
||||
/* 创建角色权限中间表 */
|
||||
create table `tb_role_privilege`
|
||||
(
|
||||
`rpid` int auto_increment comment '编号',
|
||||
`roleid` int not null comment '角色',
|
||||
`privid` int not null comment '权限',
|
||||
primary key (`rpid`)
|
||||
);
|
||||
|
||||
create unique index `uni_idx_agent_estate` on `tb_agent_estate` (`agentid`, `estateid`);
|
||||
|
||||
create unique index `uni_idx_record` on `tb_record` (`userid`, `houseid`);
|
||||
|
||||
create unique index `uni_idx_userid` on `tb_user_token` (`userid`);
|
||||
|
||||
create unique index `uni_idx_username` on `tb_user` (`username`);
|
||||
|
||||
create unique index `uni_idx_tel` on `tb_user` (`tel`);
|
||||
|
||||
create unique index `uni_idx_email` on `tb_user` (`email`);
|
||||
|
||||
create unique index `uni_idx_house_tag` on `tb_house_tag` (`houseid`, `tagid`);
|
||||
|
||||
alter table `tb_agent_estate` add constraint `fk_agent_estate_agentid` foreign key (`agentid`) references `tb_agent` (`agentid`);
|
||||
|
||||
alter table `tb_agent_estate` add constraint `fk_agent_estate_estateid` foreign key (`estateid`) references `tb_estate` (`estateid`);
|
||||
|
||||
alter table `tb_district` add constraint `fk_district_pid` foreign key (`pid`) references `tb_district` (`distid`);
|
||||
|
||||
alter table `tb_estate` add constraint `fk_estate_distid` foreign key (`distid`) references `tb_district` (`distid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_agentid` foreign key (`agentid`) references tb_agent (`agentid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_distid2` foreign key (`distid2`) references tb_district (`distid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_distid3` foreign key (`distid3`) references tb_district (`distid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_estateid` foreign key (`estateid`) references tb_estate (`estateid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_typeid` foreign key (`typeid`) references tb_house_type (`typeid`);
|
||||
|
||||
alter table `tb_house_info` add constraint `fk_house_info_userid` foreign key (`userid`) references tb_user (`userid`);
|
||||
|
||||
alter table `tb_house_photo` add constraint `fk_house_photo_houseid` foreign key (`houseid`) references `tb_house_info` (`houseid`);
|
||||
|
||||
alter table `tb_house_tag` add constraint `fk_house_tag_houseid` foreign key (`houseid`) references `tb_house_info` (`houseid`);
|
||||
|
||||
alter table `tb_house_tag` add constraint `fk_house_tag_tagid` foreign key (`tagid`) references `tb_tag` (`tagid`);
|
||||
|
||||
alter table `tb_login_log` add constraint `fk_login_log_userid` foreign key (`userid`) references `tb_user` (`userid`);
|
||||
|
||||
alter table `tb_record` add constraint `fk_record_houseid` foreign key (`houseid`) references `tb_house_info` (`houseid`);
|
||||
|
||||
alter table `tb_record` add constraint `fk_record_userid` foreign key (`userid`) references `tb_user` (`userid`);
|
||||
|
||||
alter table `tb_user_token` add constraint `fk_token_userid` foreign key (`userid`) references `tb_user` (`userid`);
|
||||
|
||||
alter table `tb_user_role` add constraint `uni_user_role` unique (`userid`, `roleid`);
|
||||
|
||||
alter table `tb_role_privilege` add constraint `uni_role_priv` unique (`roleid`, `privid`);
|
||||
|
||||
alter table `tb_role_privilege` add constraint `fk_role_privilege_privid` foreign key (`privid`) references `tb_privilege` (`privid`);
|
||||
|
||||
alter table `tb_role_privilege` add constraint `fk_role_privilege_roleid` foreign key (`roleid`) references `tb_role` (`roleid`);
|
||||
|
||||
alter table `tb_user_role` add constraint `fk_user_role_roleid` foreign key (`roleid`) references `tb_role` (`roleid`);
|
||||
|
||||
alter table `tb_user_role` add constraint `fk_user_role_userid` foreign key (`userid`) references `tb_user` (`userid`);
|
|
@ -10,8 +10,6 @@
|
|||
<dict>
|
||||
<key>connection</key>
|
||||
<dict>
|
||||
<key>database</key>
|
||||
<string>school</string>
|
||||
<key>host</key>
|
||||
<string>120.77.222.217</string>
|
||||
<key>kcid</key>
|
||||
|
@ -47,22 +45,17 @@
|
|||
<integer>1</integer>
|
||||
<key>contentSelection</key>
|
||||
<data>
|
||||
YnBsaXN0MDDUAQIDBAUGOTpYJHZlcnNpb25YJG9iamVjdHNZJGFy
|
||||
Y2hpdmVyVCR0b3ASAAGGoK0HCBUWFxgZHSQoLDE2VSRudWxs0wkK
|
||||
CwwQFFdOUy5rZXlzWk5TLm9iamVjdHNWJGNsYXNzow0OD4ACgAOA
|
||||
BKMREhOABYAGgAiADFR0eXBlVHJvd3NUa2V5c18QJlNlbGVjdGlv
|
||||
bkRldGFpbFR5cGVQcmltYXJ5S2V5ZWREZXRhaWxz0wkKCxobHKCg
|
||||
gAfSHh8gIVokY2xhc3NuYW1lWCRjbGFzc2VzXxATTlNNdXRhYmxl
|
||||
RGljdGlvbmFyeaMgIiNcTlNEaWN0aW9uYXJ5WE5TT2JqZWN00goL
|
||||
JSehJoAJgAvSCykqK1lOUy5zdHJpbmeAClRzY2lk0h4fLS5fEA9O
|
||||
U011dGFibGVTdHJpbmejLS8wWE5TU3RyaW5nWE5TT2JqZWN00h4f
|
||||
MjNeTlNNdXRhYmxlQXJyYXmjMjQ1V05TQXJyYXlYTlNPYmplY3TS
|
||||
Hh8iN6IiOFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctE7PFRk
|
||||
YXRhgAEACAARABoAIwAtADIANwBFAEsAUgBaAGUAbABwAHIAdAB2
|
||||
AHoAfAB+AIAAggCHAIwAkQC6AMEAwgDDAMUAygDVAN4A9AD4AQUB
|
||||
DgETARUBFwEZAR4BKAEqAS8BNAFGAUoBUwFcAWEBcAF0AXwBhQGK
|
||||
AY0BlgGoAasBsAAAAAAAAAIBAAAAAAAAAD0AAAAAAAAAAAAAAAAA
|
||||
AAGy
|
||||
YnBsaXN0MDDUAQIDBAUGJSZYJHZlcnNpb25YJG9iamVjdHNZJGFy
|
||||
Y2hpdmVyVCR0b3ASAAGGoKgHCBMUFRYaIVUkbnVsbNMJCgsMDxJX
|
||||
TlMua2V5c1pOUy5vYmplY3RzViRjbGFzc6INDoACgAOiEBGABIAF
|
||||
gAdUdHlwZVRyb3dzXxAdU2VsZWN0aW9uRGV0YWlsVHlwZU5TSW5k
|
||||
ZXhTZXTSFwsYGVxOU1JhbmdlQ291bnQQAIAG0hscHR5aJGNsYXNz
|
||||
bmFtZVgkY2xhc3Nlc1pOU0luZGV4U2V0oh8gWk5TSW5kZXhTZXRY
|
||||
TlNPYmplY3TSGxwiI1xOU0RpY3Rpb25hcnmiIiRYTlNPYmplY3Rf
|
||||
EA9OU0tleWVkQXJjaGl2ZXLRJyhUZGF0YYABAAgAEQAaACMALQAy
|
||||
ADcAQABGAE0AVQBgAGcAagBsAG4AcQBzAHUAdwB8AIEAoQCmALMA
|
||||
tQC3ALwAxwDQANsA3gDpAPIA9wEEAQcBEAEiASUBKgAAAAAAAAIB
|
||||
AAAAAAAAACkAAAAAAAAAAAAAAAAAAAEs
|
||||
</data>
|
||||
<key>contentSortColIsAsc</key>
|
||||
<true/>
|
||||
|
@ -289,7 +282,7 @@ select stuname as 姓名, year(now())-year(stubirth) as 年龄 from tb_student w
|
|||
);
|
||||
|
||||
-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
|
||||
select stuname from tb_student where stuid=(
|
||||
explain select stuname from tb_student where stuid in (
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)
|
||||
|
||||
|
@ -314,8 +307,6 @@ select stuname, avgmark from tb_student t1 inner join
|
|||
-- 查询每个学生的姓名和选课数量(左外连接和子查询)
|
||||
select stuname, ifnull(total, 0) from tb_student t1 left outer join (select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid;
|
||||
</string>
|
||||
<key>table</key>
|
||||
<string>tb_score</string>
|
||||
<key>view</key>
|
||||
<string>SP_VIEW_CUSTOMQUERY</string>
|
||||
<key>windowVerticalDividerPosition</key>
|
||||
|
@ -330,6 +321,137 @@ select stuname, ifnull(total, 0) from tb_student t1 left outer join (select stui
|
|||
<array/>
|
||||
<key>queryHistory</key>
|
||||
<array>
|
||||
<string>-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
|
||||
explain select stuname from tb_student where stuid=any(
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)</string>
|
||||
<string>explain select stuname from tb_student where stuid in (
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)</string>
|
||||
<string>select stuname from tb_student where stuid in (
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)</string>
|
||||
<string>select stuname from tb_student where stuid=(
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)</string>
|
||||
<string>-- 如果存在名为school的数据库就删除它
|
||||
drop database if exists school;
|
||||
-- 创建名为school的数据库并设置默认的字符集和排序方式
|
||||
create database school default charset utf8 collate utf8_bin;
|
||||
-- 切换到school数据库上下文环境
|
||||
use school;
|
||||
-- 创建学院表
|
||||
create table tb_college
|
||||
(
|
||||
collid int not null auto_increment comment '编号',
|
||||
collname varchar(50) not null comment '名称',
|
||||
collmaster varchar(20) not null comment '院长',
|
||||
collweb varchar(511) default '' comment '网站',
|
||||
primary key (collid)
|
||||
);
|
||||
-- 创建学生表
|
||||
create table tb_student
|
||||
(
|
||||
stuid int not null comment '学号',
|
||||
stuname varchar(20) not null comment '姓名',
|
||||
stusex bit default 1 comment '性别',
|
||||
stubirth date not null comment '出生日期',
|
||||
stuaddr varchar(255) default '' comment '籍贯',
|
||||
collid int not null comment '所属学院',
|
||||
primary key (stuid),
|
||||
foreign key (collid) references tb_college (collid)
|
||||
);
|
||||
-- alter table tb_student add constraint fk_student_collid foreign key (collid) references tb_college (collid);
|
||||
|
||||
-- 创建教师表
|
||||
create table tb_teacher
|
||||
(
|
||||
teaid int not null comment '工号',
|
||||
teaname varchar(20) not null comment '姓名',
|
||||
teatitle varchar(10) default '助教' comment '职称',
|
||||
collid int not null comment '所属学院',
|
||||
primary key (teaid),
|
||||
foreign key (collid) references tb_college (collid)
|
||||
);
|
||||
-- 创建课程表
|
||||
create table tb_course
|
||||
(
|
||||
couid int not null comment '编号',
|
||||
couname varchar(50) not null comment '名称',
|
||||
coucredit int not null comment '学分',
|
||||
teaid int not null comment '授课老师',
|
||||
primary key (couid),
|
||||
foreign key (teaid) references tb_teacher (teaid)
|
||||
);
|
||||
-- 创建选课记录表
|
||||
create table tb_score
|
||||
(
|
||||
scid int auto_increment comment '选课记录编号',
|
||||
stuid int not null comment '选课学生',
|
||||
couid int not null comment '所选课程',
|
||||
scdate datetime comment '选课时间日期',
|
||||
scmark decimal(4,1) comment '考试成绩',
|
||||
primary key (scid),
|
||||
foreign key (stuid) references tb_student (stuid),
|
||||
foreign key (couid) references tb_course (couid)
|
||||
);
|
||||
-- 添加唯一性约束(一个学生选某个课程只能选一次)
|
||||
alter table tb_score add constraint uni_score_stuid_couid unique (stuid, couid);
|
||||
-- 插入学院数据
|
||||
insert into tb_college (collname, collmaster, collweb) values
|
||||
('计算机学院', '左冷禅', 'http://www.abc.com'),
|
||||
('外国语学院', '岳不群', 'http://www.xyz.com'),
|
||||
('经济管理学院', '风清扬', 'http://www.foo.com');
|
||||
-- 插入学生数据
|
||||
insert into tb_student (stuid, stuname, stusex, stubirth, stuaddr, collid) values
|
||||
(1001, '杨逍', 1, '1990-3-4', '四川成都', 1),
|
||||
(1002, '任我行', 1, '1992-2-2', '湖南长沙', 1),
|
||||
(1033, '王语嫣', 0, '1989-12-3', '四川成都', 1),
|
||||
(1572, '岳不群', 1, '1993-7-19', '陕西咸阳', 1),
|
||||
(1378, '纪嫣然', 0, '1995-8-12', '四川绵阳', 1),
|
||||
(1954, '林平之', 1, '1994-9-20', '福建莆田', 1),
|
||||
(2035, '东方不败', 1, '1988-6-30', null, 2),
|
||||
(3011, '林震南', 1, '1985-12-12', '福建莆田', 3),
|
||||
(3755, '项少龙', 1, '1993-1-25', null, 3),
|
||||
(3923, '杨不悔', 0, '1985-4-17', '四川成都', 3);
|
||||
-- 插入老师数据
|
||||
insert into tb_teacher (teaid, teaname, teatitle, collid) values
|
||||
(1122, '张三丰', '教授', 1),
|
||||
(1133, '宋远桥', '副教授', 1),
|
||||
(1144, '杨逍', '副教授', 1),
|
||||
(2255, '范遥', '副教授', 2),
|
||||
(3366, '韦一笑', '讲师', 3);
|
||||
-- 插入课程数据
|
||||
insert into tb_course (couid, couname, coucredit, teaid) values
|
||||
(1111, 'Python程序设计', 3, 1122),
|
||||
(2222, 'Web前端开发', 2, 1122),
|
||||
(3333, '操作系统', 4, 1122),
|
||||
(4444, '计算机网络', 2, 1133),
|
||||
(5555, '编译原理', 4, 1144),
|
||||
(6666, '算法和数据结构', 3, 1144),
|
||||
(7777, '经贸法语', 3, 2255),
|
||||
(8888, '成本会计', 2, 3366),
|
||||
(9999, '审计学', 3, 3366);
|
||||
-- 插入选课数据
|
||||
insert into tb_score (stuid, couid, scdate, scmark) values
|
||||
(1001, 1111, '2017-09-01', 95),
|
||||
(1001, 2222, '2017-09-01', 87.5),
|
||||
(1001, 3333, '2017-09-01', 100),
|
||||
(1001, 4444, '2018-09-03', null),
|
||||
(1001, 6666, '2017-09-02', 100),
|
||||
(1002, 1111, '2017-09-03', 65),
|
||||
(1002, 5555, '2017-09-01', 42),
|
||||
(1033, 1111, '2017-09-03', 92.5),
|
||||
(1033, 4444, '2017-09-01', 78),
|
||||
(1033, 5555, '2017-09-01', 82.5),
|
||||
(1572, 1111, '2017-09-02', 78),
|
||||
(1378, 1111, '2017-09-05', 82),
|
||||
(1378, 7777, '2017-09-02', 65.5),
|
||||
(2035, 7777, '2018-09-03', 88),
|
||||
(2035, 9999, curdate(), null),
|
||||
(3755, 1111, date(now()), null),
|
||||
(3755, 8888, date(now()), null),
|
||||
(3755, 9999, '2017-09-01', 92)</string>
|
||||
<string>select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.stuid=t3.stuid inner join tb_course t2 on t2.couid=t3.couid where scmark is not null order by scmark desc limit 5 offset 10</string>
|
||||
<string>select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.stuid=t3.stuid inner join tb_course t2 on t2.couid=t3.couid where scmark is not null order by scmark desc limit 10, 5</string>
|
||||
<string>select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.stuid=t3.stuid inner join tb_course t2 on t2.couid=t3.couid where scmark is not null order by scmark desc limit 5, 5</string>
|
||||
|
@ -347,29 +469,11 @@ select stuname, couname, scmark from tb_student t1, tb_course t2, tb_score t3 wh
|
|||
<string>select stuname, avgmark from tb_student t1, (select stuid, avg(scmark) as avgmark from tb_score group by stuid) t2 where t1.stuid=t2.stuid</string>
|
||||
<string>select stuname, ifnull(total, 0) from tb_student t1 left outer join (select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid</string>
|
||||
<string>select stuname, ifnull(total,0) from tb_student t1 left outer join (select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid</string>
|
||||
<string>-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
|
||||
select stuname from tb_student where stuid=(
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)
|
||||
|
||||
-- 查询学生姓名、课程名称以及成绩(连接查询)
|
||||
|
||||
-- 查询选课学生的姓名和平均成绩(子查询和连接查询)
|
||||
|
||||
-- 外连接(outer join):左外连接 / 右外连接 / 全外连接
|
||||
-- 查询每个学生的姓名和选课数量(左外连接和子查询)
|
||||
select stuname, ifnull(total, 0) from tb_student t1 left outer join (select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid</string>
|
||||
<string>select stuname, total from tb_student t1 left outer join
|
||||
(select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid</string>
|
||||
<string>select stuname, total from tb_student t1 inner join
|
||||
(select stuid, count(stuid) as total from tb_score group by stuid) t2 on t1.stuid=t2.stuid</string>
|
||||
<string>select stuid, count(stuid) from tb_score group by stuid</string>
|
||||
<string>select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.stuid=t3.stuid inner join tb_course t2 on t2.couid=t3.couid</string>
|
||||
</array>
|
||||
<key>rdbms_type</key>
|
||||
<string>mysql</string>
|
||||
<key>rdbms_version</key>
|
||||
<string>5.5.60-MariaDB</string>
|
||||
<string>5.7.26</string>
|
||||
<key>version</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
|
|
|
@ -69,61 +69,53 @@
|
|||
|
||||
- 启动MySQL服务。
|
||||
|
||||
先修改MySQL的配置文件(`/etc/my.cnf`)添加一行`skip-grant-tables`,可以设置不进行身份验证即可连接MySQL服务器,然后就可以以超级管理员(root)身份登录。
|
||||
|
||||
```Shell
|
||||
vim /etc/my.cnf
|
||||
```
|
||||
|
||||
```INI
|
||||
[mysqld]
|
||||
skip-grant-tables
|
||||
|
||||
datadir=/var/lib/mysql
|
||||
socket=/var/lib/mysql/mysql.sock
|
||||
|
||||
symbolic-links=0
|
||||
|
||||
log-error=/var/log/mysqld.log
|
||||
pid-file=/var/run/mysqld/mysqld.pid
|
||||
```
|
||||
|
||||
接下来可以使用下面的命令来启动MySQL。
|
||||
可以使用下面的命令来启动MySQL。
|
||||
|
||||
```Shell
|
||||
service mysqld start
|
||||
```
|
||||
|
||||
在CentOS 7中建议使用下面的命令来启动MySQL。
|
||||
在CentOS 7中,更推荐使用下面的命令来启动MySQL。
|
||||
|
||||
```Shell
|
||||
systemctl start mysqld
|
||||
```
|
||||
|
||||
启动MySQL成功后,可以通过下面的命令来检查网络端口使用情况,MySQL默认使用3306端口。
|
||||
|
||||
```Shell
|
||||
netstat -nap | grep mysql
|
||||
```
|
||||
|
||||
- 使用MySQL客户端工具连接服务器。
|
||||
|
||||
命令行工具:
|
||||
|
||||
```Shell
|
||||
mysql -u root
|
||||
```
|
||||
|
||||
修改超级管理员(root)的访问口令为i_LOVE_macos_123。
|
||||
|
||||
```SQL
|
||||
use mysql;
|
||||
update user set authentication_string=password('i_LOVE_macos_123') where user='root';
|
||||
flush privileges;
|
||||
```
|
||||
|
||||
将MySQL配置文件中的`skip-grant-tables`去掉,然后重启服务器,重新登录。这一次需要提供用户名和口令才能连接MySQL服务器。
|
||||
|
||||
```Shell
|
||||
systemctl restart mysqld
|
||||
mysql -u root -p
|
||||
```
|
||||
|
||||
也可以选择图形化的客户端工具来连接MySQL服务器,可以选择下列工具之一:
|
||||
> 说明:启动客户端时,`-u`参数用来指定用户名,MySQL默认的超级管理账号为`root`;`-p`表示要输入密码(用户口令);如果连接的是其他主机而非本机,可以用`-h`来指定连接主机的主机名或IP地址。
|
||||
|
||||
如果是首次安装MySQL,可以使用下面的命令来找到默认的初始密码。
|
||||
|
||||
```Shell
|
||||
cat /var/log/mysqld.log | grep password
|
||||
```
|
||||
|
||||
上面的命令会查看MySQL的日志带有password的行,在显示的结果中`root@localhost:`后面的部分就是默认设置的初始密码。
|
||||
|
||||
修改超级管理员(root)的访问口令为`123456`。
|
||||
|
||||
```SQL
|
||||
set global validate_password_policy=0;
|
||||
set global validate_password_length=6;
|
||||
alter user 'root'@'localhost' identified by '123456';
|
||||
```
|
||||
|
||||
> 说明:MySQL默认不允许使用弱口令作为用户口令,所以我们通过上面的前两条命令修改了验证用户口令的策略和口令的长度。事实上我们不应该使用弱口令,因为存在用户口令被暴力破解的风险。近年来,攻击数据库窃取数据和劫持数据库勒索比特币的事件屡见不鲜,要避免这些潜在的风险,最为重要的一点是不要让数据库服务器暴露在公网上(最好的做法是将数据库置于内网,至少要做到不向公网开放数据库服务器的访问端口),另外要保管好`root`账号的口令,应用系统需要访问数据库时,通常不使用`root`账号进行访问,而是创建其他拥有适当权限的账号来访问。
|
||||
|
||||
再次使用客户端工具连接MySQL服务器时,就可以使用新设置的口令了。在实际开发中,为了方便用户操作,可以选择图形化的客户端工具来连接MySQL服务器,包括:
|
||||
|
||||
- MySQL Workbench(官方提供的工具)
|
||||
- Navicat for MySQL(界面简单优雅,功能直观强大)
|
||||
|
@ -401,7 +393,7 @@
|
|||
);
|
||||
|
||||
-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
|
||||
select stuname from tb_student where stuid=(
|
||||
select stuname from tb_student where stuid in (
|
||||
select stuid from tb_score group by stuid having count(stuid)>2
|
||||
)
|
||||
|
||||
|
@ -696,4 +688,4 @@ insert into tb_emp values
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
```
|
||||
|
|
|
@ -122,7 +122,7 @@ def show_subjects(request):
|
|||
<style>/* 此处略去了层叠样式表的选择器 */</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>所有学科</h1>
|
||||
<h1>千锋互联所有学科信息</h1>
|
||||
<hr>
|
||||
<div id="container">
|
||||
{% for subject in subjects %}
|
||||
|
@ -167,7 +167,7 @@ def show_teachers(request):
|
|||
<style>/* 此处略去了层叠样式表的选择器 */</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ subject.name }}的老师信息</h1>
|
||||
<h1>{{ subject.name }}学科老师信息</h1>
|
||||
<hr>
|
||||
{% if teachers %}
|
||||
<div id="container">
|
||||
|
@ -231,7 +231,7 @@ urlpatterns = [
|
|||
|
||||
启动服务器运行项目,进入首页查看学科信息。
|
||||
|
||||
![](/Users/Hao/Desktop/Python-100-Days/Day41-55/res/show-subjects.png)
|
||||
![](./res/show-subjects.png)
|
||||
|
||||
点击学科查看老师信息。
|
||||
|
||||
|
@ -301,4 +301,4 @@ def praise_or_criticize(request):
|
|||
|
||||
### 小结
|
||||
|
||||
到此为止,这个投票项目的核心功能已然完成,在下一个章节中我们要求用户必须登录才能投票,没有账号的用户可以通过注册功能注册一个账号。
|
||||
到此为止,这个投票项目的核心功能已然完成,在下面的章节中我们会要求用户必须登录才能投票,没有账号的用户可以通过注册功能注册一个账号。
|
|
@ -62,7 +62,9 @@ python manage.py migrate
|
|||
</html>
|
||||
```
|
||||
|
||||
注意,在上面的表单中,我们使用了模板指令`{% csrf_token %}`,它的作用是在表单中生成一个随机令牌(token)来防范[跨站请求伪造](<https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0>)(通常简称为CSRF),这也是Django在提交表单时的硬性要求,除非我们专门设置了免除CSRF令牌。
|
||||
注意,在上面的表单中,我们使用了模板指令`{% csrf_token %}`为表单添加一个隐藏域(type属性值为hidden的input标签),它的作用是在表单中生成一个随机令牌(token)来防范[跨站请求伪造](<https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0>)(通常简称为CSRF),这也是Django在提交表单时的硬性要求,除非我们专门设置了免除CSRF令牌。下图是一个关于CSRF简单生动的例子,它来自于[维基百科](<https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5>)。
|
||||
|
||||
![](./res/CSRF.png)
|
||||
|
||||
用户在提交注册表单时,我们还需要对用户的输入进行验证,例如我们的网站要求用户名必须由字母、数字、下划线构成且长度在4-20个字符之间,密码的长度为8-20个字符,确认密码必须跟密码保持一致。这些验证操作首先可以通过浏览器中的JavaScript代码来完成,但是即便如此,在服务器端仍然要对用户输入再次进行验证来避免将无效的数据库交给数据库,因为用户可能会禁用浏览器的JavaScript功能,也有可能绕过浏览器的输入检查将注册数据提交给服务器,所以服务器端的用户输入检查仍然是必要的。
|
||||
|
||||
|
@ -97,7 +99,7 @@ class RegisterForm(forms.ModelForm):
|
|||
exclude = ('no', 'regdate')
|
||||
```
|
||||
|
||||
上面,我们定义了一个与User模型绑定的表单(继承自ModelForm),我们排除了用户编号(no)和注册日期(regdate)这两个属性,并添加了一个repassword属性用来接收从用户表单传给服务器的确认密码。我们在定义User模型时已经对用户名的最大长度进行了限制,上面我们又对确认密码的最小和最大长度进行了限制,但是这些都不足以完成我们对用户输入的验证。上面以`clean_`打头的方法就是我们自定义的验证规则。很明显,`clean_username`是对用户名的检查,而`clean_password`是对密码的检查。由于数据库二维表中不应该保存密码的原文,所以对密码做了一个简单的MD5摘要处理(实际开发中这样处理还不太够,因为有被实施反向查表法(利用彩虹表反向查询)破解用户密码的风险)。生成MD5摘要的代码如下所示。
|
||||
上面,我们定义了一个与User模型绑定的表单(继承自ModelForm),我们排除了用户编号(no)和注册日期(regdate)这两个属性,并添加了一个repassword属性用来接收从用户表单传给服务器的确认密码。我们在定义User模型时已经对用户名的最大长度进行了限制,上面我们又对确认密码的最小和最大长度进行了限制,但是这些都不足以完成我们对用户输入的验证。上面以`clean_`打头的方法就是我们自定义的验证规则。很明显,`clean_username`是对用户名的检查,而`clean_password`是对密码的检查。由于数据库二维表中不应该保存密码的原文,所以对密码做了一个简单的MD5摘要处理,实际开发中这样处理还不太够,因为有被实施反向查表法(利用彩虹表反向查询)破解用户密码的风险。为字符串生成MD5摘要的代码如下所示。
|
||||
|
||||
```Python
|
||||
def to_md5_hex(message):
|
||||
|
@ -381,6 +383,8 @@ def random_color(start=0, end=255, opacity=255):
|
|||
return red, green, blue, opacity
|
||||
```
|
||||
|
||||
> 说明:上面的代码在生成验证码图片时用到了三种字体文件,使用上面的代码时需要添加字体文件到应用目录下的fonts目录中。
|
||||
|
||||
下面的视图函数用来生成验证码并通过HttpResponse对象输出到用户浏览器中。
|
||||
|
||||
```Python
|
||||
|
|
|
@ -1,3 +1,185 @@
|
|||
## Cookie和Session
|
||||
|
||||
### 实现用户跟踪
|
||||
|
||||
如今,一个网站如果不通过某种方式记住你是谁以及你之前在网站的活动情况,失去的就是网站的可用性和便利性,继而很有可能导致网站用户的流式,所以记住一个用户(更专业的说法叫**用户跟踪**)对绝大多数Web应用来说都是必需的功能。
|
||||
|
||||
在服务器端,我们想记住一个用户最简单的办法就是创建一个对象,通过这个对象就可以把用户相关的信息都保存起来,这个对象就是我们常说的session(用户会话对象)。那么问题来了,HTTP本身是一个无连接(每次请求和响应的过程中,服务器一旦完成对客户端请求的响应之后就断开连接)、无状态(客户端再次发起对服务器的请求时,服务器无法得知这个客户端之前的任何信息)的协议,即便服务器通过session对象保留了用户数据,还得通过某种方式来确定当前的请求与之前保存过的哪一个session是有关联的。相信很多人都能想到,我们可以给每个session对象分配一个全局唯一的标识符来识别session对象,我们姑且称之为sessionid,每次客户端发起请求时,只要携带上这个sessionid,就有办法找到与之对应的session对象,从而实现在两次请求之间记住该用户的信息,也就是我们之前说的用户跟踪。
|
||||
|
||||
要让客户端记住并在每次请求时带上sessionid又有以下几种做法:
|
||||
|
||||
1. URL重写。所谓URL重写就是在URL中携带sessionid,例如:`http://www.example.com/index.html?sessionid=123456`,服务器通过获取sessionid参数的值来取到与之对应的session对象。
|
||||
|
||||
2. 隐藏域(隐式表单域)。在提交表单的时候,可以通过在表单中设置隐藏域向服务器发送额外的数据。例如:`<input type="hidden" name="sessionid" value="123456">`。
|
||||
|
||||
3. Cookie。Cookie是保存在浏览器临时文件中的数据,每次请求时,请求头中会携带本站点的cookie到服务器,那么只要将sessionid写入cookie,下次请求时服务器只要读取请求头中的cookie就能够获得这个sessionid,如下图所示:
|
||||
|
||||
![](./res/sessionid_from_cookie.png)
|
||||
|
||||
需要说明的是,在HTML5时代要想在浏览器中保存数据,除了使用cookie之外,还可以使用新的本地存储API,包括localStorage、sessionStorage、IndexedDB等,如下图所示。
|
||||
|
||||
![](./res/cookie_xstorage_indexeddb.png)
|
||||
|
||||
### Django框架对session的支持
|
||||
|
||||
在创建Django项目时,默认的配置文件`settings.py`文件中已经激活了一个名为`SessionMiddleware`的中间件(关于中间件的知识我们在下一个章节做详细的讲解,这里只需要知道它的存在即可),因为这个中间件的存在,我们可以直接通过请求对象的`session`属性来操作会话对象。`session`属性是一个像字典一样可以读写数据的容器对象,因此我们可以使用“键值对”的方式来保留用户数据。与此同时,`SessionMiddleware`中间件还封装了对cookie的操作,在cookie中保存了sessionid,就如同我们之前描述的那样。
|
||||
|
||||
在默认情况下,Django将session的数据序列化后保存在关系型数据库中,在Django 1.6以后的版本中,默认的序列化数据的方式是JSON序列化,而在此之前一直使用Pickle序列化。JSON序列化和Pickle序列化的差别在于前者将对象序列化为字符串(字符形式),而后者将对象序列化为字节串(二进制形式),因为安全方面的原因,JSON序列化成为了目前Django框架默认序列化数据的方式,这就要求在我们保存在session中的数据必须是能够JSON序列化的,否则就会引发异常。还有一点需要说明的是,使用关系型数据库保存session中的数据在大多数时候并不是最好的选择,因为数据库可能会承受巨大的压力而成为系统性能的瓶颈,在后面的章节中我们会告诉大家如何将session的数据保存到缓存服务中。
|
||||
|
||||
我们继续完善之前的投票应用,前一个章节中我们实现了用户的登录和注册,下面我们首先完善登录时对验证码的检查。
|
||||
|
||||
```Python
|
||||
def get_captcha(request):
|
||||
"""验证码"""
|
||||
captcha_text = random_captcha_text()
|
||||
request.session['captcha'] = captcha_text
|
||||
image_data = Captcha.instance().generate(captcha_text)
|
||||
return HttpResponse(image_data, content_type='image/png')
|
||||
```
|
||||
|
||||
注意上面代码中的第4行,我们将随机生成的验证码字符串保存到session中,稍后用户登录时,我们要将保存在session中的验证码字符串和用户输入的验证码字符串进行比对,如果用户输入了正确的验证码才能够执行后续的登录流程,代码如下所示。
|
||||
|
||||
```Python
|
||||
def login(request: HttpRequest):
|
||||
"""登录"""
|
||||
hint = ''
|
||||
if request.method == 'POST':
|
||||
form = LoginForm(request.POST)
|
||||
if form.is_valid():
|
||||
# 对验证码的正确性进行验证
|
||||
captcha_from_user = form.cleaned_data['captcha']
|
||||
captcha_from_sess = request.session.get('captcha', '')
|
||||
if captcha_from_sess.lower() != captcha_from_user.lower():
|
||||
hint = '请输入正确的验证码'
|
||||
else:
|
||||
username = form.cleaned_data['username']
|
||||
password = form.cleaned_data['password']
|
||||
user = User.objects.filter(username=username, password=password).first()
|
||||
if user:
|
||||
# 登录成功后将用户编号和用户名保存在session中
|
||||
request.session['no'] = user.no
|
||||
request.session['username'] = user.username
|
||||
return redirect('/')
|
||||
else:
|
||||
hint = '用户名或密码错误'
|
||||
else:
|
||||
hint = '请输入有效的登录信息'
|
||||
return render(request, 'login.html', {'hint': hint})
|
||||
```
|
||||
|
||||
上面的代码中,我们设定了登录成功后会在session中保存用户的编号(`no`)和用户名(`username`),页面会重定向到首页。接下来我们可以稍微对首页的代码进行调整,在页面的右上角显示出登录用户的用户名。我们将这段代码单独写成了一个名为header.html的HTML文件,首页中可以通过在`<body>`标签中添加`{% include 'header.html' %}`来包含这个页面,代码如下所示。
|
||||
|
||||
```HTML
|
||||
<div class="user">
|
||||
{% if request.session.no %}
|
||||
<span>{{ request.session.username }}</span>
|
||||
<a href="/vote/logout">注销</a>
|
||||
{% else %}
|
||||
<a href="/vote/login">登录</a>
|
||||
{% endif %}
|
||||
<a href="/vote/register">注册</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
如果用户没有登录,页面会显示登录和注册的超链接;而用户登录成功后,页面上会显示用户名和注销的链接,注销链接对应的视图函数如下所示。
|
||||
|
||||
```Python
|
||||
def logout(request):
|
||||
"""注销"""
|
||||
request.session.flush()
|
||||
return redirect('/')
|
||||
```
|
||||
|
||||
上面的代码通过session对象`flush`方法来销毁session,一方面清除了服务器上session对象保存的用户数据,一方面将保存在浏览器cookie中的sessionid删除掉,稍后我们会对如何读写cookie的操作加以说明。
|
||||
|
||||
我们可以通过项目使用的数据库中名为`django_session` 的表来找到所有的session,该表的结构如下所示:
|
||||
|
||||
| session_key | session_data | expire_date |
|
||||
| -------------------------------- | ------------------------------- | -------------------------- |
|
||||
| c9g2gt5cxo0k2evykgpejhic5ae7bfpl | MmI4YzViYjJhOGMyMDJkY2M5Yzg3... | 2019-05-25 23:16:13.898522 |
|
||||
|
||||
其中,第1列就是浏览器cookie中保存的sessionid;第2列是经过BASE64编码后的session中的数据,如果使用Python的`base64`对其进行解码,解码的过程和结果如下所示。
|
||||
|
||||
```Python
|
||||
>>> import base64
|
||||
>>> base64.b64decode('MmI4YzViYjJhOGMyMDJkY2M5Yzg3ZWIyZGViZmUzYmYxNzdlNDdmZjp7ImNhcHRjaGEiOiJzS3d0Iiwibm8iOjEsInVzZXJuYW1lIjoiamFja2ZydWVkIn0=')
|
||||
'2b8c5bb2a8c202dcc9c87eb2debfe3bf177e47ff:{"captcha":"sKwt","no":1,"username":"jackfrued"}'
|
||||
```
|
||||
|
||||
第3列是session的过期时间,session过期后浏览器保存的cookie中的sessionid就会失效,但是数据库中的这条对应的记录仍然会存在,如果想清除过期的数据,可以使用下面的命令。
|
||||
|
||||
```Shell
|
||||
python manage.py clearsessions
|
||||
```
|
||||
|
||||
Django框架默认的session过期时间为两周(1209600秒),如果想修改这个时间,可以在项目的配置文件中添加如下所示的代码。
|
||||
|
||||
```Python
|
||||
# 配置会话的超时时间为1天(86400秒)
|
||||
SESSION_COOKIE_AGE = 86400
|
||||
```
|
||||
|
||||
有很多对安全性要求较高的应用都必须在关闭浏览器窗口时让会话过期,不再保留用户的任何信息,如果希望在关闭浏览器窗口时就让会话过期(cookie中的sessionid失效),可以加入如下所示的配置。
|
||||
|
||||
```Python
|
||||
# 设置为True在关闭浏览器窗口时session就过期
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
||||
```
|
||||
|
||||
如果不希望将session的数据保存在数据库中,可以将其放入缓存中,对应的配置如下所示,缓存的配置和使用我们在后面讲解。
|
||||
|
||||
```Python
|
||||
# 配置将会话对象放到缓存中存储
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
||||
# 配置使用哪一组缓存来保存会话
|
||||
SESSION_CACHE_ALIAS = 'default'
|
||||
```
|
||||
|
||||
如果要修改session数据默认的序列化方式,可以将默认的`JSONSerializer`修改为`PickleSerializer`。
|
||||
|
||||
```Python
|
||||
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
||||
```
|
||||
|
||||
### 在视图函数中读写cookie
|
||||
|
||||
Django封装的`HttpRequest`和`HttpResponse`对象分别提供了读写cookie的操作。
|
||||
|
||||
HttpRequest封装的属性和方法:
|
||||
|
||||
1. `COOKIES`属性 - 该属性包含了HTTP请求携带的所有cookie。
|
||||
2. `get_signed_cookie`方法 - 获取带签名的cookie,如果签名验证失败,会产生`BadSignature`异常。
|
||||
|
||||
HttpResponse封装的方法:
|
||||
|
||||
1. `set_cookie`方法 - 该方法可以设置一组键值对并将其最终将写入浏览器。
|
||||
2. `set_signed_cookie`方法 - 跟上面的方法作用相似,但是会对cookie进行签名来达到防篡改的作用。因为如果篡改了cookie中的数据,在不知道[密钥](<https://zh.wikipedia.org/wiki/%E5%AF%86%E9%92%A5>)和[盐](<https://zh.wikipedia.org/wiki/%E7%9B%90_(%E5%AF%86%E7%A0%81%E5%AD%A6)>)的情况下是无法生成有效的签名,这样服务器在读取cookie时会发现数据与签名不一致从而产生`BadSignature`异常。需要说明的是,这里所说的密钥就是我们在Django项目配置文件中指定的`SECRET_KEY`,而盐是程序中设定的一个字符串,你愿意设定为什么都可以,只要是一个有效的字符串。
|
||||
|
||||
上面提到的方法,如果不清楚它们的具体用法,可以自己查阅一下Django的[官方文档](<https://docs.djangoproject.com/en/2.1/ref/request-response/>),没有什么资料比官方文档能够更清楚的告诉你这些方法到底如何使用。
|
||||
|
||||
刚才我们说过了,激活`SessionMiddleware`之后,每个`HttpRequest`对象都会绑定一个session属性,它是一个类似字典的对象,除了保存用户数据之外还提供了检测浏览器是否支持cookie的方法,包括:
|
||||
|
||||
1. `set_test_cookie`方法 - 设置用于测试的cookie。
|
||||
2. `test_cookie_worked`方法 - 检测测试cookie是否工作。
|
||||
3. `delete_test_cookie`方法 - 删除用于测试的cookie。
|
||||
4. `set_expiry`方法 - 设置会话的过期时间。
|
||||
5. `get_expire_age`/`get_expire_date`方法 - 获取会话的过期时间。
|
||||
6. `clear_expired`方法 - 清理过期的会话。
|
||||
|
||||
下面是在执行登录之前检查浏览器是否支持cookie的代码。
|
||||
|
||||
```Python
|
||||
def login(request):
|
||||
if request.method == 'POST':
|
||||
if request.session.test_cookie_worked():
|
||||
request.session.delete_test_cookie()
|
||||
# Add your code to perform login process here
|
||||
else:
|
||||
return HttpResponse("Please enable cookies and try again.")
|
||||
request.session.set_test_cookie()
|
||||
return render_to_response('login.html')
|
||||
```
|
||||
|
||||
### Cookie的替代品
|
||||
|
||||
之前我们说过了,cookie的名声一直都不怎么好,当然我们在实际开发中是不会在cookie中保存用户的敏感信息(如用户的密码、信用卡的账号等)的,而且保存在cookie中的数据一般也会做好编码和签名的工作。即便如此,HTML5中还是给出了用于替代cookie的技术方案,其中使用得最为广泛的就是localStorage和sessionStorage,相信从名字上你就能听出二者的差别,存储在`localStorage`的数据可以长期保留;而存储在`sessionStorage`的数据会在浏览器关闭时会被清除 。关于这些cookie替代品的用法,建议大家查阅[MDN](<https://developer.mozilla.org/zh-CN/docs/Web>)来进行了解。
|
|
@ -1,4 +1,135 @@
|
|||
## 中间件的应用
|
||||
|
||||
我们继续来完善投票应用。在上一个章节中,我们在用户登录成功后通过session保留了用户信息,接下来我们可以应用做一些调整,要求在为老师投票时必须要先登录,登录过的用户可以投票,否则就将用户引导到登录页面,为此我们可以这样修改视图函数。
|
||||
|
||||
```Python
|
||||
def praise_or_criticize(request: HttpRequest):
|
||||
"""投票"""
|
||||
if 'username' in request.session:
|
||||
try:
|
||||
tno = int(request.GET.get('tno', '0'))
|
||||
teacher = Teacher.objects.get(no=tno)
|
||||
if request.path.startswith('/vote/praise'):
|
||||
teacher.good_count += 1
|
||||
else:
|
||||
teacher.bad_count += 1
|
||||
teacher.save()
|
||||
data = {'code': 200, 'message': '操作成功'}
|
||||
except (ValueError, Teacher.DoesNotExist):
|
||||
data = {'code': 404, 'message': '操作失败'}
|
||||
else:
|
||||
data = {'code': 401, 'message': '请先登录'}
|
||||
return JsonResponse(data)
|
||||
```
|
||||
|
||||
前端页面在收到`{'code': 401, 'message': '请先登录'}`后,可以将用户引导到登录页面,修改后的teacher.html页面的JavaScript代码部门如下所示。
|
||||
|
||||
```HTML
|
||||
<script>
|
||||
$(() => {
|
||||
$('.comment > a').on('click', (evt) => {
|
||||
evt.preventDefault()
|
||||
let a = $(evt.target)
|
||||
$.ajax({
|
||||
url: a.attr('href'),
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: (json) => {
|
||||
if (json.code == 200) {
|
||||
let span = a.next()
|
||||
span.text(parseInt(span.text()) + 1)
|
||||
} else if (json.code == 401) {
|
||||
location.href = '/vote/login/?backurl=' + location.href
|
||||
} else {
|
||||
alert(json.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
> 注意:为了在登录成功之后能够回到刚才投票的页面,我们在跳转登录时设置了一个`backurl`参数,把当前浏览器中的URL作为返回的页面地址。
|
||||
|
||||
这样我们已经实现了用户必须登录才能投票的限制,但是一个新的问题来了。如果我们的应用中有很多功能都需要用户先登录才能执行,那么我们是不是需要在每个视图函数中添加代码来检查session中是否包含了登录用户的信息呢?答案是否定的,如果这样做了,我们的视图函数中必然会充斥着大量的重复代码。编程大师*Martin Fowler*曾经说过:**代码有很多种坏味道,重复是最坏的一种**。我们可以把验证用户是否登录这样的代码放到Django的中间件中。
|
||||
|
||||
### Django中间件概述
|
||||
|
||||
中间件是安插在Web应用请求和响应过程之间的组件,它在整个Web应用中扮演了拦截过滤器的角色,通过中间件可以拦截请求和响应,并对请求和响应进行过滤(简单的说就是执行额外的处理)。通常,一个中间件组件只专注于完成一件特定的事,例如:Django框架通过`SessionMiddleware`中间件实现了对session的支持,又通过`AuthenticationMiddleware`中间件实现了基于session的请求认证。通过把多个中间件组合在一起,我们可以完成更为复杂的任务,Django框架就是这么做的。
|
||||
|
||||
Django项目的配置文件中就包含了对中间件的配置,代码如下所示。
|
||||
|
||||
```Python
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
```
|
||||
|
||||
我们稍微为大家解释一下这些中间件的作用:
|
||||
|
||||
1. CommonMiddleware - 基础设置中间件,可以处理以下一些配置参数。
|
||||
- DISALLOWED_USER_AGENTS - 不被允许的用户代理(浏览器)
|
||||
- APPEND_SLASH - 是否追加`/`
|
||||
- USE_ETAG - 浏览器缓存相关
|
||||
2. SecurityMiddleware - 安全相关中间件,可以处理和安全相关的配置项。
|
||||
- SECURE_HSTS_SECONDS - 强制使用HTTPS的时间
|
||||
- SECURE_HSTS_INCLUDE_SUBDOMAINS - HTTPS是否覆盖子域名
|
||||
- SECURE_CONTENT_TYPE_NOSNIFF - 是否允许浏览器推断内容类型
|
||||
- SECURE_BROWSER_XSS_FILTER - 是否启用跨站脚本攻击过滤器
|
||||
- SECURE_SSL_REDIRECT - 是否重定向到HTTPS连接
|
||||
- SECURE_REDIRECT_EXEMPT - 免除重定向到HTTPS
|
||||
3. SessionMiddleware - 会话中间件。
|
||||
4. CsrfViewMiddleware - 通过生成令牌,防范跨请求份伪的造中间件。
|
||||
5. XFrameOptionsMiddleware - 通过设置请求头参数,防范点击劫持攻击的中间件。
|
||||
|
||||
在请求的过程中,上面的中间件会按照书写的顺序从上到下执行,然后是URL解析,最后请求才会来到视图函数;在响应的过程中,上面的中间件会按照书写的顺序从下到上执行,与请求时中间件执行的顺序正好相反。
|
||||
|
||||
### 自定义中间件
|
||||
|
||||
Django中的中间件有两种实现方式:基于类的实现方式和基于函数的实现方式,后者更接近于装饰器的写法。装饰器实际上是代理模式的应用,将横切关注功能(与正常业务逻辑没有必然联系的功能,例如:身份认证、日志记录、编码转换之类的功能)置于代理中,由代理对象来完成被代理对象的行为并添加额外的功能。中间件对用户请求和响应进行拦截过滤并增加额外的处理,在这一点上它跟装饰器是完全一致的,所以基于函数的写法来实现中间件就跟装饰器的写法几乎一模一样。下面我们用自定义的中间件来实现对用户进行登录验证的功能。
|
||||
|
||||
```Python
|
||||
"""
|
||||
middlewares.py
|
||||
"""
|
||||
from django.shortcuts import redirect
|
||||
|
||||
|
||||
def check_login_middleware(func):
|
||||
|
||||
def wrapper(request, *args, **kwargs):
|
||||
# 获取请求的资源路径
|
||||
path = request.path
|
||||
# 如果请求的资源路径在设定的元组中就表示需要登录验证
|
||||
if path in ('/vote/praise/', '/vote/criticize/'):
|
||||
if 'username' not in request.session:
|
||||
# session中没有username就重定向到登录页
|
||||
return redirect('login')
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
```
|
||||
|
||||
修改配置文件,激活中间件使其生效。
|
||||
|
||||
```Python
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'vote.middlewares.check_login_middleware',
|
||||
]
|
||||
```
|
||||
|
||||
|
|
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 246 KiB |
|
@ -1,2 +1,25 @@
|
|||
## Pandas的应用
|
||||
|
||||
### 1、pandas入门
|
||||
|
||||
### 2、pandas索引
|
||||
|
||||
### 3、pandas数据清洗之空数据
|
||||
|
||||
[数据挖掘之空数据处理(有史以来最全面)]: https://blog.csdn.net/Soft_Po/article/details/89302887
|
||||
|
||||
### 4、pandas多层索引
|
||||
|
||||
### 5、pandas多层索引计算
|
||||
|
||||
### 6、pandas数据集成concat
|
||||
|
||||
### 7、pandas数据集成merge
|
||||
|
||||
### 8、pandas分组聚合操作
|
||||
|
||||
### 9、pandas数据集成实战
|
||||
|
||||
### 10、美国大选项目
|
||||
|
||||
[2012美国大选政治献金项目数据分析(有史以来最全面)]: https://blog.csdn.net/Soft_Po/article/details/89283382
|
|
@ -0,0 +1,631 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import pandas as pd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pandas import Series,DataFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Math 120\n",
|
||||
"Python 136\n",
|
||||
"En 128\n",
|
||||
"Chinese 99\n",
|
||||
"dtype: int64"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 创建\n",
|
||||
"# Series是一维的数据\n",
|
||||
"s = Series(data = [120,136,128,99],index = ['Math','Python','En','Chinese'])\n",
|
||||
"s"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(4,)"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([120, 136, 128, 99], dtype=int64)"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v = s.values\n",
|
||||
"v"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"numpy.ndarray"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"type(v)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"120.75"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s.mean()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"136"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s.max()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"15.903353943953666"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s.std()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Math 14400\n",
|
||||
"Python 18496\n",
|
||||
"En 16384\n",
|
||||
"Chinese 9801\n",
|
||||
"dtype: int64"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s.pow(2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>a</th>\n",
|
||||
" <td>113</td>\n",
|
||||
" <td>116</td>\n",
|
||||
" <td>75</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>b</th>\n",
|
||||
" <td>19</td>\n",
|
||||
" <td>145</td>\n",
|
||||
" <td>23</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>c</th>\n",
|
||||
" <td>57</td>\n",
|
||||
" <td>107</td>\n",
|
||||
" <td>113</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>d</th>\n",
|
||||
" <td>95</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>66</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>e</th>\n",
|
||||
" <td>28</td>\n",
|
||||
" <td>121</td>\n",
|
||||
" <td>120</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>f</th>\n",
|
||||
" <td>141</td>\n",
|
||||
" <td>85</td>\n",
|
||||
" <td>132</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>h</th>\n",
|
||||
" <td>124</td>\n",
|
||||
" <td>39</td>\n",
|
||||
" <td>10</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>i</th>\n",
|
||||
" <td>80</td>\n",
|
||||
" <td>35</td>\n",
|
||||
" <td>17</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>j</th>\n",
|
||||
" <td>68</td>\n",
|
||||
" <td>99</td>\n",
|
||||
" <td>31</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>k</th>\n",
|
||||
" <td>74</td>\n",
|
||||
" <td>12</td>\n",
|
||||
" <td>11</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"a 113 116 75\n",
|
||||
"b 19 145 23\n",
|
||||
"c 57 107 113\n",
|
||||
"d 95 3 66\n",
|
||||
"e 28 121 120\n",
|
||||
"f 141 85 132\n",
|
||||
"h 124 39 10\n",
|
||||
"i 80 35 17\n",
|
||||
"j 68 99 31\n",
|
||||
"k 74 12 11"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DataFrame是二维的数据\n",
|
||||
"# excel就非诚相似\n",
|
||||
"# 所有进行数据分析,数据挖掘的工具最基础的结果:行和列,行表示样本,列表示的是属性\n",
|
||||
"df = DataFrame(data = np.random.randint(0,150,size = (10,3)),index = list('abcdefhijk'),columns=['Python','En','Math'])\n",
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(10, 3)"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([[113, 116, 75],\n",
|
||||
" [ 19, 145, 23],\n",
|
||||
" [ 57, 107, 113],\n",
|
||||
" [ 95, 3, 66],\n",
|
||||
" [ 28, 121, 120],\n",
|
||||
" [141, 85, 132],\n",
|
||||
" [124, 39, 10],\n",
|
||||
" [ 80, 35, 17],\n",
|
||||
" [ 68, 99, 31],\n",
|
||||
" [ 74, 12, 11]])"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v = df.values\n",
|
||||
"v"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Python 79.9\n",
|
||||
"En 76.2\n",
|
||||
"Math 59.8\n",
|
||||
"dtype: float64"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.mean()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Python 141\n",
|
||||
"En 145\n",
|
||||
"Math 132\n",
|
||||
"dtype: int32"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.max()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>a</th>\n",
|
||||
" <td>113</td>\n",
|
||||
" <td>116</td>\n",
|
||||
" <td>75</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>b</th>\n",
|
||||
" <td>19</td>\n",
|
||||
" <td>145</td>\n",
|
||||
" <td>23</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>c</th>\n",
|
||||
" <td>57</td>\n",
|
||||
" <td>107</td>\n",
|
||||
" <td>113</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>d</th>\n",
|
||||
" <td>95</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>66</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>e</th>\n",
|
||||
" <td>28</td>\n",
|
||||
" <td>121</td>\n",
|
||||
" <td>120</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>f</th>\n",
|
||||
" <td>141</td>\n",
|
||||
" <td>85</td>\n",
|
||||
" <td>132</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>h</th>\n",
|
||||
" <td>124</td>\n",
|
||||
" <td>39</td>\n",
|
||||
" <td>10</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>i</th>\n",
|
||||
" <td>80</td>\n",
|
||||
" <td>35</td>\n",
|
||||
" <td>17</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>j</th>\n",
|
||||
" <td>68</td>\n",
|
||||
" <td>99</td>\n",
|
||||
" <td>31</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>k</th>\n",
|
||||
" <td>74</td>\n",
|
||||
" <td>12</td>\n",
|
||||
" <td>11</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"a 113 116 75\n",
|
||||
"b 19 145 23\n",
|
||||
"c 57 107 113\n",
|
||||
"d 95 3 66\n",
|
||||
"e 28 121 120\n",
|
||||
"f 141 85 132\n",
|
||||
"h 124 39 10\n",
|
||||
"i 80 35 17\n",
|
||||
"j 68 99 31\n",
|
||||
"k 74 12 11"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Python 79.9\n",
|
||||
"En 76.2\n",
|
||||
"Math 59.8\n",
|
||||
"dtype: float64"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.mean(axis = 0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"a 101.333333\n",
|
||||
"b 62.333333\n",
|
||||
"c 92.333333\n",
|
||||
"d 54.666667\n",
|
||||
"e 89.666667\n",
|
||||
"f 119.333333\n",
|
||||
"h 57.666667\n",
|
||||
"i 44.000000\n",
|
||||
"j 66.000000\n",
|
||||
"k 32.333333\n",
|
||||
"dtype: float64"
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.mean(axis = 1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"# 数据分析BI-------->人工智能AI\n",
|
||||
"# 数据分析和数据挖掘一个意思,\n",
|
||||
"# 工具和软件:Excel 免费版\n",
|
||||
"# SPSS(一人一年10000)、SAS(一人一年5000)、Matlab 收费\n",
|
||||
"# R、Python(全方位语言,流行) 免费\n",
|
||||
"# Python + numpy + scipy + pandas + matplotlib + seaborn + pyEcharts + sklearn + kereas(Tensorflow)+…… \n",
|
||||
"# 代码,自动化(数据输入----输出结果)\n",
|
||||
"from pandas import Series,DataFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"a 63\n",
|
||||
"b 107\n",
|
||||
"c 16\n",
|
||||
"d 35\n",
|
||||
"e 140\n",
|
||||
"f 83\n",
|
||||
"dtype: int32"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 多层索引,行列\n",
|
||||
"# 单层索引\n",
|
||||
"s = Series(np.random.randint(0,150,size = 6),index=list('abcdef'))\n",
|
||||
"s"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"张三 期中 114\n",
|
||||
" 期末 131\n",
|
||||
"李四 期中 3\n",
|
||||
" 期末 63\n",
|
||||
"王五 期中 107\n",
|
||||
" 期末 34\n",
|
||||
"dtype: int32"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 多层索引,两层,三层以上(规则一样)\n",
|
||||
"s2 = Series(np.random.randint(0,150,size = 6),index = pd.MultiIndex.from_product([['张三','李四','王五'],['期中','期末']]))\n",
|
||||
"s2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">张三</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>73</td>\n",
|
||||
" <td>5</td>\n",
|
||||
" <td>25</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>37</td>\n",
|
||||
" <td>36</td>\n",
|
||||
" <td>56</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">李四</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>149</td>\n",
|
||||
" <td>81</td>\n",
|
||||
" <td>142</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>71</td>\n",
|
||||
" <td>138</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">王五</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>11</td>\n",
|
||||
" <td>94</td>\n",
|
||||
" <td>103</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>25</td>\n",
|
||||
" <td>121</td>\n",
|
||||
" <td>83</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"张三 期中 73 5 25\n",
|
||||
" 期末 37 36 56\n",
|
||||
"李四 期中 149 81 142\n",
|
||||
" 期末 71 138 0\n",
|
||||
"王五 期中 11 94 103\n",
|
||||
" 期末 25 121 83"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df = DataFrame(np.random.randint(0,150,size = (6,3)),columns=['Python','En','Math'],index =pd.MultiIndex.from_product([['张三','李四','王五'],['期中','期末']]) )\n",
|
||||
"\n",
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"4\" valign=\"top\">张三</th>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期中</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>15</td>\n",
|
||||
" <td>31</td>\n",
|
||||
" <td>17</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>82</td>\n",
|
||||
" <td>56</td>\n",
|
||||
" <td>123</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期末</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>14</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" <td>78</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>69</td>\n",
|
||||
" <td>50</td>\n",
|
||||
" <td>17</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"4\" valign=\"top\">李四</th>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期中</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>91</td>\n",
|
||||
" <td>87</td>\n",
|
||||
" <td>143</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>120</td>\n",
|
||||
" <td>118</td>\n",
|
||||
" <td>39</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期末</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>56</td>\n",
|
||||
" <td>76</td>\n",
|
||||
" <td>55</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>11</td>\n",
|
||||
" <td>105</td>\n",
|
||||
" <td>121</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"4\" valign=\"top\">王五</th>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期中</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>147</td>\n",
|
||||
" <td>78</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>128</td>\n",
|
||||
" <td>126</td>\n",
|
||||
" <td>146</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">期末</th>\n",
|
||||
" <th>A</th>\n",
|
||||
" <td>49</td>\n",
|
||||
" <td>45</td>\n",
|
||||
" <td>114</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>B</th>\n",
|
||||
" <td>121</td>\n",
|
||||
" <td>26</td>\n",
|
||||
" <td>77</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"张三 期中 A 15 31 17\n",
|
||||
" B 82 56 123\n",
|
||||
" 期末 A 14 2 78\n",
|
||||
" B 69 50 17\n",
|
||||
"李四 期中 A 91 87 143\n",
|
||||
" B 120 118 39\n",
|
||||
" 期末 A 56 76 55\n",
|
||||
" B 11 105 121\n",
|
||||
"王五 期中 A 147 78 1\n",
|
||||
" B 128 126 146\n",
|
||||
" 期末 A 49 45 114\n",
|
||||
" B 121 26 77"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 三层索引\n",
|
||||
"df3 = DataFrame(np.random.randint(0,150,size = (12,3)),columns=['Python','En','Math'],index =pd.MultiIndex.from_product([['张三','李四','王五'],['期中','期末'],['A','B']]) )\n",
|
||||
"\n",
|
||||
"df3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"73"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 先获取列后获取行\n",
|
||||
"df['Python']['张三']['期中']"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df2 = df.copy()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">张三</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>73</td>\n",
|
||||
" <td>5</td>\n",
|
||||
" <td>25</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>37</td>\n",
|
||||
" <td>36</td>\n",
|
||||
" <td>56</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">李四</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>149</td>\n",
|
||||
" <td>81</td>\n",
|
||||
" <td>142</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>71</td>\n",
|
||||
" <td>138</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">王五</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>11</td>\n",
|
||||
" <td>94</td>\n",
|
||||
" <td>103</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>25</td>\n",
|
||||
" <td>121</td>\n",
|
||||
" <td>83</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"张三 期中 73 5 25\n",
|
||||
" 期末 37 36 56\n",
|
||||
"李四 期中 149 81 142\n",
|
||||
" 期末 71 138 0\n",
|
||||
"王五 期中 11 94 103\n",
|
||||
" 期末 25 121 83"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df2.sort_index()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"73"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 先获取行,后获取列\n",
|
||||
"df.loc['张三'].loc['期中']['Python']"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th>Python</th>\n",
|
||||
" <th>En</th>\n",
|
||||
" <th>Math</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">张三</th>\n",
|
||||
" <th>期中</th>\n",
|
||||
" <td>73</td>\n",
|
||||
" <td>5</td>\n",
|
||||
" <td>25</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>期末</th>\n",
|
||||
" <td>37</td>\n",
|
||||
" <td>36</td>\n",
|
||||
" <td>56</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Python En Math\n",
|
||||
"张三 期中 73 5 25\n",
|
||||
" 期末 37 36 56"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.iloc[[0,1]]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -0,0 +1,877 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 分组聚合透视\n",
|
||||
"# 很多时候属性是相似的\n",
|
||||
"\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from pandas import Series,DataFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th>Smoke</th>\n",
|
||||
" <th>sex</th>\n",
|
||||
" <th>weight</th>\n",
|
||||
" <th>IQ</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>80</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>50</td>\n",
|
||||
" <td>120</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>48</td>\n",
|
||||
" <td>90</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>75</td>\n",
|
||||
" <td>130</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>68</td>\n",
|
||||
" <td>140</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" <td>80</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>40</td>\n",
|
||||
" <td>94</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>90</td>\n",
|
||||
" <td>110</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>8</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>88</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>9</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>76</td>\n",
|
||||
" <td>160</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Hand Smoke sex weight IQ\n",
|
||||
"0 right yes male 80 100\n",
|
||||
"1 left yes female 50 120\n",
|
||||
"2 left no female 48 90\n",
|
||||
"3 right no male 75 130\n",
|
||||
"4 right yes male 68 140\n",
|
||||
"5 right no male 100 80\n",
|
||||
"6 right no female 40 94\n",
|
||||
"7 right no female 90 110\n",
|
||||
"8 left no male 88 100\n",
|
||||
"9 right yes female 76 160"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 走右手习惯,是否抽烟,性别,对体重,智商,有一定影响\n",
|
||||
"\n",
|
||||
"df = DataFrame({'Hand':['right','left','left','right','right','right','right','right','left','right'],\n",
|
||||
" 'Smoke':['yes','yes','no','no','yes','no','no','no','no','yes'],\n",
|
||||
" 'sex':['male','female','female','male','male','male','female','female','male','female'],\n",
|
||||
" 'weight':[80,50,48,75,68,100,40,90,88,76],\n",
|
||||
" 'IQ':[100,120,90,130,140,80,94,110,100,160]})\n",
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 分组聚合查看规律,某一条件下规律"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>weight</th>\n",
|
||||
" <th>IQ</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>left</th>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" <td>103.3</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>right</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" <td>116.3</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" weight IQ\n",
|
||||
"Hand \n",
|
||||
"left 62.0 103.3\n",
|
||||
"right 75.6 116.3"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data = df.groupby(by = ['Hand'])[['weight','IQ']].mean().round(1)\n",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>weight</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>left</th>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>right</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" weight\n",
|
||||
"Hand \n",
|
||||
"left 62.0\n",
|
||||
"right 75.6"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.groupby(by = ['Hand'])[['weight']].apply(np.mean).round(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df2 = df.groupby(by = ['Hand'])[['weight']].transform(np.mean).round(1)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>weight_mean</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>8</th>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>9</th>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" weight_mean\n",
|
||||
"0 75.6\n",
|
||||
"1 62.0\n",
|
||||
"2 62.0\n",
|
||||
"3 75.6\n",
|
||||
"4 75.6\n",
|
||||
"5 75.6\n",
|
||||
"6 75.6\n",
|
||||
"7 75.6\n",
|
||||
"8 62.0\n",
|
||||
"9 75.6"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df2 = df2.add_suffix('_mean')\n",
|
||||
"df2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th>Smoke</th>\n",
|
||||
" <th>sex</th>\n",
|
||||
" <th>weight</th>\n",
|
||||
" <th>IQ</th>\n",
|
||||
" <th>weight_mean</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>80</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>50</td>\n",
|
||||
" <td>120</td>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>48</td>\n",
|
||||
" <td>90</td>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>75</td>\n",
|
||||
" <td>130</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>68</td>\n",
|
||||
" <td>140</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" <td>80</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>40</td>\n",
|
||||
" <td>94</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>90</td>\n",
|
||||
" <td>110</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>8</th>\n",
|
||||
" <td>left</td>\n",
|
||||
" <td>no</td>\n",
|
||||
" <td>male</td>\n",
|
||||
" <td>88</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>9</th>\n",
|
||||
" <td>right</td>\n",
|
||||
" <td>yes</td>\n",
|
||||
" <td>female</td>\n",
|
||||
" <td>76</td>\n",
|
||||
" <td>160</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" Hand Smoke sex weight IQ weight_mean\n",
|
||||
"0 right yes male 80 100 75.6\n",
|
||||
"1 left yes female 50 120 62.0\n",
|
||||
"2 left no female 48 90 62.0\n",
|
||||
"3 right no male 75 130 75.6\n",
|
||||
"4 right yes male 68 140 75.6\n",
|
||||
"5 right no male 100 80 75.6\n",
|
||||
"6 right no female 40 94 75.6\n",
|
||||
"7 right no female 90 110 75.6\n",
|
||||
"8 left no male 88 100 62.0\n",
|
||||
"9 right yes female 76 160 75.6"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df3 = df.merge(df2,left_index=True,right_index=True)\n",
|
||||
"df3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Hand\n",
|
||||
"left ([3, 3], [62.0, 103.3])\n",
|
||||
"right ([7, 7], [75.6, 116.3])\n",
|
||||
"dtype: object"
|
||||
]
|
||||
},
|
||||
"execution_count": 26,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def count(x):\n",
|
||||
" \n",
|
||||
" return (x.count(),x.mean().round(1))\n",
|
||||
"\n",
|
||||
"df.groupby(by = ['Hand'])[['weight','IQ']].apply(count)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th>IQ</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th>sex</th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">left</th>\n",
|
||||
" <th>female</th>\n",
|
||||
" <td>120</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>male</th>\n",
|
||||
" <td>100</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th rowspan=\"2\" valign=\"top\">right</th>\n",
|
||||
" <th>female</th>\n",
|
||||
" <td>160</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>male</th>\n",
|
||||
" <td>140</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" IQ\n",
|
||||
"Hand sex \n",
|
||||
"left female 120\n",
|
||||
" male 100\n",
|
||||
"right female 160\n",
|
||||
" male 140"
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.groupby(by = ['Hand','sex'])[['IQ']].max()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000019E24051EF0>"
|
||||
]
|
||||
},
|
||||
"execution_count": 29,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data = df.groupby(by = ['Hand'])['IQ','weight']\n",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead tr th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead tr:last-of-type th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr>\n",
|
||||
" <th></th>\n",
|
||||
" <th colspan=\"2\" halign=\"left\">IQ</th>\n",
|
||||
" <th colspan=\"2\" halign=\"left\">weight</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th></th>\n",
|
||||
" <th>max</th>\n",
|
||||
" <th>mean</th>\n",
|
||||
" <th>max</th>\n",
|
||||
" <th>mean</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>left</th>\n",
|
||||
" <td>120</td>\n",
|
||||
" <td>103.3</td>\n",
|
||||
" <td>88</td>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>right</th>\n",
|
||||
" <td>160</td>\n",
|
||||
" <td>116.3</td>\n",
|
||||
" <td>100</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" IQ weight \n",
|
||||
" max mean max mean\n",
|
||||
"Hand \n",
|
||||
"left 120 103.3 88 62.0\n",
|
||||
"right 160 116.3 100 75.6"
|
||||
]
|
||||
},
|
||||
"execution_count": 31,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data.agg(['max','mean']).round(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 35,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>IQ</th>\n",
|
||||
" <th>weight</th>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>Hand</th>\n",
|
||||
" <th></th>\n",
|
||||
" <th></th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>left</th>\n",
|
||||
" <td>120</td>\n",
|
||||
" <td>62.0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>right</th>\n",
|
||||
" <td>160</td>\n",
|
||||
" <td>75.6</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" IQ weight\n",
|
||||
"Hand \n",
|
||||
"left 120 62.0\n",
|
||||
"right 160 75.6"
|
||||
]
|
||||
},
|
||||
"execution_count": 35,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data.agg({'IQ':'max','weight':'mean'}).round(1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
"state","abbreviation"
|
||||
"Alabama","AL"
|
||||
"Alaska","AK"
|
||||
"Arizona","AZ"
|
||||
"Arkansas","AR"
|
||||
"California","CA"
|
||||
"Colorado","CO"
|
||||
"Connecticut","CT"
|
||||
"Delaware","DE"
|
||||
"District of Columbia","DC"
|
||||
"Florida","FL"
|
||||
"Georgia","GA"
|
||||
"Hawaii","HI"
|
||||
"Idaho","ID"
|
||||
"Illinois","IL"
|
||||
"Indiana","IN"
|
||||
"Iowa","IA"
|
||||
"Kansas","KS"
|
||||
"Kentucky","KY"
|
||||
"Louisiana","LA"
|
||||
"Maine","ME"
|
||||
"Montana","MT"
|
||||
"Nebraska","NE"
|
||||
"Nevada","NV"
|
||||
"New Hampshire","NH"
|
||||
"New Jersey","NJ"
|
||||
"New Mexico","NM"
|
||||
"New York","NY"
|
||||
"North Carolina","NC"
|
||||
"North Dakota","ND"
|
||||
"Ohio","OH"
|
||||
"Oklahoma","OK"
|
||||
"Oregon","OR"
|
||||
"Maryland","MD"
|
||||
"Massachusetts","MA"
|
||||
"Michigan","MI"
|
||||
"Minnesota","MN"
|
||||
"Mississippi","MS"
|
||||
"Missouri","MO"
|
||||
"Pennsylvania","PA"
|
||||
"Rhode Island","RI"
|
||||
"South Carolina","SC"
|
||||
"South Dakota","SD"
|
||||
"Tennessee","TN"
|
||||
"Texas","TX"
|
||||
"Utah","UT"
|
||||
"Vermont","VT"
|
||||
"Virginia","VA"
|
||||
"Washington","WA"
|
||||
"West Virginia","WV"
|
||||
"Wisconsin","WI"
|
||||
"Wyoming","WY"
|
|
|
@ -0,0 +1,53 @@
|
|||
state,area (sq. mi)
|
||||
Alabama,52423
|
||||
Alaska,656425
|
||||
Arizona,114006
|
||||
Arkansas,53182
|
||||
California,163707
|
||||
Colorado,104100
|
||||
Connecticut,5544
|
||||
Delaware,1954
|
||||
Florida,65758
|
||||
Georgia,59441
|
||||
Hawaii,10932
|
||||
Idaho,83574
|
||||
Illinois,57918
|
||||
Indiana,36420
|
||||
Iowa,56276
|
||||
Kansas,82282
|
||||
Kentucky,40411
|
||||
Louisiana,51843
|
||||
Maine,35387
|
||||
Maryland,12407
|
||||
Massachusetts,10555
|
||||
Michigan,96810
|
||||
Minnesota,86943
|
||||
Mississippi,48434
|
||||
Missouri,69709
|
||||
Montana,147046
|
||||
Nebraska,77358
|
||||
Nevada,110567
|
||||
New Hampshire,9351
|
||||
New Jersey,8722
|
||||
New Mexico,121593
|
||||
New York,54475
|
||||
North Carolina,53821
|
||||
North Dakota,70704
|
||||
Ohio,44828
|
||||
Oklahoma,69903
|
||||
Oregon,98386
|
||||
Pennsylvania,46058
|
||||
Rhode Island,1545
|
||||
South Carolina,32007
|
||||
South Dakota,77121
|
||||
Tennessee,42146
|
||||
Texas,268601
|
||||
Utah,84904
|
||||
Vermont,9615
|
||||
Virginia,42769
|
||||
Washington,71303
|
||||
West Virginia,24231
|
||||
Wisconsin,65503
|
||||
Wyoming,97818
|
||||
District of Columbia,68
|
||||
Puerto Rico,3515
|
|
|
@ -1,5 +1,7 @@
|
|||
## Django知识点概述
|
||||
|
||||
> 说明:本文的部分插图来自于《Python项目开发实战》和《精通Django》,这两本书中都包含了对Django框架精彩的讲解,有兴趣的读者可以自行购买阅读。
|
||||
|
||||
### Web应用
|
||||
|
||||
问题1:描述一个Web应用的工作流程。
|
||||
|
|
|
@ -46,7 +46,7 @@ API接口返回的数据通常都是JSON或XML格式,我们这里不讨论后
|
|||
| 10003 | 评论已被删除 | 查看评论时评论因不和谐因素已被删除 |
|
||||
| 10004 | …… | …… |
|
||||
|
||||
1. **GET** `/comments/{article-id}`
|
||||
1. **GET** `/articles/{article-id}/comments/`
|
||||
|
||||
开发者:王大锤
|
||||
|
||||
|
@ -95,7 +95,7 @@ API接口返回的数据通常都是JSON或XML格式,我们这里不讨论后
|
|||
}
|
||||
```
|
||||
|
||||
2. **POST** `/comments/{article-id}`
|
||||
2. **POST** `/articles/{article-id}/comments`
|
||||
|
||||
开发者:王大锤
|
||||
|
||||
|
|
18
Python惯例.md
|
@ -5,7 +5,6 @@
|
|||
1. 让代码既可以被导入又可以被执行。
|
||||
|
||||
```Python
|
||||
|
||||
if __name__ == '__main__':
|
||||
```
|
||||
|
||||
|
@ -13,7 +12,6 @@
|
|||
2. 用下面的方式判断逻辑“真”或“假”。
|
||||
|
||||
```Python
|
||||
|
||||
if x:
|
||||
if not x:
|
||||
```
|
||||
|
@ -21,7 +19,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
name = 'jackfrued'
|
||||
fruits = ['apple', 'orange', 'grape']
|
||||
owners = {'1001': '骆昊', '1002': '王大锤'}
|
||||
|
@ -32,7 +29,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
name = 'jackfrued'
|
||||
fruits = ['apple', 'orange', 'grape']
|
||||
owners = {'1001': '骆昊', '1002': '王大锤'}
|
||||
|
@ -43,7 +39,6 @@
|
|||
3. 善于使用in运算符。
|
||||
|
||||
```Python
|
||||
|
||||
if x in items: # 包含
|
||||
for x in items: # 迭代
|
||||
```
|
||||
|
@ -51,7 +46,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
name = 'Hao LUO'
|
||||
if 'L' in name:
|
||||
print('The name has an L in it.')
|
||||
|
@ -60,7 +54,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
name = 'Hao LUO'
|
||||
if name.find('L') != -1:
|
||||
print('This name has an L in it!')
|
||||
|
@ -69,7 +62,6 @@
|
|||
4. 不使用临时变量交换两个值。
|
||||
|
||||
```Python
|
||||
|
||||
a, b = b, a
|
||||
```
|
||||
|
||||
|
@ -78,7 +70,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
chars = ['j', 'a', 'c', 'k', 'f', 'r', 'u', 'e', 'd']
|
||||
name = ''.join(chars)
|
||||
print(name) # jackfrued
|
||||
|
@ -87,7 +78,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
chars = ['j', 'a', 'c', 'k', 'f', 'r', 'u', 'e', 'd']
|
||||
name = ''
|
||||
for char in chars:
|
||||
|
@ -104,7 +94,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
d = {'x': '5'}
|
||||
try:
|
||||
value = int(d['x'])
|
||||
|
@ -116,7 +105,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
d = {'x': '5'}
|
||||
if 'x' in d and isinstance(d['x'], str) \
|
||||
and d['x'].isdigit():
|
||||
|
@ -131,7 +119,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
fruits = ['orange', 'grape', 'pitaya', 'blueberry']
|
||||
for index, fruit in enumerate(fruits):
|
||||
print(index, ':', fruit)
|
||||
|
@ -140,7 +127,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
fruits = ['orange', 'grape', 'pitaya', 'blueberry']
|
||||
index = 0
|
||||
for fruit in fruits:
|
||||
|
@ -153,7 +139,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
data = [7, 20, 3, 15, 11]
|
||||
result = [num * 3 for num in data if num > 10]
|
||||
print(result) # [60, 45, 33]
|
||||
|
@ -162,7 +147,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
data = [7, 20, 3, 15, 11]
|
||||
result = []
|
||||
for i in data:
|
||||
|
@ -176,7 +160,6 @@
|
|||
**好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
keys = ['1001', '1002', '1003']
|
||||
values = ['骆昊', '王大锤', '白元芳']
|
||||
d = dict(zip(keys, values))
|
||||
|
@ -186,7 +169,6 @@
|
|||
**不好**的代码:
|
||||
|
||||
```Python
|
||||
|
||||
keys = ['1001', '1002', '1003']
|
||||
values = ['骆昊', '王大锤', '白元芳']
|
||||
d = {}
|
||||
|
|
81
README.md
|
@ -1,6 +1,10 @@
|
|||
## Python - 100天从新手到大师
|
||||
|
||||
> 作者:骆昊
|
||||
>
|
||||
> 说明:最近有很多想学习Python的小伙伴申请单独加我微信和QQ,因为我自己平时也很忙,没办法一一解答大家的问题,我创建了**Python100天学习交流1群**和**Python100天学习交流2群**两个交流群,群号分别为**680701107**和**213132758**,二维码在下方。我的同事和朋友很多也在这个群里,他们都是优秀的Python开发者,有丰富的商业项目经验,我们在时间充足的时候会及时解答大家的问题,而且从Python语言入门到Web应用开发,从数据分析到机器学习,每个领域都有技术大咖为大家解惑答疑。以后我们争取每周做一次视频直播,以专题的形式分享Python开发的点点滴滴,同时还会不定期的举办线上和线下的技术交流和分享活动,小伙伴们可以加群进行交流。感谢**千锋教育Python教学部**对本群的支持。
|
||||
|
||||
![](./res/python_100_days_qq_group.png)
|
||||
|
||||
### Python应用领域和就业形势分析
|
||||
|
||||
|
@ -35,7 +39,7 @@
|
|||
|
||||
![](./res/python-bj-salary.png)
|
||||
|
||||
![](./res/python-cd-salary.png)
|
||||
![](./res/python-salary-chengdu.png)
|
||||
|
||||
给初学者的几个建议:
|
||||
|
||||
|
@ -242,33 +246,78 @@
|
|||
|
||||
#### Day44 - [表单的应用](./Day41-55/04.表单的应用.md)
|
||||
|
||||
- 表单和表单控件
|
||||
- 跨站请求伪造和CSRF令牌
|
||||
- Form和ModelForm
|
||||
- 表单验证
|
||||
|
||||
#### Day45 - [Cookie和Session](./Day41-55/05.Cookie和Session.md)
|
||||
|
||||
- 实现用户跟踪
|
||||
- cookie和session的关系
|
||||
- Django框架对session的支持
|
||||
- 视图函数中的cookie读写操作
|
||||
|
||||
#### Day46 - [中间件的应用](./Day41-55/06.中间件的应用.md)
|
||||
|
||||
#### Day47 - [日志和缓存](./Day41-55/07.日志和缓存.md)
|
||||
- 什么是中间件
|
||||
- Django框架内置的中间件
|
||||
- 自定义中间件及其应用场景
|
||||
|
||||
#### Day47 - [日志和调试](./Day41-55/07.日志和调试.md)
|
||||
|
||||
- 配置日志
|
||||
- 配置和使用Django-Debug-Toolbar
|
||||
|
||||
#### Day48 - [文件上传和富文本编辑](./Day41-55/08.文件上传.md)
|
||||
|
||||
- 文件上传表单控件和图片文件预览
|
||||
- 服务器端如何处理上传的文件
|
||||
- 富文本编辑器概述
|
||||
- wangEditor的使用
|
||||
|
||||
#### Day49 - [文件下载和报表](./Day41-55/09.文件下载和报表.md)
|
||||
|
||||
- 通过HttpResponse修改响应头
|
||||
- 使用StreamingHttpResponse处理大文件
|
||||
- 使用xlwt生成Excel报表
|
||||
- 使用reportlab生成PDF报表
|
||||
- 使用ECharts生成前端图表
|
||||
|
||||
#### Day50 - [RESTful架构和DRF入门](./Day41-55/10.RESTful架构和DRF入门.md)
|
||||
|
||||
#### Day51 - [RESTful架构和DRF进阶](./Day41-55/11.RESTful架构和DRF进阶.md)
|
||||
|
||||
#### Day52 - [使用缓存](./Day41-55/12.使用缓存.md)
|
||||
|
||||
- 网站优化第一定律
|
||||
|
||||
- 在Django项目中使用Redis提供缓存服务
|
||||
- 在视图函数中读写缓存
|
||||
- 使用装饰器实现页面缓存
|
||||
- 为数据接口提供缓存服务
|
||||
|
||||
#### Day53 - [短信和邮件](./Day41-55/13.短信和邮件.md)
|
||||
|
||||
- 常用短信网关平台介绍
|
||||
- 使用螺丝帽发送短信
|
||||
- Django框架对邮件服务的支持
|
||||
|
||||
#### Day54 - [异步任务和定时任务](./Day41-55/14.异步任务和定时任务.md)
|
||||
|
||||
- 网站优化第二定律
|
||||
- 配置消息队列服务
|
||||
- 在项目中使用celery实现任务异步化
|
||||
- 在项目中使用celery实现定时任务
|
||||
|
||||
#### Day55 - [单元测试和项目上线](./Day41-55/15.单元测试和项目上线.md)
|
||||
|
||||
- 项目开发流程和相关工具
|
||||
- 生成非HTML内容
|
||||
- 项目部署和测试
|
||||
- 项目性能初步调优
|
||||
- Web应用安全保护
|
||||
- Python中的单元测试
|
||||
- Django框架对单元测试的支持
|
||||
- 使用版本控制系统
|
||||
- 配置和使用uWSGI
|
||||
- 动静分离和Nginx配置
|
||||
- 配置HTTPS
|
||||
|
||||
|
||||
### Day56~60 - [实战Flask](./Day56-65)
|
||||
|
@ -395,15 +444,15 @@
|
|||
> - **客户合作** 高于 合同谈判
|
||||
> - **响应变化** 高于 遵循计划
|
||||
|
||||
![](./res/the-daily-scrum-in-the-sprint-cycle.png)
|
||||
![](./res/agile-scrum-sprint-cycle.png)
|
||||
|
||||
> 角色:产品所有者(决定做什么,能对需求拍板的人)、团队负责人(解决各种问题,专注如何更好的工作,屏蔽外部对开发团队的影响)、开发团队(项目执行人员,具体指开发人员和测试人员)。
|
||||
>
|
||||
> 准备工作:商业案例和资金、合同、憧憬、初始产品需求、初始发布计划、入股、组建团队。
|
||||
>
|
||||
> 敏捷团队通常人数为8-10人。
|
||||
>
|
||||
> 工作量估算:将开发任务量化,包括原型、Logo设计、UI设计、前端开发等,尽量把每个工作分解到最小任务量,最小任务量标准为工作时间不能超过两天,然后估算总体项目时间。把每个任务都贴在白板上面,白板上分三部分:to do(待完成)、in progress(进行中)和done(已完成)。
|
||||
> 角色:产品所有者(决定做什么,能对需求拍板的人)、团队负责人(解决各种问题,专注如何更好的工作,屏蔽外部对开发团队的影响)、开发团队(项目执行人员,具体指开发人员和测试人员)。
|
||||
|
||||
> 准备工作:商业案例和资金、合同、憧憬、初始产品需求、初始发布计划、入股、组建团队。
|
||||
|
||||
> 敏捷团队通常人数为8-10人。
|
||||
|
||||
> 工作量估算:将开发任务量化,包括原型、Logo设计、UI设计、前端开发等,尽量把每个工作分解到最小任务量,最小任务量标准为工作时间不能超过两天,然后估算总体项目时间。把每个任务都贴在白板上面,白板上分三部分:to do(待完成)、in progress(进行中)和done(已完成)。
|
||||
|
||||
2. 项目团队组建
|
||||
|
||||
|
@ -587,6 +636,4 @@
|
|||
- 云存储
|
||||
- CDN
|
||||
|
||||
|
||||
|
||||
> 致谢:感谢的我的同事古晔、张旭、肖世荣、王海飞、荣佳伟、路丰坤等在技术上给予的指导和帮助。
|
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 554 KiB |
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 217 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 313 KiB |
Before Width: | Height: | Size: 195 KiB |
Before Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 400 KiB |
BIN
res/celery.png
Before Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 436 KiB |
Before Width: | Height: | Size: 290 KiB |
Before Width: | Height: | Size: 336 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 253 KiB |
Before Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 140 KiB |