看两个例子:html
a = 1
def fun(a):
a = 2
fun(a)
print a # 1
复制代码
a = []
def fun(a):
a.append(1)
fun(a)
print a # [1]
复制代码
全部的变量均可以理解是内存中一个对象的“引用”,或者,也能够看似c中void*的感受。前端
经过id
来看引用a
的内存地址能够比较理解:python
a = 1
def fun(a):
print "func_in",id(a) # func_in 41322472
a = 2
print "re-point",id(a), id(2) # re-point 41322448 41322448
print "func_out",id(a), id(1) # func_out 41322472 41322472
fun(a)
print a # 1
复制代码
注:具体的值在不一样电脑上运行时可能不一样。mysql
能够看到,在执行完a = 2
以后,a
引用中保存的值,即内存地址发生变化,由原来1
对象的所在的地址变成了2
这个实体对象的内存地址。linux
而第2个例子a
引用保存的内存值就不会发生变化:nginx
a = []
def fun(a):
print "func_in",id(a) # func_in 53629256
a.append(1)
print "func_out",id(a) # func_out 53629256
fun(a)
print a # [1]
复制代码
这里记住的是类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而 list, dict, set 等则是能够修改的对象。(这就是这个问题的重点)git
当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.因此第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感受.而第二个例子就不同了,函数内的引用指向的是可变对象,对它的操做就和定位了指针地址同样,在内存里进行修改.程序员
若是还不明白的话,这里有更好的解释: stackoverflow.com/questions/9…github
这个很是的不经常使用,可是像ORM这种复杂的结构仍是会须要的,详情请看:stackoverflow.com/questions/1…web
Python其实有3个方法,即静态方法(staticmethod),类方法(classmethod)和实例方法,以下:
def foo(x):
print "executing foo(%s)"%(x)
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
a=A()
复制代码
这里先理解下函数参数里面的self和cls.这个self和cls是对类或者实例的绑定,对于通常的函数来讲咱们能够这么调用foo(x)
,这个函数就是最经常使用的,它的工做跟任何东西(类,实例)无关.对于实例方法,咱们知道在类里每次定义方法的时候都须要绑定这个实例,就是foo(self, x)
,为何要这么作呢?由于实例方法的调用离不开实例,咱们须要把实例本身传给函数,调用的时候是这样的a.foo(x)
(实际上是foo(a, x)
).类方法同样,只不过它传递的是类而不是实例,A.class_foo(x)
.注意这里的self和cls能够替换别的参数,可是python的约定是这俩,仍是不要改的好.
对于静态方法其实和普通的方法同样,不须要对谁进行绑定,惟一的区别是调用的时候须要使用a.static_foo(x)
或者A.static_foo(x)
来调用.
\ | 实例方法 | 类方法 | 静态方法 |
---|---|---|---|
a = A() | a.foo(x) | a.class_foo(x) | a.static_foo(x) |
A | 不可用 | A.class_foo(x) | A.static_foo(x) |
类变量:
是可在类的全部实例之间共享的值(也就是说,它们不是单独分配给每一个实例的)。例以下例中,num_of_instance 就是类变量,用于跟踪存在着多少个Test 的实例。
实例变量:
实例化以后,每一个实例单独拥有的变量。
class Test(object):
num_of_instance = 0
def __init__(self, name):
self.name = name
Test.num_of_instance += 1
if __name__ == '__main__':
print Test.num_of_instance # 0
t1 = Test('jack')
print Test.num_of_instance # 1
t2 = Test('lucy')
print t1.name , t1.num_of_instance # jack 2
print t2.name , t2.num_of_instance # lucy 2
复制代码
补充的例子
class Person:
name="aaa"
p1=Person()
p2=Person()
p1.name="bbb"
print p1.name # bbb
print p2.name # aaa
print Person.name # aaa
复制代码
这里p1.name="bbb"
是实例调用了类变量,这其实和上面第一个问题同样,就是函数传参的问题,p1.name
一开始是指向的类变量name="aaa"
,可是在实例的做用域里把类变量的引用改变了,就变成了一个实例变量,self.name再也不引用Person的类变量name了.
能够看看下面的例子:
class Person:
name=[]
p1=Person()
p2=Person()
p1.name.append(1)
print p1.name # [1]
print p2.name # [1]
print Person.name # [1]
复制代码
这个也是python彪悍的特性.
自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时可以得到对象的类型.好比type(),dir(),getattr(),hasattr(),isinstance().
a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print type(a),type(b),type(c) # <type 'list'> <type 'dict'> <type 'bool'>
print isinstance(a,list) # True
复制代码
可能你见过列表推导时,却没有见过字典推导式,在2.7中才加入的:
d = {key: value for (key, value) in iterable}
复制代码
>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
复制代码
__foo__
:一种约定,Python内部的名字,用来区别其余用户自定义的命名,以防冲突,就是例如__init__()
,__del__()
,__call__()
这些特殊方法
_foo
:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.不能用from module import * 导入,其余方面和公有同样访问;
__foo
:这个有真正的意义:解析器用_classname__foo
来代替这个名字,以区别和其余类相同的命名,它没法直接像公有成员同样随便访问,经过对象名._类名__xxx这样的方式能够访问.
详情见:这里
.format在许多方面看起来更便利.对于%
最烦人的是它没法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:
"hi there %s" % name
复制代码
可是,若是name刚好是(1,2,3),它将会抛出一个TypeError异常.为了保证它老是正确的,你必须这样作:
"hi there %s" % (name,) # 提供一个单元素的数组而不是一个参数
复制代码
可是有点丑..format就没有这些问题.你给的第二个问题也是这样,.format好看多了.
你为何不用它?
%
(issue #4))stackoverflow.com/questions/5…
这个是stackoverflow里python排名第一的问题,值得一看
这是中文版
这里有个关于生成器的建立问题面试官有考: 问: 将列表生成式中[]改为() 以后数据结构是否改变? 答案:是,从列表变为生成器
>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000028F8B774200>
复制代码
经过列表生成式,能够直接建立一个列表。可是,受到内存限制,列表容量确定是有限的。并且,建立一个包含百万元素的列表,不只是占用很大的内存空间,如:咱们只须要访问前面的几个元素,后面大部分元素所占的空间都是浪费的。所以,没有必要建立完整的列表(节省大量内存空间)。在Python中,咱们能够采用生成器:边循环,边计算的机制—>generator
*args
and **kwargs
用*args
和**kwargs
只是为了方便并无强制使用它们.
当你不肯定你的函数里将要传递多少参数时你能够用*args
.例如,它能够传递任意数量的参数:
>>> def print_everything(*args):
for count, thing in enumerate(args):
... print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage
复制代码
类似的,**kwargs
容许你使用没有事先定义的参数名:
>>> def table_things(**kwargs):
... for name, value in kwargs.items():
... print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit
复制代码
你也能够混着用.命名参数首先得到参数值而后全部的其余参数都传递给*args
和**kwargs
.命名参数在列表的最前端.例如:
def table_things(titlestring, **kwargs)
复制代码
*args
和**kwargs
能够同时在函数的定义中,可是*args
必须在**kwargs
前面.
当调用函数时你也能够用*
和**
语法.例如:
>>> def print_three_things(a, b, c):
... print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat
复制代码
就像你看到的同样,它能够传递列表(或者元组)的每一项并把它们解包.注意必须与它们在函数里的参数相吻合.固然,你也能够在函数定义或者函数调用时用*.
引自知乎
函数重载主要是为了解决两个问题。
另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不一样之外,其功能是彻底相同的,此时才使用函数重载,若是两个函数的功能其实不一样,那么不该当使用重载,而应当使用一个名字不一样的函数。
好吧,那么对于状况 1 ,函数功能相同,可是参数类型不一样,python 如何处理?答案是根本不须要处理,由于 python 能够接受任何类型的参数,若是函数的功能相同,那么不一样的参数类型在 python 中极可能是相同的代码,没有必要作成两个不一样函数。
那么对于状况 2 ,函数功能相同,但参数个数不一样,python 如何处理?你们知道,答案就是缺省参数。对那些缺乏的参数设定为缺省参数便可解决问题。由于你假设函数功能相同,那么那些缺乏的参数终归是须要用的。
好了,鉴于状况 1 跟 状况 2 都有了解决方案,python 天然就不须要函数重载了。
这个面试官问了,我说了老半天,不知道他问的真正意图是什么.
这篇文章很好的介绍了新式类的特性:
新式类很早在2.2就出现了,因此旧式类彻底是兼容的问题,Python3里的类所有都是新式类.这里有一个MRO问题能够了解下(新式类继承是根据C3算法,旧式类是深度优先),<Python核心编程>里讲的也不少.
一个旧式类的深度优先的例子
class A():
def foo1(self):
print "A"
class B(A):
def foo2(self):
pass
class C(A):
def foo1(self):
print "C"
class D(B, C):
pass
d = D()
d.foo1()
# A
复制代码
按照经典类的查找顺序从左到右深度优先
的规则,在访问d.foo1()
的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),因此这时候调用的是A的foo1(),从而致使C重写的foo1()被绕过
__new__
和__init__
的区别这个__new__
确实不多见到,先作了解吧.
__new__
是一个静态方法,而__init__
是一个实例方法.__new__
方法会返回一个建立的实例,而__init__
什么都不返回.__new__
返回一个cls的实例时后面的__init__
才能被调用.__new__
,初始化一个实例时用__init__
.ps: __metaclass__
是建立类时起做用.因此咱们能够分别使用__metaclass__
,__new__
和__init__
来分别在类建立,实例建立和实例初始化的时候作一些小手脚.
单例模式是一种经常使用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。经过单例模式能够保证系统中一个类只有一个实例并且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。若是但愿在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
__new__()
在__init__()
以前被调用,用于生成实例对象。利用这个方法和类的属性的特色能够实现设计模式的单例模式。单例模式是指建立惟一对象,单例模式设计的类只能实例 这个绝对常考啊.绝对要记住1~2个方法,当时面试官是让手写的.
__new__
方法class Singleton(object):
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kw)
return cls._instance
class MyClass(Singleton):
a = 1
复制代码
建立实例时把全部实例的__dict__
指向同一个字典,这样它们具备相同的属性和方法.
class Borg(object):
_state = {}
def __new__(cls, *args, **kw):
ob = super(Borg, cls).__new__(cls, *args, **kw)
ob.__dict__ = cls._state
return ob
class MyClass2(Borg):
a = 1
复制代码
def singleton(cls):
instances = {}
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
@singleton
class MyClass:
...
复制代码
做为python的模块是自然的单例模式
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
复制代码
Python 中,一个变量的做用域老是由在代码中被赋值的地方所决定的。
当 Python 遇到一个变量的话他会按照这样的顺序进行搜索:
本地做用域(Local)→当前做用域被嵌入的本地做用域(Enclosing locals)→全局/模块做用域(Global)→内置做用域(Built-in)
线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采起的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务,python的多线程起到做用,但对于cpu密集型任务,python的多线程几乎占不到任何优点,还有可能由于争夺资源而变慢。
解决办法就是多进程和下面的协程(协程也只是单CPU,可是能减少切换代价提高性能).
简单点说协程是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户本身控制切换的时机,再也不须要陷入系统的内核态.
Python里最多见的yield就是协程的思想!能够查看第九个问题.
闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它一样提升了代码的可重复使用性。
当一个内嵌函数引用其外部做做用域的变量,咱们就会获得一个闭包. 总结一下,建立一个闭包必须知足如下几点:
感受闭包仍是有难度的,几句话是说不明白的,仍是查查相关资料.
重点是函数运行后并不会被撤销,就像16题的instance字典同样,当函数运行完后,instance并不被销毁,而是继续留在内存空间里.这个功能相似类里的类变量,只不过迁移到了函数上.
闭包就像个空心球同样,你知道外面和里面,但你不知道中间是什么样.
其实就是一个匿名函数,为何叫lambda?由于和后面的函数式编程有关.
推荐: 知乎
这个须要适当的了解一下吧,毕竟函数式编程在Python中也作了引用.
推荐: 酷壳
python中函数式编程支持:
filter 函数的功能至关于过滤器。调用一个布尔函数bool_func
来迭代遍历每一个seq中的元素;返回一个使bool_seq
返回值为true的元素的序列。
>>>a = [1,2,3,4,5,6,7]
>>>b = filter(lambda x: x > 5, a)
>>>print b
>>>[6,7]
复制代码
map函数是对一个序列的每一个项依次执行函数,下面是对一个序列每一个项都乘以2:
>>> a = map(lambda x:x*2,[1,2,3])
>>> list(a)
[2, 4, 6]
复制代码
reduce函数是对一个序列的每一个项迭代调用函数,下面是求3的阶乘:
>>> reduce(lambda x,y:x*y,range(1,4))
6
复制代码
引用和copy(),deepcopy()的区别
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d
输出结果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
复制代码
Python垃圾回收机制:Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,经过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,经过“分代回收”(generation collection)以空间换时间的方法提升垃圾回收效率。
PyObject是每一个对象必有的内容,其中ob_refcnt
就是作为引用计数。当一个对象有新的引用时,它的ob_refcnt
就会增长,当引用它的对象被删除,它的ob_refcnt
就会减小.引用计数为0时,该对象生命就结束了。
优势:
缺点:
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把全部能够访问到的对象打上标记,而后清扫一遍内存空间,把全部没标记的对象释放。
分代回收的总体思想是:将系统中的全部内存块根据其存活时间划分为不一样的集合,每一个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减少,存活时间一般利用通过几回垃圾回收来度量。
Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
举例: 当某些内存块M通过了3次垃圾收集的清洗以后还存活时,咱们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工做时,大多数状况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔至关长一段时间后才进行,这就使得垃圾收集机制须要处理的内存少了,效率天然就提升了。在这个过程当中,集合B中的某些内存块因为存活时间长而会被转移到集合A中,固然,集合A中实际上也存在一些垃圾,这些垃圾的回收会由于这种分代的机制而被延迟。
都在循环时使用,xrange内存性能更好。 for i in range(0, 20): for i in xrange(0, 20): What is the difference between range and xrange functions in Python 2.X? range creates a list, so if you do range(1, 10000000) it creates a list in memory with 9999999 elements. xrange is a sequence object that evaluates lazily.
数据库事务(Database Transaction) ,是指做为单个逻辑工做单元执行的一系列操做,要么彻底地执行,要么彻底地不执行。 完全理解数据库事务: www.hollischuang.com/archives/89…
汇集索引,非汇集索引,B-Tree,B+Tree,最左前缀原理
一般局限点来讲,Redis也以消息队列的形式存在,做为内嵌的List存在,知足实时的高并发需求。在使用缓存的时候,redis比memcached具备更多的优点,而且支持更多的数据类型,把redis看成一个中间存储系统,用来处理高并发的数据库操做
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做
乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。
全称是Multi-Version Concurrent Control,即多版本并发控制,在MVCC协议下,每一个读操做会看到一个一致性的snapshot,而且能够实现非阻塞的读。MVCC容许数据具备多个版本,这个版本能够是时间戳或者是全局递增的事务ID,在同一个时间点,不一样的事务看到的数据是不一样的。
innodb会为每一行添加两个字段,分别表示该行建立的版本和删除的版本,填入的是事务的版本号,这个版本号随着事务的建立不断递增。在repeated read的隔离级别(事务的隔离级别请看这篇文章)下,具体各类数据库操做的实现:
其中,写操做(insert、delete和update)执行时,须要将系统版本号递增。
因为旧数据并不真正的删除,因此必须对这些数据进行清理,innodb会开启一个后台线程执行清理工做,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫作purge。
经过MVCC很好的实现了事务的隔离性,能够达到repeated read级别,要实现serializable还必须加锁。
参考:MVCC浅析
MyISAM 适合于一些须要大量查询的应用,但其对于有大量写操做并非很好。甚至你只是须要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都没法操做直到读操做完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。
InnoDB 的趋势会是一个很是复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,因而在写操做比较多的时候,会更优秀。而且,他还支持更多的高级应用,好比:事务。
mysql 数据库引擎: MySQL存储引擎--MyISAM与InnoDB区别:
注意: 中断链接端能够是客户端,也能够是服务器端. 下面仅以客户端断开链接举例, 反之亦然.
地址解析协议(Address Resolution Protocol),其基本功能为透过目标设备的IP地址,查询目标的MAC地址,以保证通讯的顺利进行。它是IPv4网络层必不可少的协议,不过在IPv6中已再也不适用,并被邻居发现协议(NDP)所替代。
这个面试官确实问过,当时答的urllib2能够Post而urllib不能够.
GET和POST有什么区别?及为何网上的多数答案都是错的 知乎回答
get: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 post: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1
Cookie | Session | |
---|---|---|
储存位置 | 客户端 | 服务器端 |
目的 | 跟踪会话,也能够保存用户偏好设置或者保存用户名密码等 | 跟踪会话 |
安全性 | 不安全 | 安全 |
session技术是要使用到cookie的,之因此出现session技术,主要是为了安全。
nginx 相对 apache 的优势:
apache 相对nginx 的优势:
状态码 | 定义 |
---|---|
1xx 报告 | 接收到请求,继续进程 |
2xx 成功 | 步骤成功接收,被理解,并被接受 |
3xx 重定向 | 为了完成请求,必须采起进一步措施 |
4xx 客户端出错 | 请求包括错的顺序或不能完成 |
5xx 服务器出错 | 服务器没法完成显然有效的请求 |
403: Forbidden 404: Not Found
HTTPS握手,对称加密,非对称加密,TLS/SSL,RSA
CSRF重点在请求,XSS重点在脚本
HTTP方法的幂等性是指一次和屡次请求某一个资源应该具备一样的反作用。(注意是反作用)
GET http://www.bank.com/account/123456
,不会改变资源的状态,不论调用一次仍是N次都没有反作用。请注意,这里强调的是一次和N次具备相同的反作用,而不是每次GET的结果相同。GET http://www.news.com/latest-news
这个HTTP请求可能会每次获得不一样的结果,但它自己并无产生任何反作用,于是是知足幂等性的。
DELETE方法用于删除资源,有反作用,但它应该知足幂等性。好比:DELETE http://www.forum.com/article/4231
,调用一次和N次对系统产生的反作用是相同的,即删掉id为4231的帖子;所以,调用者能够屡次调用或刷新页面而没必要担忧引发错误。
POST所对应的URI并不是建立的资源自己,而是资源的接收者。好比:POST http://www.forum.com/articles
的语义是在http://www.forum.com/articles
下建立一篇帖子,HTTP响应中应包含帖子的建立状态以及帖子的URI。两次相同的POST请求会在服务器端建立两份资源,它们具备不一样的URI;因此,POST方法不具有幂等性。
PUT所对应的URI是要建立或更新的资源自己。好比:PUT http://www.forum/articles/4231
的语义是建立或更新ID为4231的帖子。对同一URI进行屡次PUT的反作用和一次PUT是相同的;所以,PUT方法具备幂等性。
SOAP(原为Simple Object Access Protocol的首字母缩写,即简单对象访问协议)是交换数据的一种协议规范,使用在计算机网络Web服务(web service)中,交换带结构信息。SOAP为了简化网页服务器(Web Server)从XML数据库中提取数据时,节省去格式化页面时间,以及不一样应用程序之间按照HTTP通讯协议,听从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种经过网络从远程计算机程序上请求服务,而不须要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通讯程序之间携带信息数据。在OSI网络通讯模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
总结:服务提供的两大流派.传统意义以方法调用为导向通称RPC。为了企业SOA,若干厂商联合推出webservice,制定了wsdl接口定义,传输soap.当互联网时代,臃肿SOA被简化为http+xml/json.可是简化出现各类混乱。以资源为导向,任何操做无非是对资源的增删改查,因而统一的REST出现了.
进化的顺序: RPC -> SOAP -> RESTful
CGI是通用网关接口,是链接web服务器和应用程序的接口,用户经过CGI来获取动态数据或文件等。 CGI程序是一个独立的程序,它能够用几乎全部语言来写,包括perl,c,lua,python等等。
WSGI, Web Server Gateway Interface,是Python应用程序或框架和Web服务器之间的一种接口,WSGI的其中一个目的就是让用户能够用统一的语言(Python)编写先后端。
官方说明:PEP-3333
在GFW里家常便饭的,呵呵.
中间人攻击(Man-in-the-middle attack,一般缩写为MITM)是指攻击者与通信的两端分别建立独立的联系,并交换其所收到的数据,使通信的两端认为他们正在经过一个私密的链接与对方直接对话,但事实上整个会话都被攻击者彻底控制。
所谓c10k问题,指的是服务器同时支持成千上万个客户端的问题,也就是concurrent 10 000 connection(这也是c10k这个名字的由来)。 推荐:
Socket=Ip address+ TCP/UDP + port
304 Not Modified
HTTP请求8种方法介绍 HTTP/1.1协议中共定义了8种HTTP请求方法,HTTP请求方法也被叫作“请求动做”,不一样的方法规定了不一样的操做指定的资源方式。服务端也会根据不一样的请求方法作不一样的响应。
GET GET请求会显示请求指定的资源。通常来讲GET方法应该只用于数据的读取,而不该当用于会产生反作用的非幂等的操做中。 GET会方法请求指定的页面信息,并返回响应主体,GET被认为是不安全的方法,由于GET方法会被网络蜘蛛等任意的访问。
HEAD HEAD方法与GET方法同样,都是向服务器发出指定资源的请求。可是,服务器在响应HEAD请求时不会回传资源的内容部分,即:响应主体。这样,咱们能够不传输所有内容的状况下,就能够获取服务器的响应头信息。HEAD方法常被用于客户端查看服务器的性能。
POST POST请求会 向指定资源提交数据,请求服务器进行处理,如:表单数据提交、文件上传等,请求数据会被包含在请求体中。POST方法是非幂等的方法,由于这个请求可能会建立新的资源或/和修改现有资源。
PUT PUT请求会身向指定资源位置上传其最新内容,PUT方法是幂等的方法。经过该方法客户端能够将指定资源的最新数据传送给服务器取代指定的资源的内容。
DELETE DELETE请求用于请求服务器删除所请求URI(统一资源标识符,Uniform Resource Identifier)所标识的资源。DELETE请求后指定资源会被删除,DELETE方法也是幂等的。
CONNECT CONNECT方法是HTTP/1.1协议预留的,可以将链接改成管道方式的代理服务器。一般用于SSL加密服务器的连接与非加密的HTTP代理服务器的通讯。
OPTIONS OPTIONS请求与HEAD相似,通常也是用于客户端查看服务器的性能。 这个方法会请求服务器返回该资源所支持的全部HTTP请求方法,该方法会用’*’来代替资源名称,向服务器发送OPTIONS请求,能够测试服务器功能是否正常。JavaScript的XMLHttpRequest对象进行CORS跨域资源共享时,就是使用OPTIONS方法发送嗅探请求,以判断是否有对指定资源的访问权限。 容许
TRACE TRACE请求服务器回显其收到的请求信息,该方法主要用于HTTP请求的测试或诊断。 HTTP/1.1以后增长的方法 在HTTP/1.1标准制定以后,又陆续扩展了一些方法。其中使用中较多的是 PATCH 方法: PATCH PATCH方法出现的较晚,它在2010年的RFC 5789标准中被定义。PATCH请求与PUT请求相似,一样用于资源的更新。两者有如下两点不一样: 但PATCH通常用于资源的部分更新,而PUT通常用于资源的总体更新。 当资源不存在时,PATCH会建立一个新的资源,而PUT只会对已在资源进行更新。
AJAX,Asynchronous JavaScript and XML(异步的 JavaScript 和 XML), 是与在不从新加载整个页面的状况下,与服务器交换数据并更新部分网页的技术。