*args
and **kwargs
__new__
和__init__
的区别__init__
()看两个例子: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
的内存地址能够比较理解:java
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
注:具体的值在不一样电脑上运行时可能不一样。node
能够看到,在执行完a = 2
以后,a
引用中保存的值,即内存地址发生变化,由原来1
对象的所在的地址变成了2
这个实体对象的内存地址。python
而第2个例子a
引用保存的内存值就不会发生变化:mysql
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等则是能够修改的对象。(这就是这个问题的重点)linux
当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.因此第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感受.而第二个例子就不同了,函数内的引用指向的是可变对象,对它的操做就和定位了指针地址同样,在内存里进行修改.nginx
若是还不明白的话,这里有更好的解释: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-referencegit
这个很是的不经常使用,可是像ORM这种复杂的结构仍是会须要的,详情请看:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python程序员
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)|
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]
参考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block
这个也是python彪悍的特性.
自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时可以得到对象的类型.好比type(),dir(),getattr(),hasattr(),isinstance().
可能你见过列表推导时,却没有见过字典推导式,在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内部的名字,用来区别其余用户自定义的命名,以防冲突.
_foo
:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.
__foo
:这个有真正的意义:解析器用_classname__foo
来代替这个名字,以区别和其余类相同的命名.
或者: http://www.zhihu.com/question/19754941
.format在许多方面看起来更便利.对于%
最烦人的是它没法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:
"hi there %s" % name
可是,若是name刚好是(1,2,3),它将会抛出一个TypeError异常.为了保证它老是正确的,你必须这样作:
"hi there %s" % (name,) # 提供一个单元素的数组而不是一个参数
可是有点丑..format就没有这些问题.你给的第二个问题也是这样,.format好看多了.
你为何不用它?
%
(issue #4))http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format
这个是stackoverflow里python排名第一的问题,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python
这是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html
*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
就像你看到的同样,它能够传递列表(或者元组)的每一项并把它们解包.注意必须与它们在函数里的参数相吻合.固然,你也能够在函数定义或者函数调用时用*.
http://stackoverflow.com/questions/3394835/args-and-kwargs
这个AOP一听起来有点懵,同窗面阿里的时候就被问懵了...
装饰器是一个很著名的设计模式,常常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,咱们就能够抽离出大量函数中与函数功能自己无关的雷同代码并继续重用。归纳的讲,装饰器的做用就是为已经存在的对象添加额外的功能。
这个问题比较大,推荐: http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python
中文: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/3/README.html
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就能够被称为鸭子。”
咱们并不关心对象是什么类型,究竟是不是鸭子,只关心行为。
好比在python中,有不少file-like的东西,好比StringIO,GzipFile,socket。它们有不少相同的方法,咱们把它们看成文件使用。
又好比list.extend()方法中,咱们并不关心它的参数是否是list,只要它是可迭代的,因此它的参数能够是list/tuple/dict/字符串/生成器等.
鸭子类型在动态语言中常用,很是灵活,使得python不想java那样专门去弄一大堆的设计模式。
引自知乎:http://www.zhihu.com/question/20053359
函数重载主要是为了解决两个问题。
另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不一样之外,其功能是彻底相同的,此时才使用函数重载,若是两个函数的功能其实不一样,那么不该当使用重载,而应当使用一个名字不一样的函数。
好吧,那么对于状况 1 ,函数功能相同,可是参数类型不一样,python 如何处理?答案是根本不须要处理,由于 python 能够接受任何类型的参数,若是函数的功能相同,那么不一样的参数类型在 python 中极可能是相同的代码,没有必要作成两个不一样函数。
那么对于状况 2 ,函数功能相同,但参数个数不一样,python 如何处理?你们知道,答案就是缺省参数。对那些缺乏的参数设定为缺省参数便可解决问题。由于你假设函数功能相同,那么那些缺乏的参数终归是须要用的。
好了,鉴于状况 1 跟 状况 2 都有了解决方案,python 天然就不须要函数重载了。
这个面试官问了,我说了老半天,不知道他问的真正意图是什么.
这篇文章很好的介绍了新式类的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html
新式类很早在2.2就出现了,因此旧式类彻底是兼容的问题,Python3里的类所有都是新式类.这里有一个MRO问题能够了解下(新式类是广度优先,旧式类是深度优先),<Python核心编程>里讲的也不少.
__new__
和__init__
的区别这个__new__
确实不多见到,先作了解吧.
__new__
是一个静态方法,而__init__
是一个实例方法.__new__
方法会返回一个建立的实例,而__init__
什么都不返回.__new__
返回一个cls的实例时后面的__init__
才能被调用.__new__
,初始化一个实例时用__init__
.ps: __metaclass__
是建立类时起做用.因此咱们能够分别使用__metaclass__
,__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, *args, **kw): instances = {} def getinstance(): 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为了保证线程安全而采起的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.
解决办法就是多进程和下面的协程(协程也只是单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 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中实际上也存在一些垃圾,这些垃圾的回收会由于这种分代的机制而被延迟。
推荐: http://www.jianshu.com/p/J4U6rR
is是对比地址,==是对比值
推荐:Python 2.7.x 与 Python 3.x 的主要差别
super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
Note that the syntax changed in Python 3.0: you can just say super().__init__
() instead of super(ChildB, self).__init__
() which IMO is quite a bit nicer.
http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods
都在循环时使用,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.
其实全部的I/O都是轮询的方法,只不过实现的层面不一样罢了.
这个问题可能有点深刻了,但相信能回答出这个问题是对I/O多路复用有很好的了解了.其中tornado使用的就是epoll的.
基本上select有3个缺点:
poll改善了第一个缺点
epoll改了三个缺点.
关于epoll的: http://www.cnblogs.com/my_life/articles/3968782.html
实时调度算法:
缘由:
必要条件:
处理死锁基本方法:
推荐: http://www.ruanyifeng.com/blog/2014/11/compiler.html
Bulid过程能够分解为4个步骤:预处理(Prepressing), 编译(Compilation)、汇编(Assembly)、连接(Linking)
以c语言为例:
预编译过程主要处理那些源文件中的以“#”开始的预编译指令,主要处理规则有:
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程是整个程序构建的核心部分。
汇编器是将汇编代码转化成机器能够执行的指令,每一条汇编语句几乎都是一条机器指令。通过编译、连接、汇编输出的文件成为目标文件(Object File)
连接的主要内容就是把各个模块之间相互引用的部分处理好,使各个模块能够正确的拼接。 连接的主要过程包块 地址和空间的分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定位(Relocation)等步骤。
静态连接方法:静态连接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址肯定下来 静态库的连接可使用静态连接,动态连接库也可使用这种方法连接导入库
动态连接方法:使用这种方式的程序并不在一开始就完成动态连接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,而后等到某个时候,程序又须要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,因此,这种方式使程序初始化时间较短,但运行期间的性能比不上静态连接的程序
虚拟存储器是指具备请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储系统.
分页: 用户程序的地址空间被划分红若干固定大小的区域,称为“页”,相应地,内存空间分红若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。
分段: 将用户程序地址空间分红若干个大小不等的段,每段能够定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中能够不相邻接,也实现了离散分配。
边缘触发是指每当状态变化时发生一个 io 事件,条件触发是只要知足条件就发生一个 io 事件
数据库事务(Database Transaction) ,是指做为单个逻辑工做单元执行的一系列操做,要么彻底地执行,要么彻底地不执行。
推荐: http://tech.meituan.com/mysql-index.html
汇集索引,非汇集索引,B-Tree,B+Tree,最左前缀原理
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做
乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。
MyISAM 适合于一些须要大量查询的应用,但其对于有大量写操做并非很好。甚至你只是须要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都没法操做直到读操做完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。
InnoDB 的趋势会是一个很是复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,因而在写操做比较多的时候,会更优秀。而且,他还支持更多的高级应用,好比:事务。
注意: 中断链接端能够是客户端,也能够是服务器端. 下面仅以客户端断开链接举例, 反之亦然.
地址解析协议(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方法具备幂等性。
推荐: http://www.ruanyifeng.com/blog/2011/09/restful.html
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这个名字的由来)。 推荐: http://www.kegel.com/c10k.html
推荐: http://www.360doc.com/content/11/0609/15/5482098_122692444.shtml
Socket=Ip address+ TCP/UDP + port
推荐: http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html
304 Not Modified
推荐: http://blog.csdn.net/elifefly/article/details/3964766
AJAX,Asynchronous JavaScript and XML(异步的 JavaScript 和 XML), 是与在不从新加载整个页面的状况下,与服务器交换数据并更新部分网页的技术。
红黑树与AVL的比较:
AVL是严格平衡树,所以在增长或者删除节点的时候,根据不一样状况,旋转的次数比红黑树要多;
红黑是用非严格的平衡来换取增删节点时候旋转次数的下降;
因此简单说,若是你的应用中,搜索的次数远远大于插入和删除,那么选择AVL,若是搜索,插入删除次数几乎差很少,应该选择RB。
一只青蛙一次能够跳上1级台阶,也能够跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)
第二种记忆方法
def memo(func): cache = {} def wrap(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrap @memo def fib(i): if i < 2: return 1 return fib(i-1) + fib(i-2)
第三种方法
def fib(n): a, b = 0, 1 for _ in xrange(n): a, b = b, a + b return b
一只青蛙一次能够跳上1级台阶,也能够跳上2级……它也能够跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n < 2 else 2 * fib(n - 1)
咱们能够用2*1
的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1
的小矩形无重叠地覆盖一个2*n
的大矩形,总共有多少种方法?
第
2*n
个矩形的覆盖方法等于第2*(n-1)
加上第2*(n-2)
的方法。
f = lambda n: 1 if n < 2 else f(n - 1) + f(n - 2)
在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
使用Step-wise线性搜索。
def get_value(l, r, c): return l[r][c] def find(l, x): m = len(l) - 1 n = len(l[0]) - 1 r = 0 c = n while c >= 0 and r <= m: value = get_value(l, r, c) if value == x: return True elif value > x: c = c - 1 elif value < x: r = r + 1 return False
用集合
list(set(l))
用字典
l1 = ['b','c','d','b','c','a','a'] l2 = {}.fromkeys(l1).keys() print l2
用字典并保持顺序
l1 = ['b','c','d','b','c','a','a'] l2 = list(set(l1)) l2.sort(key=l1.index) print l2
列表推导式
l1 = ['b','c','d','b','c','a','a'] l2 = [] [l2.append(i) for i in l1 if not i in l2]
面试官提到的,先排序而后删除.
1->2->3->4
转换成2->1->4->3
.
class ListNode: def __init__(self, x): self.val = x self.next = None class Solution: # @param a ListNode # @return a ListNode def swapPairs(self, head): if head != None and head.next != None: next = head.next head.next = self.swapPairs(next.next) next.next = head return next return head
dict = {'name':'earth', 'port':'80'}
items=[('name','earth'),('port','80')] dict2=dict(items) dict1=dict((['name','earth'],['port','80']))
dict1={}.fromkeys(('x','y'),-1) dict={'x':-1,'y':-1} dict2={}.fromkeys(('x','y')) dict2={'x':None, 'y':None}
知乎远程面试要求编程
尾递归
def _recursion_merge_sort2(l1, l2, tmp): if len(l1) == 0 or len(l2) == 0: tmp.extend(l1) tmp.extend(l2) return tmp else: if l1[0] < l2[0]: tmp.append(l1[0]) del l1[0] else: tmp.append(l2[0]) del l2[0] return _recursion_merge_sort2(l1, l2, tmp) def recursion_merge_sort2(l1, l2): return _recursion_merge_sort2(l1, l2, [])
循环算法
def loop_merge_sort(l1, l2): tmp = [] while len(l1) > 0 and len(l2) > 0: if l1[0] < l2[0]: tmp.append(l1[0]) del l1[0] else: tmp.append(l2[0]) del l2[0] tmp.extend(l1) tmp.extend(l2) return tmp
去哪儿的面试,没作出来.
class ListNode: def __init__(self, x): self.val = x self.next = None def node(l1, l2): length1, lenth2 = 0, 0 # 求两个链表长度 while l1.next: l1 = l1.next length1 += 1 while l2.next: l2 = l2.next length2 += 1 # 长的链表先走 if length1 > lenth2: for _ in range(length1 - length2): l1 = l1.next else: for _ in range(length2 - length1): l2 = l2.next while l1 and l2: if l1.next == l2.next: return l1.next else: l1 = l1.next l2 = l2.next
def binarySearch(l, t): low, high = 0, len(l) - 1 while low < high: print low, high mid = (low + high) / 2 if l[mid] > t: high = mid elif l[mid] < t: low = mid + 1 else: return mid return low if l[low] == t else False if __name__ == '__main__': l = [1, 4, 12, 45, 66, 99, 120, 444] print binarySearch(l, 12) print binarySearch(l, 1) print binarySearch(l, 13) print binarySearch(l, 444)
def qsort(seq): if seq==[]: return [] else: pivot=seq[0] lesser=qsort([x for x in seq[1:] if x<pivot]) greater=qsort([x for x in seq[1:] if x>=pivot]) return lesser+[pivot]+greater if __name__=='__main__': seq=[5,6,78,9,0,-1,2,3,-65,12] print(qsort(seq))
def coinChange(values, money, coinsUsed): #values T[1:n]数组 #valuesCounts 钱币对应的种类数 #money 找出来的总钱数 #coinsUsed 对应于目前钱币总数i所使用的硬币数目 for cents in range(1, money+1): minCoins = cents #从第一个开始到money的全部状况初始 for value in values: if value <= cents: temp = coinsUsed[cents - value] + 1 if temp < minCoins: minCoins = temp coinsUsed[cents] = minCoins print('面值为:{0} 的最小硬币数目为:{1} '.format(cents, coinsUsed[cents]) ) if __name__ == '__main__': values = [ 25, 21, 10, 5, 1] money = 63 coinsUsed = {i:0 for i in range(money+1)} coinChange(values, money, coinsUsed)
给定一个数组,构建二叉树,而且按层次打印这个二叉树
## 14 二叉树节点 class Node(object): def __init__(self, data, left=None, right=None): self.data = data self.left = left self.right = right tree = Node(1, Node(3, Node(7, Node(0)), Node(6)), Node(2, Node(5), Node(4))) ## 15 层次遍历 def lookup(root): stack = [root] while stack: current = stack.pop(0) print current.data if current.left: stack.append(current.left) if current.right: stack.append(current.right) ## 16 深度遍历 def deep(root): if not root: return print root.data deep(root.left) deep(root.right) if __name__ == '__main__': lookup(tree) deep(tree)
深度遍历改变顺序就OK了
def maxDepth(root): if not root: return 0 return max(maxDepth(root.left), maxDepth(root.right)) + 1
def isSameTree(p, q): if p == None and q == None: return True elif p and q : return p.val == q.val and isSameTree(p.left,q.left) and isSameTree(p.right,q.right) else : return False
推荐: http://blog.csdn.net/hinyunsin/article/details/6315502
def rebuild(pre, center): if not pre: return cur = Node(pre[0]) index = center.index(pre[0]) cur.left = rebuild(pre[1:index + 1], center[:index]) cur.right = rebuild(pre[index + 1:], center[index + 1:]) return cur def deep(root): if not root: return deep(root.left) deep(root.right) print root.data
class Node(object): def __init__(self, data=None, next=None): self.data = data self.next = next link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9))))))))) def rev(link): pre = link cur = link.next pre.next = None while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre root = rev(link) while root: print root.data root = root.next
class Anagram: """ @:param s1: The first string @:param s2: The second string @:return true or false """ def Solution1(s1,s2): alist = list(s2) pos1 = 0 stillOK = True while pos1 < len(s1) and stillOK: pos2 = 0 found = False while pos2 < len(alist) and not found: if s1[pos1] == alist[pos2]: found = True else: pos2 = pos2 + 1 if found: alist[pos2] = None else: stillOK = False pos1 = pos1 + 1 return stillOK print(Solution1('abcd','dcba')) def Solution2(s1,s2): alist1 = list(s1) alist2 = list(s2) alist1.sort() alist2.sort() pos = 0 matches = True while pos < len(s1) and matches: if alist1[pos] == alist2[pos]: pos = pos + 1 else: matches = False return matches print(Solution2('abcde','edcbg')) def Solution3(s1,s2): c1 = [0]*26 c2 = [0]*26 for i in range(len(s1)): pos = ord(s1[i])-ord('a') c1[pos] = c1[pos] + 1 for i in range(len(s2)): pos = ord(s2[i])-ord('a') c2[pos] = c2[pos] + 1 j = 0 stillOK = True while j<26 and stillOK: if c1[j] == c2[j]: j = j + 1 else: stillOK = False return stillOK print(Solution3('apple','pleap'))