Contents
  1. 1. Python_Advanced
    1. 1.1. 字符串的反转?
    2. 1.2. lambda函数
    3. 1.3. 删除下面list里面的重复元素
    4. 1.4. 手写一个函数,用来取出1—100中9的倍数或者有数字9的所有整数
    5. 1.5. 算法复杂度
    6. 1.6. tuple和list的转换
    7. 1.7. match()和search()的区别?
    8. 1.8. 简述Django重定向的原理?
    9. 1.9. Django调用模板过程?
    10. 1.10. 对cookie和session的理解
    11. 1.11. 单例模式的特点,手写一个单例模式
    12. 1.12. 左连接,右连接以及内连接的理解
    13. 1.13. 写出下列代码运行结果:
  2. 2. SQL
  3. 3. Web
    1. 3.1. 防御csrf攻击的常用方法
  4. 4. Re
    1. 4.1. 匹配一个IP地址
  5. 5. Django
  6. 6. Spider
  7. 7. Tornado
  8. 8. Flask
  9. 9. Other
    1. 9.1. 下面这段代码的输出结果是什么?
    2. 9.2. 下面这段代码的输出结果是什么?
    3. 9.3. 下面这段代码的输出结果将是什么?

Python_Advanced

字符串的反转?

1
2
3
4
5
6
7
8
9
10
# 方案一
A='abcdefg'
A[::-1]
# 方案二
b = ''
for i in A:
b = i + b
print b


lambda函数

1
2
3
add = lambda x,y:x+y
a = add(2,4)
print a


删除下面list里面的重复元素

1
2
3
A=[1,2,3,4,5,1,5]
B=set(A)
A=list(B)


手写一个函数,用来取出1—100中9的倍数或者有数字9的所有整数

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 num():
a = []
for i in range(1,100):
# 取的是整除9,(i-9)整除10,90-99之间带9的数
if i % 9 == 0 or (i-9) % 10 == 0 or ((i-90)>0 and (i-90)<9):
a.append(i)
print(a)
print("一共%d个数"%len(a))
num()
# 方案二
def start():
list = []
for i in range(1,101):
# 整除9,带有9字符的i
if i%9==0 or ("9" in str(i)):
print i
list.append(i)
print len(list)
start()


算法复杂度

算法复杂度包括时间复杂度和空间复杂度,空间复杂度现在考虑的情况很少,存储空间比较充裕,通常关注的都是时间复杂度

tuple和list的转换

1
2
3
4
a = (1, 2, 3, 4)
b = list(a)
c = tuple(b)
a = c


match()和search()的区别?

match函数只能够从字符串的开始位置进行匹配,search是可以匹配字符串的任意位置,但也是只会返回找到的第一个匹配的模式


下面代码会输出什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def f(x,l=[]):
for i in range(x): # 左闭右开,x=2,range(0, 1)
l.append(i*i)
print l
print id(l)
# f(x= 2)
f(2)
# f(x = 3, l = [3, 2, 1])
f(3,[3,2,1])
# f(x= 2)
f(3) # 如果列表没有定义值,会使用默认列表,默认列表是上个f(2)的返回值[0, 1]
# 输出
[0, 1]
140407520303368
[3, 2, 1, 0, 1, 4]
140407520442704
[0, 1, 0, 1, 4]
140407520303368


简述Django重定向的原理?

定义一个red1和一个red2,在浏览器中输入red1时,浏览器请求到服务器,服务器视图还是red1,返回浏览器一个302,浏览器接收到302,通过重定向再向服务器发送请求,此时请求的是red2,之后red2的结果再返回浏览器

Django调用模板过程?

配置项目urls,项目的urls包含应用的urls,应用中的urls指向应用中的视图中的某个函数,视图调用函数,函数再调用模板,模板再模板

对cookie和session的理解

cookie就是客户端存储数据的一种键值对,session是服务器存储数据的一种键值对。
浏览器先向服务器请求数据,发一个服务器向浏览器写cookie的信息,之后response就会对浏览器进行cookie的写操作,之后如果浏览器请求服务器,就用 cookie请求网站通过保存的id和服务器中的session的id进行匹配


单例模式的特点,手写一个单例模式

创建一个从始至终只有一个实例对象的类,可以用多种方式实现,模块,new方法,装饰器,元类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Nums(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Nums, cls).__new__(cls, *args, **kwargs)
return cls._instance
class MyClass(Nums):
a = 1
one = MyClass()
two = MyClass()
one == two # True
one is two # True
# 保证一个类永远只有一个实例对象
print(one)
print(id(one))
print(two)
print(id(two))
# 把类的实例和一个类变量 _instance 关联起来,如果cls._instance是None,则创建实例,否则直接返回cls._instance


左连接,右连接以及内连接的理解

左连接就是两个表匹配到的数据作为查询结果,左边表中特有的数据,对于右表中不存在的数据用空null填充

右连接和左连接相反,就是两个表匹配到的数据作为查询结果,右边表中特有的数据,对于左表中不存在的数据用空null填充

内连接就是两个表匹配到的数据作为查询结果,结果至少有一个匹配到的数据

