Superchilli's Blog

Tech and life


  • 首页

  • 归档

  • 标签

  • 分类

  • 关于

Recursion

发表于 2017-12-16 |

之前我一直对递归抱有很深的误解,还没有去了解递归是什么就对这个概念感到害怕,一遇到递归就死机。

我在知乎上看到一个问题说:“如何理解递归?”,有一条回复是:“要理解递归,先理解递归。”这样看起来确实很糊涂,所以我就更糊涂了。

最近看《Problem Solving With Algrithm and Data Structure》这本书,重新去了解了递归的概念和法则,并且从简单的练习里真正去运用递归,发现递归其实没有想的那么困难。

什么是递归?

Recursion is a method of solving problems that involves breaking a problem down into smaller and smaller subproblems. Until you get to a small problem that it can be solved trivially. Usually recursion involves a function calling itself. While it may not seem like much on the surface, recursion allows us write elegant solution to problems that may otherwise be very diffcult to program.

简单来说,递归就是把一个问题分解成更小的问题,直到这个问题小到可以被轻易的解决。就像 1+2 这么简单。同时,递归需要调用自身来解决问题。

递归的三个法则

  • A recursive algorithm must have a base case.
  • A recursive algorithm must change its state and move toword the base case.
  • A recursive algorithm must call itself, recursively.
  • 运用递归,必须要有一个最基础的解决方法。
  • 运用递归时,必须要一直朝着基础的方法前进。意思是每一步都会把问题分解成更基础的算法,直到问题变成可以用最简单的方法解决。
  • 递归必须要调用自身。

这里是 base case 就是指一个可以直接解决的小问题。例如:1+2, 1*2 这种。

章节4.5后面有2个小的练习:

  • Write a function that takes a string as a parameter and returns a new string that is the reverse of the old string.
  • Write a function that takes a string as a parameter and returns True if the string is a palindrome, False otherwise. Remember that a string is a palindrome if it is spelled the same both forward and backward. For example: radar is a palindrome. for bonus points palindromes can also be phrases, but you need to remove the spaces and punctuation before checking. for example: madam i’m adam is a palindrome.

这2个小练习都非常简单,并且有很多种方法去写。

以下答案:

1
2
3
4
5
def reverse(s):
if len(s) == 1:
return s
else:
return reverse(s[1:]) + s[0]

第二题:

1
2
3
4
5
6
def isPalindrome(s):
if len(s) <= 1:
return True
from string import ascii_letters
s = ''.join([i.lower() for i in s if i in ascii_letters])
return s[0] == s[-1] and isPalindrome(s[1:-1])

做完以上2个小练习之后,我对递归的概念就清楚很多了。

Python 核心编程练习-chapter 5

发表于 2017-09-11 |

Q: 1. 讲讲Python普通整形和长整型的区别。

A: 一般情况长整型用来表示非常大的数字,和计算机支持的内存大小有关。而普通整形则代表C语言中的整形和长整型。

Q: 2. 写一个函数,计算并返回两个数的乘积。

A:

1
2
3
4
5
def multiply(x, y):
if isinstance(x, (int, float)) and isinstance(y, (int, float)):
return x * y
else:
print('Please enter a int or float.')

Q: 3. 写一段脚本,输入一个测验成绩,根据下面的标准,输出他的评分成绩(A-F)
A:90 - 100;B: 80 - 89; C: 70 - 79; D: 60 - 69; F: < 60

A:

1
2
3
4
5
6
7
8
9
10
def score(s):
if s >= 90:
return A
elif s >= 80:
return B
elif s >= 70:
return C
elif s >= 60:
return D
return F

Q: 4. 判断给定年份是否是闰年,使用下面的公式:一个闰年就是指它可以被4整除,但不能被100整除,或者它既可以被4又可以被100整除。

A:

1
2
3
4
5
6
def isLeapYear(x):
if x % 4 == 0 and x % 100 == 0:
return True
elif x % 4 == 0:
return True
return False