写出下列代码运行结果:

1
2
3
4
5
6
7
8
9
10
11
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a # 浅拷,拷贝引用
c = copy.copy(a) # 浅拷,拷贝外层的内存地址
d = copy.deepcopy(a) # 深拷,拷贝每一层内存地址,称为深拷贝
a.append(5)
a[4].append('c')
print 'a = ', a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print 'b = ', b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] # 浅拷贝引用
print 'c = ', c = [1, 2, 3, 4, ['a', 'b', 'c']] # 列表里面的列表有c,因为浅拷贝的外层内存地址,但是列表里面的列表添加数据,对于浅拷的外层内存地址来说,是不变的,所以会输出[1, 2, 3, 4, ['a', 'b', 'c']](列表是可变的,列表里面的列表添加值,地址不变,所以只拷贝到外层的内存地址,又因为a里面添加值 ,相应的只拷贝到外层的内存地址所以不拷贝)
print 'd = ', d = [1, 2, 3, 4, ['a', 'b']]


SQL

Web

防御csrf攻击的常用方法

(1)对于重要操作不使用get请求方式

(2)采用post请求方式

(3)在post请求方式的表单中添加@{\%csrf_token}@

(4)输入验证码

Re

匹配一个IP地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 已知ip地址,1.0.0.1-255.255.255.255,配置路由时使用0.0.0.0
# 匹配第一个数:1-255
# 拆分匹配法
1-9 --> \d
10-99 --> [1-9]\d
100-199 --> 1\d{2}
200-249 --> 2[0-4]\d
250-255 --> 25[0-5]
# 结合正则
1-99 [1-9]?\d
1-199 1\d{2}|[1-9]?\d
1-249 2[0-4]\d|((1\d{2})|([1-9]?\d))
1-255 (25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))
# 最后的正则
((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))

Django

Spider

Tornado

Flask

Other

下面这段代码的输出结果是什么?

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def num_list(val, list=[]):
list.append(val)
return list
list1 = num_list(10)
list2 = num_list(123,[])
list3 = num_list('a')
# list[10]
# list[10, a]
list1 = num_list(10)
# 仅仅是传递了一个新的[]而已,不会把原先的替换掉
# list[123]
list2 = num_list(123,[])
# list[10, a]
list3 = num_list('a')
print "list1 = %s" % list1 # list[10, a]
print "list2 = %s" % list2 # list[123]
print "list3 = %s" % list3 # list[10, a]
上面代码输出结果是:
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']
很多人都会误认为list1=[10],list3=[‘a’],因为他们以为每次num_list被调用时,列表参数的默认值都将被设置为[].但实际上的情况是,新的默认列表只在函数被定义的那一刻创建一次。
当num_list被没有指定特定参数list调用时,这组list的值随后将被使用。这是因为带有默认参数的表达式在函数被定义的时候被计算,不是在调用的时候被计算。因此list1和list3是在同一个默认列表上进行操作(计算)的。而list2是在一个分离的列表上进行操作(计算)的。(通过传递一个自有的空列表作为列表参数的数值)。
num_list的定义可以作如下修改。
尽管,创建一个新的列表,没有特定的列表参数。
下面这段代码可能能够产生想要的结果。
def num_list(val, list=None):
if list is None:
list = []
list.append(val)
return list
通过上面的修改,输出结果将变成:
list1 = [10]
list2 = [123]
list3 = ['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
34
def multipliers():
return [lambda x : i * x for i in range(4)]
# 认为i是0 1 2 3,,,2*0,2*1,2*2,2*3
# m(2) --> m(x) 0 2 4 6 --> 错的
# 此时真值i已经被闭包成了3,,,3*2
# m(2) --> m(x) 6 6 6 6 --> 错的
print [m(2) for m in multipliers()]
你如何修改上面的multipliers的定义产生想要的结果?
上面代码输出的结果是[6, 6, 6, 6] (不是我们想的[0, 2, 4, 6])。
上述问题产生的原因是Python闭包的延迟绑定。这意味着内部函数被调用时,参数的值在闭包内进行查找。因此,当任何由multipliers()返回的函数被调用时,i的值将在附近的范围进行查找。那时,不管返回的函数是否被调用,for循环已经完成,i被赋予了最终的值3。
因此,每次返回的函数乘以传递过来的值3,因为上段代码传过来的值是2,它们最终返回的都是6。(3*2)碰巧的是,《The Hitchhiker’s Guide to Python》也指出,在与lambdas函数相关也有一个被广泛被误解的知识点,不过跟这个case不一样。由lambda表达式创造的函数没有什么特殊的地方,它其实是和def创造的函数式一样的。
下面是解决这一问题的一些方法。
一种解决方法就是用Python生成器。
def multipliers():
for i in range(4): yield lambda x : i * x
另外一个解决方案就是创造一个闭包,利用默认函数立即绑定。
def multipliers():
return [lambda x, i=i : i * x for i in range(4)]
还有种替代的方案是,使用偏函数:
from functools import partial
from operator import mul
def multipliers():
return [partial(mul, i) for i in range(4)]


下面这段代码的输出结果将是什么?

class Parent(object):
x = 1

class Child1(Parent):
pass

class Child2(Parent):
pass

print Parent.x, Child1.x, Child2.x
Child1.x = 2
print Parent.x, Child1.x, Child2.x
Parent.x = 3
print Parent.x, Child1.x, Child2.x

输出结果将是:

1 1 1
1 2 1
3 2 3

让很多人困惑或惊讶的是最后一行输出为什么是3 2 3 而不是 3 2 1.为什么在改变parent.x的同时也改变了child2.x的值?但与此同时没有改变Child1.x的值?

此答案的关键是,在Python中,类变量在内部是以字典的形式进行传递。

如果一个变量名没有在当前类下的字典中发现。则在更高级的类(如它的父类)中尽心搜索直到引用的变量名被找到。(如果引用变量名在自身类和更高级类中没有找到,将会引发一个属性错误。)

因此,在父类中设定x = 1,让变量x类(带有值1)能够在其类和其子类中被引用到。这就是为什么第一个打印语句输出结果是1 1 1

因此,如果它的任何一个子类被覆写了值(例如说,当我们执行语句Child.x = 2),这个值只在子类中进行了修改。这就是为什么第二个打印语句输出结果是1 2 1

最终,如果这个值在父类中进行了修改,(例如说,当我们执行语句Parent.x = 3),这个改变将会影响那些还没有覆写子类的值(在这个例子中就是Child2)这就是为什么第三打印语句输出结果是3 2 3

4、下面这段代码在Python2下输出结果将是什么?请解释。

def div1(x,y):
print “%s/%s = %s” % (x, y, x/y)

def div2(x,y):
print “%s//%s = %s” % (x, y, x//y)

div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)

在Python3下结果会有怎样的不同?(当然,假设上述打印语句被转换成Python3的语法)

在Python2中,上述代码输出将是

5/2 = 2
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

默认情况下,Python 2 自动执行整形计算如果两者都是整数。因此,5/2 结果是2,而5./2结果是2.5

注意,在Python2中,你可以通过增加以下引用来覆写这个行为。

from future import division

同时要注意的是,//操作符将总是执行整形除法,不管操作符的类型。这就是为什么即使在Python 2中5.0//2.0的结果是2.0。然而在Python3中,没有此类特性,

例如,在两端都是整形的情况下,它不会执行整形除法

因此,在Python3中,将会是如下结果:

5/2 = 2.5
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

5、下面代码的输出结果将是什么?

list = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]
print list[10:]

下面的代码将输出[],不会产生IndexError错误。就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。

例如,尝试获取list[10]和之后的成员,会导致IndexError.

然而,尝试获取列表的切片,开始的index超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。

这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致bug很难被追踪到。

6、考虑下列代码片段:

list = [ [ ] ] * 5
list # output?
list[0].append(10)
list # output?
list[1].append(20)
list # output?
list.append(30)
list # output?

2,4,6,8行将输出什么结果?试解释。

输出的结果如下:

[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]

解释如下:

第一行的输出结果直觉上很容易理解,例如 list = [ [ ] ] 5 就是简单的创造了5个空列表。然而,理解表达式list=[ [ ] ] 5的关键一点是它不是创造一个包含五个独立列表的列表,而是它是一个创建了包含对同一个列表五次引用的列表。只有了解了这一点,我们才能更好的理解接下来的输出结果。

list[0].append(10) 将10附加在第一个列表上。

但由于所有5个列表是引用的同一个列表,所以这个结果将是:

[[10], [10], [10], [10], [10]]

同理,list[1].append(20)将20附加在第二个列表上。但同样由于5个列表是引用的同一个列表,所以输出结果现在是:

[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].

作为对比, list.append(30)是将整个新的元素附加在外列表上,因此产生的结果是: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].

7、Given a list of N numbers。

给定一个含有N个数字的列表。

使用单一的列表生成式来产生一个新的列表,该列表只包含满足以下条件的值:

(a)偶数值
(b)元素为原始列表中偶数切片。

例如,如果list[2]包含的值是偶数。那么这个值应该被包含在新的列表当中。因为这个数字同时在原始列表的偶数序列(2为偶数)上。然而,如果list[3]包含一个偶数,

那个数字不应该被包含在新的列表当中,因为它在原始列表的奇数序列上。
对此问题的简单解决方法如下:

[x for x in list[::2] if x%2 == 0]

例如,给定列表如下:

list = [ 1 , 3 , 5 , 8 , 10 , 13 , 18 , 36 , 78 ]

列表生成式[x for x in list[::2] if x%2 == 0] 的结果是,

[10, 18, 78]

这个表达式工作的步骤是,第一步取出偶数切片的数字,

第二步剔除其中所有奇数。

给定以下字典的子类:

class DefaultDict(dict):
def missing(self, key):
return []

8、下面的代码能够运行么?为什么?

d = DefaultDict()
d[‘florp’] = 127

能够运行。

当key缺失时,执行DefaultDict类,字典的实例将自动实例化这个数列。