Q: 5. 取一个任意小于1美元的金额,然后计算可以换成最少多少枚硬币。硬币有1美分,5美分,10美分,25美分4种。1美元等于100美分。0.76美元换算成结果应该是3枚25美分,1枚1美分。

A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def changeCent(x):
if x < 1 and x >= 0.25:
i = x * 100
a, b = divmod(i, 25)
if b >= 10:
c, d = divmod(b, 10)
if d >= 5:
e, f = divmod(d, 5)
return a + c + e + f
return a + c + d
return a + b
elif x >= 0.1:
i = x * 100
a, b = divmod(i, 10)
if b >= 5:
c, d = divmod(b, 5)
return a + c + d
return a + b
elif x >= 0.05:
i = x * 100
a, b = divmod(i, 5)
return a + b
elif x > 0:
i = x * 100
return i

Q: 6. 写一个计算器程序,你的代码可以接受这样的表达式,两个操作数加一个运算符: N1 运算符 N2,其中 N1 和 N2 为整数或浮点数,运算符可以是 +,-,*,//,%,\分别表示加法,减法,乘法,整除,取余和幂计算。计算这个表达式的结果,然后显示出来。提示:可以使用字符串 split(),但不可以使用内建函数 eval()。**

A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def calculator(s):
new_s = str(s).split()
if len(new_s) == 3:
a, b, c = new_s
if '.' in a or '.' in c:
d, e = float(a), float(c)
if b == "+":
return (d + e)
elif b == "-":
return (d - e)
elif b == "*":
return (d * e)
elif b == "//":
return (d // e)
elif b == "%":
return (d % e)
elif b == "**":
return (d ** e)
d, e = int(a), int(c)
if b == "+":
return (d + e)
elif b == "-":
return (d - e)
elif b == "*":
return (d * e)
elif b == "//":
return (d // e)
elif b == "%":
return (d % e)
elif b == "**":
return (d ** e)
print("Please enter correct format, e.g: '1 + 2'")

Q: 7. 为什么 17+32 等于49, 而 017+32 等于 47,017+032 等于41?

A: 17+32 是十进制运算,结果是49,017+32 是把 017 先转成十进制,int(‘017’, 8)可以得到15,15+32等于47,同理 017+032, int(‘032’, 8)等于26,15+26 等于41

Q: 8. 为什么下面这个表达式得到的结果是 134L,而不是1342?>>>56l + 78l; 134L

A: 因为是 56L + 78L,两个长整型相加所以得到长整型。

Python 核心编程练习-chapter 4

发表于 2017-09-11 |

Q: 1. 与所有Python对象有关的三个属性是什么?请简单的描述一下。

A: 身份,类型和值。
身份:每一个对象都有一个唯一的身份表示,可以用内建函数 id() 来查看。
类型:对象的类型决定了对象可以保存什么类型的值,可以进行什么样的操作,以及遵循什么样的规则。可以使用内建函数 type() 来查看对象的类型。
值:对象表示的数值项。

Q: 2. 不可变更指的是什么?Python的哪些类型是可更改的,哪些不是?

A: 不可变更是指对象一旦创建,值就不可以变更。数值,字符串和元组是不可变更的类型,列表和字典是可以变更的类型。

Q: 3. 哪些Python类型是按照顺序访问的,它们和映射类型的不同是什么?

A: 字符串,列表和元组是按照顺序访问的,映射类型的值是无序存储,需要通过具体的键去查找对应的值。映射类型查找数据更直接更快,但是需要更多的内存。

Q: 4. 内建函数 type() 做什么?type() 返回的对象是什么?

A: type() 用来查看对象的类型,返回的对象是类型对象,类型对象的类型都是type, 它是所有Python类型的根和所有Python标准类的默认元类(mataclass)。

Q: 5. 内建函数 str() 和 repr() 之间的不同是什么?哪一个等价于反引号(’’)运算符?

A: str() 函数得到的字符串可读性好,而 repr() 函数得到的字符串通常可以用力啊重新获取该对象。 repr()和反引号相等。

Q: 6. 你认为type(a) == type(b) 和 type(a) is type(b)之间的不同点是什么?为什么会选择后者?函数 isinstance()与这有什么关系?

A: == 是对比值,is 是对比引用地址,如果对象是相同的,就不需要去比较值了。isinstance() 就是用来判断类型的。

Q: 7. 列表和元祖的相同点是什么?不同点是什么?

A: 列表和元组都是容器存储类型,不同点是,列表的值可以变更, 元组不可变更。

Python 核心编程练习-chapter 3

发表于 2017-09-09 |

Q: 1. 为什么Python中不需要变量名和变量类型声明?
A: Python 的变量在第一次被赋值时自动声明,同时,对象的类型和内存占用也是运行时确定的。在创建–也就是赋值时,解释器会根据语法和右侧的操作数来决定新对象的类型。

Q: 2. 为什么Python中不需要声明函数类型?
A: Python 不需要指定函数返回值的类型,如果函数执行过return语句,它将返回指定的值,否则将返回None。

Q: 3. 为什么应当避免在变量名的开始和结尾使用双下划线?
A: 因为下划线对解释器有特殊意义,例如 xxx 是 Python 的内置函数变量名,是系统定义的名字。

Q: 4. 在Python中一行可以书写多个语句吗?
A: 可以,使用分号(;)隔开即可。但是同一行书写太多语句会降低代码的可读性。

Q: 5. 在Python中可以将一个语句分成多行书写吗?
A: 可以,可以使用反斜杠\,或是括号”(){}[]”。建议使用括号。

Q: 6. 赋值语句 x, y, z = 1, 2, 3 会在 x, y, z 中分别赋什么值?
A: x → 1,y → 2,z → 3,

Q: 7. 执行 z, x, y = y, z, x 后,x, y, z 中分别含有什么值?
A: z → 2,x → 3,y → 1

staticmethod and classmethod

发表于 2017-09-04 |

python 有三个方法,分别是实例方法,staticmethod(静态方法)和 classmethod(类方法)。

实例方法就是常用的,把一个类实例化,例如:

1
2
3
4
5
class Foo(object):
def my_class(self):
pass
a = Foo()
a.my_class()

staticmethod

staticmethod 不需要通过实例化类,就可以直接调用类里的方法。

1
2
3
4
5
6
class Foo():
@staticmethod
def static_method():
pass
Foo.static_method()

classmethod

classmethod 也不需要实例化类,但是在使用的时候,需要在方法里传入一个 cls 的参数,这相当于把类本身传递进去。在调用的时候可以直接通过Foo.class_method()来调用。

1
2
3
4
5
6
class Foo():
@classmethod
def class_method(cls):
pass
Foo.class_method()

WSGI partⅡ

发表于 2017-09-04 |

WSGI应用接口

WSGI应用接口要求,应用必须有是一个可调用对象,即拥有 __call__() 方法,这个应用可以是:函数,方法,类或实例。同时,这个应用必须满足:

  • 接收2个参数:environ 和 start_response
  • 在发送响应正文之前必须调用 start_response 回调函数
  • 必须返回一个可迭代的正文

一个简单 WSGI 应用示例:


def application(environ, start_response):
    status = '200 OK' 
    response_headers = [('Content-type','text/plain')] 
    start_response(status, response_headers) 
    return ['Hello world!\n']

WSGI服务器

如何启动上面的应用呢? 可以选择一个WSGI服务器来调用,如果只是想在本地测试,可以使用 wsgiref,下面是一个简单的示例:


if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    srv = make_server('localhost', 8080, application)
    srv.serve_forever()

将这两段代码放在同一个文件里,并将文件命名为application.py,在终端里输入python application.py,再打开浏览器,输入http://localhost:8080/就可以看到页面上显示的 Hello world 了。
按ctrl+C可以终止服务器。

这样就完成了一个简单的WSGI应用程序和调用。

WSGI partⅠ

发表于 2017-09-04 |

WSGI 是什么?

WSGI 不是服务器,不是Python的模块,不是一个框架,不是API也不是任何类型的软件,它只是服务器和应用程序通信的接口规范。

这个规范分为2部分:
为Web服务器端编写的第一部分说:“OK,如果你想处理一个WSGI应用程序,这是软件在加载时会如何思考,这是你必须为应用程序提供的东西,在这里是您可以期望每个应用程序拥有的界面(布局),以及,如果出现问题,应用程序将如何思考以及如何期待它的行为。“

第二部分是针对Python应用软件编写的,他说:“好的,如果你想接入一个WSGI服务器,那么这个服务器在与你联系的时候会这么想,这是服务器必须提供的东西,这是您可以期望每个服务器拥有的界面(布局),而且,如果出现任何问题,这里应该如何运行,这里应该告诉服务器。”

如果一个应用程序(或框架或工具包)是按照WSGI的规范写入,那么这个应用程序可以在任何写入了WSGI服务器上运行。
WSGI应用程序可以堆栈,位于堆栈中间的称为中间件,中间件必须实现WSGI接口,服务器和应用程序的两端。位于上层的中间件可以作为服务器,位于下层的中间件可以作为应用程序。

一个符合WSGI标准的服务器,只接受从客户端发起的请求,传递给应用程序,再将回应从应用程序发送给客户端。其他的细节工作都交给中间件或应用程序来完成。

为什么要使用WSGI

一个传统的Web服务器不知道如何启动Python应用程序。1990年后期,Grisha Trubetskoy 编写了一个名为 mod_python 的 Apache 模块来执行Python代码。mod_python 流行了一段时间,由于不够规范化和存在安全隐患,所以 Python 社区提出了使用WSGI作为模块和容器可以实现的接口。

文章内容来自:
WSGI-Introduction
Full Stack Python
What are WSGI and CGI in plain English?-Stack Overflow

HTTP 协议

发表于 2017-09-01 |

HTTP 协议

  • Web客户端和服务器是如何通信的
  • Web页面的资源来自何方
  • Web事务是怎样工作的
  • HTTP通信所使用的报文格式
  • 底层TCP网络传输
  • 不同的HTTP协议变体

HTTP是什么?
超文本传输安全协议, Web客户端和服务器是通过HTTP相互通信的,也需要遵守HTTP的规则。

简单的说,常见的客户端就是Web浏览器,我们在地址栏输入网址,点击Enter的动作就是向这个网址所在的服务器发起请求,来获取这个网页上的资源。服务器接收到这个请求后,根据请求的内容,发送相应的资源文件给到客户端,于是我就可以在浏览器上查看这个网站的内容了。

一般我们说网址都是说URL,第一次看到URI这个概念的时候有点发懵。URI: Uniform Resource Identifier,统一资源标识符。URI有2中形式,一种是URL,另外一种是URN。

URL的格式:http://superchilli.github.io/blog
http代表访问资源所使用的协议类型,通常就是HTTP协议。
superchilli.github.io 代表这个网站的地址。
/blog 代表了具体资源所在的位置。

现在,几乎所有的URI都是URL。

URN是作为特点内容的唯一名称使用的,与资源所在的位置无关。


事务:

一个HTTP事务由一条从客户端发往服务器的请求命令和一个从服务器发挥客户端的响应结果组成。
这种通讯是通过名为HTTP报文的格式化数据块进行的。

HTTP支持几种不同的请求命令,这些命令被称为HTTP方法。每条HTTP请求报文都包含一个方法,这个方法会告诉服务器要执行什么动作。
5种常见的HTTP方法:

  • GET 从服务器向客户端发送命名资源
  • PUT 将来自客户端的数据存储到一个命名的服务器资源中去
  • DELETE 从服务器中删除命名资源
  • POST 将客户端数据发送到一个服务器网关应用程序
  • HEAD 仅发送命名资源相应中的HTTP首部

状态码:每条HTTP相应报文返回时都会携带一个状态码,状态码是一个三位数字的代码。告知客户端请求是否成功,或者是否需要采取其他动作。

HTTP报文都是纯文本,由一行一行的字符串组成。

HTTP报文由三部分组成:起始行,首部字段,主体。

HTTP是一个应用协议层,无需操心网络通信的具体细节,而是交给TCP/IP协议。

TCP提供了:

  • 无差错的数据传输;
  • 按需传输(数据总是会按照发送的顺序到达);
  • 未分段的数据流(可以在任意时刻以任意尺寸将数据发送出去)。

只要建立了TCP链接,客户端和服务器之间的报文交换就不会丢失,不会破坏,也不会在接收时出现错序了。

在HTTP客户端向服务器发送报文之前,需要用IP地址和端口号在客户端和付钱之间建立一条TCP/IP连接。

在TCP中,需要知道服务器的IP地址以及在服务器上允许的特定软件的相关TCP端口号。服务器的IP地址和端口号是依靠URL获取的。HTTP的URL中没有端口号时,可以假设默认端口号是80。

具体的步骤:

  1. 浏览器从URL中解析出服务器的主机名
  2. 浏览器将服务器的主机名转换成服务器的IP地址
  3. 浏览器将端口号从URL中解析出来
  4. 浏览器建立一条与Web服务器的TCP连接
  5. 浏览器向服务器发送一条HTTP请求报文
  6. 服务器向浏览器回送一条HTTP响应报文
  7. 关闭连接,浏览器显示文档

协议版本

HTTP/0.9
HTTP的1991原型版本称为HTTP/0.9。这个协议有很多严重的设计缺陷,只应该用于与老客户端的交互。HTTP/0.9只支持GET方法,不支持多媒体内容的MIME类型、各种HTTP首部或者版本号。

HTTP/1.0

1.0是第一个得到广泛使用的HTTP版本。HTTP/1.0添加了版本号,各种HTTP首部,一些额外的方法,以及对多媒体对象的处理。

HTTP/1.0+

在20世纪90年代中叶,很多流行的Web客户端和服务器都在飞快的向HTTP中添加各种特性,以满足需要。这种非正式的HTTP扩展版本通常称为HTTP/1.0+

HTTP/1.1

HTTP/1.1重点关注的是校正HTTP设计中的结构性缺陷,明确语义,引入重要的性能优化措施,并删除一些不好的特性。HTTP/1.1是当前使用的HTTP版本。

HTTP-NG(又名HTTP/2.0)

HTTP-NG是HTTP/1.1后继结构的原型建议,它重点关注的是性能的大幅优化,以及更强大的服务器逻辑远程执行框架。

Web的结构组件

代理:位于客户端和服务器之间的HTTP中间实体。接收所有客户端的HTTP请求,并将这些请求转发给服务器。
缓存:HTTP的仓库,使常用页面的副本可以保存在离客户端更近的地方。客户端从附近的缓存下载文档会比从远程Web服务器下载快得多。
网关:连接其他应用程序的特殊Web服务器。
隧道:对HTTP通信报文进行盲转发的特殊代理。
Agent代理:发起自动HTTP请求的半智能Web客户端。

状态码

  • 100-199 信息提示
  • 200-299 成功
  • 300-399 重定向
  • 400-499 客户端错误
  • 500-599 服务器错误

HTTP请求格式:
<method> <request-URL> <version>
<headers>
<entity-body>

HTTP相应格式:
<version> <status> <reason-phrase>
<headers>
<entity-body>

Roseluo

Roseluo

about tech and life.

8 日志
4 标签
GitHub Twitter DouBan
© 2017 Roseluo
由 Hexo 强力驱动
主题 - NexT.Muse