3+4j不是合法的Python表达式。(错)
Python集合可以包含相同的元素。(错)
在UTF-8编码中一个汉字需要占用3个字节。(错)
注意:
UTF-8 是变长的,1-6个字节。
少数是汉字每个占用3个字节,多数占用4个字节。
占用3个字节的汉字: 52156 个
占用4个字节的汉字: 64029 个
Python 3.x 支持使用中文作为变量名。(对)
函数中必须包含return语句。(错)
栈和队列的都具有先入后出的特点。(错)
定义类时实现类__eq__()方法,该类对象即可支持运算符==。(对)
(1) 下面的函数转换哪一个是正确的(语法均正确):BCD
A. int("ABcDef"); B. float('5')C. bool((3, 5, 7))D. str(5)
(2) 下面的函数,那些会输出1,2,3三个数字:
A.
for i in range(3):
print i
B.
aList = [0, 1, 2]
for i in aList:
print i+1
C.
i = 1
while i < 3:
print i
i = i + 1
D.
for i in range(3):
print i + 1
选 BD
(1) 以下叙述正确的是:d
a. continue语句的作用是结束整个循环的执行
b. 只能在循环体内和switch语句体内使用break语句
c. 在循环体内使用break语句或continue语句的作用相同
d. 从多层循环嵌套中退出时,只能使用goto语句
(2) Python如何定义一个函数:c
a. class ( arg1, arg2, ..., argN)
b. function (arg1, arg2, ..., argN)
c. def (arg1, arg2, ..., argN)
d. def ( arg1, arg2, ..., argN)
(3) 下面哪个函数能够在linux环境下创建一个子进程:b
a. os.popen b. os.fork c. os.system d. os.link
(4) 已知x=43, ch='A', y=1,则表达式(x>=y and ch<'B' and y)的值是:b
a. 0 b. 1 c. 出错 d. True("真")
(5) 下面的语句哪个会无限循环下去:b
其中range函数原型为range([start], stop[, step])
a.
for a in range(10):
time.sleep(10)
b.
while 1 < 10:
time.sleep(10)
c.
while True:
break
d.
a = [3,-1,5,7]
for i in a[:]:
if a > 10:
break
(6) 下列表达式中返回为True的是:
a. 3 > 2 > 2 b. 'abc' > 'xyz' c. 0x56 < 56 d. (3,2) < ('a','b')
注意:
python2中,d的返回是True。
python3中,全部返回False。
(7) Python不支持的数据类型有:a
a. char b. int c. float d. list
(1) 以下函数需要在其中引入一个全局变量k,请填写语句:
def func():
___________ global k
k = k + 1;
(2) 请把以下函数转化为Python Lambda匿名函数:
def add(x, y):
return x+y
_______________ add = lambda x, y: x + y
已知列表x=[1,2,3],那么执行语句x.insert(1,4)只有,x的值为 [1,4,2,3]
已知字符串x='hello world',那么执行语句x.replace('hello','hi')之后,x的值为'hi world'
获取随机数的方法:Math.random
python中基本数据结构的操作
元组由偏移量(位置)访问的不易变对象引用序列。
列表是由偏移量(位置)访问的对象引用易变序列。
字典是由键(不是位置)访问的对象引用的易变映射,是未排序的表。
集合是 唯一 和 一成不变 对象的易变(可改变的)和无序聚集。
-------------------------------------------------------
新增 arr = (0, 1, 2)
arr = [0, 1, 2]
info = {'a': 1, 'b': 2}
info = set([1, 2, 3])
-------------------------------------------------------
更改 -
arr[0] = 5
info['a'] = 5
-
-------------------------------------------------------
删除 -
arr.remove(1)
arr.clear()
info.pop('a')
info.clear()
info.pop()
info.remove(1)
tuple和list的区别
1) list中是可变的,tuple不可变
2) 定义只有一个元素的tuple的时候,必须加逗号,否则不会被认为是tuple,而被识别为括号
3) 元组可以转列表,但不可以转字典
python里面如何实现tuple和list的转换
1) tuple(seq)
把所有可迭代的(iterable)序列转换成一个tuple, 元素不变,排序也不变。
2) list(seq)
把所有的序列和可迭代的对象转换成一个list,元素不变,排序也不变。
list和dict两种结构的区别
list 是以动态数组(Array)实现的。
最大的开销发生在超过当前分配大小的增长,这种情况下所有元素都需要移动;或者是在起始位置附近插入或者删除元素,这种情况下所有在该位置后面的元素都需要移动。
如果你需要在一个队列的两端进行增删的操作,应当使用collections.deque(双向队列)
list是对象的序列,list 中的元素可以是同构,也可以异构的。
以完全随机的列表考虑平均情况。
操作 平均情况 最坏情况
--------------------------------------
复制 O(n) O(n)
append[注1] O(1) O(1)
插入 O(n) O(n)
取元素 O(1) O(1)
更改元素 O(1) O(1)
删除元素 O(n) O(n)
遍历 O(n) O(n)
取切片 O(k) O(k)
删除切片 O(n) O(n)
更改切片 O(k+n) O(k+n)
extend[注1] O(k) O(k)
排序 O(n log n) O(n log n)
列表乘法 O(nk) O(nk)
x in s O(n)
min(s), max(s) O(n)
计算长度 O(1) O(1)
dict 是以哈希表(hash)实现的。
字典是无序的集合。
下列字典的平均情况基于以下假设:
(1) 对象的散列函数足够撸棒(robust),不会发生冲突。
(2) 字典的键是从所有可能的键的集合中随机选择的。
操作 平均情况 最坏情况
------------------------------------
复制 O(n) O(n)
取元素 O(1) O(n)
更改元素 O(1) O(n)
删除元素 O(1) O(n)
遍历 O(n) O(n)
用python将‘123456’反转为’654321’
def func(s):
return ''.join(reversed(list(s)))
func('123456')
使用python将字符串"1.2.3.4.5"转换为字符串"5|4|3|2|1"
>>> msg = '1.2.3.4.5'
>>> ''.join(reversed(list(msg.replace('.', '|'))))
'5|4|3|2|1'
将字符串: “k:1|k1:2|k2:3|k3:4”,处理成python字段: {k:1, k1:2, …}
dict(s.split(':') for s in "k:1|k1:2|k2:3|k3:4".split('|'))
输入一个字符串,返回倒序排列。如:string reverse(‘abcdef’),返回:‘fedcba’
def my_reverse(msg):
arr = list(msg)
s = ''.join(arr[::-1])
return s
对list进行切片的用法
取list的部分元素。
语法:
list[start:stop:step]
若step < 0,则stop < start。否则,返回[]。
若step = 0,则抛出ValueError。
若0 < step,则start < stop。否则,返回[]。
python代码得到列表list的交集与差集
交集:set(arr_01) & set(arr_02)
差集:set(arr_01) - set(arr_02) 或者 set(arr_02) - set(arr_01)
alist=[‘a’,‘b’,‘c’,‘d’,‘e’,‘f’], blist=[‘x’,‘y’,‘z’,‘d’,‘e’,‘f’]合并这2个list,并且元素不能重复。
list(set(alist, blist))
按升序合并如下两个list,并去除重复的元素
list1 = [2, 3, 8, 4, 9, 5, 6]
list2 = [5, 6, 10, 17, 11, 2]
def func(arr_a, arr_b):
''' 升序合并两个list,并去除重复的元素 '''
arr = []
arr.extend(arr_a)
arr.extend(arr_b)
arr = sorted(set(arr))
return arr
下面代码执行后的结果:
def f(x, l=[]):
for i in range(x):
l.append(i*i)
print l
>>> f(2) [0, 1]
>>> f(3, [3,2,1]) [3, 2, 1, 0, 1, 4]
>>> f(3) [0, 1, 0, 1, 4]
字典m={“a”:1, “b”:2},请用代码完成key和value的交换。
方法一:info = {v: k for k, v in m.items()}
方法二:m中,值有重复的。
import collections
info = collections.defaultdict(lsit)
for k, v in m.items():
info[v].append(k)
alist = [{‘name’:‘a’,‘age’:20}, {‘name’:‘b’,‘age’:30}, {‘name’:‘c’,‘age’:25}],按age由大到小排序
alist.sort(key=lambda obj: obj['age'], reverse=True)
阅读下面的代码,写出A0, A1至An的最终值
A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
A1 = range(10)
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
回答:
A0 {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
A1
py2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
py3: 迭代器对象range(0, 10)
A2 []
A3 [1, 2, 3, 4, 5]的队列,但顺序是随机的
A4 [1, 2, 3, 4, 5]
利用yield关键字的好处
yield每次调用都返回当前计算值,并在下一次调用时,将继续沿着上次的记忆进行。
1) 更节省存储空间
2) 响应更迅速
3) 使用更灵活
python中pass语句的作用是什么?
pass语句不会执行任何操作,一般作为占位符或者创建占位程序。
什么是lambda函数,有什么好处
lambda函数,是一种单行的匿名函数。
代码更为简洁,使用函数的定义方式更为直观,易理解。
python函数中经常有*args, **kwargs这两个参数
一种答法:
如果我们不确定往一个函数中传入多少参数,或者我们希望以元组(tuple)或者列表(list)的形式传参数的时候,我们可以使用*args(单星号)。
如果我们不知道往函数中传递多少个关键词参数或者想传入字典的值作为关键词参数的时候我们可以使用**kwargs(双星号)。
args、kwargs两个标识符是约定俗成的用法。
另一种答法:
当函数的参数前面有一个星号*号的时候表示这是一个可变的位置参数,两个星号**表示这个是一个可变的关键词参数。
星号*把序列或者集合解包(unpack)成位置参数,两个星号**把字典解包成关键词参数。
介绍以下except的用法和作用?
except是异常处理器,用于捕捉指定类型的异常。
Python的异常处理能力很强大的,可向用户准确反馈出错信息。
在Python中,异常也是对象,可对它进行操作。
所有异常都是基类 Exception的成员。
所有异常都从基类Exception继承,而且都在exceptions模块中定义。
Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。
一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。
如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。
语法:
try:
statements
except [type [as value]]:
statements
[except [type [as value]]:
statements]*
[else:
statements]
[finally:
statements]
如何用python输出一个Fibonacci数列?
>>> def fib_yield(n):
... a, b = 0, 1
... while 0 < n:
... yield a
... a, b = b, a+b
... n = n - 1
... yield a
...
>>> list( fib_yield(10) )
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
请写一段代码输出1到100的和。
>>> import functools
>>> functools.reduce(lambda x, y: x+y, range(1, 101))
5050
在函数中使用global关键字声明全局变量
>>> def func():
>>> global COUNT
>>> pass
python正则表达式提取字符串中的数字
s = '12j33jk12ksdjfkj23jk4h1k23h'
>>> fmt = r'\D*(\d+)\D*'
>>> arr = re.findall(fmt, s)
>>> [int(s) for s in arr if s]
[12, 33, 12, 23, 4, 1, 23]
python中search()和match()的区别
re.match():仅在字符串的开始处检查匹配,
re.search():检查匹配字符串中的任意位置(这是Perl默认执行的操作)。
使用正则表达式在 ‘’‘待处理’’'字符串中,获取OPTION的value属性值。注意:OPTION中可能有其他的标签属性,
如: 或者
>>> import re
>>> msg = '''\w*)[\"\'].*'''
>>> re.search(fmt, msg).groupdict()
{'value': '待处理'}
利用python打印前一天的本地时间,格式为’2017-03-24 16:55:44’
import datetime
yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
fmt = '%Y-%m-%d %H:%M:%S'
s = yesterday.strftime(fmt)
print(s)
如何理解python中字符串中的\字符
字符串中的\,是转义字符。
需要中字符串中使用特殊字符时,python用用反斜杠(\)转义字符。例如:
\ 在行尾时,是续行符
\\ 反斜杠符号
\' 单引号
列表中有n个正整数,范围在[0,1000],请编程对列表中的数据排序。
方法一:
def sort_arr_v1(arr):
''' 对列表中的数据排序,使用list.sort() '''
arr.sort()
return arr
方法二:
def sort_arr_v2(arr):
''' 对列表中的数据排序,使用快速排序 '''
_less = [] # 存储小于基准数的值
_greater = [] # 存储大于基准数的值
# 递归函数一定要有退出条件
if len(arr) <= 1:
return arr
# 基准数,直接获取src的最后一个
_pivot = arr.pop()
for _item in arr:
if _item <= _pivot:
_less.append(_item)
else:
_greater.append(_item)
# 这里用到了python的list是可以直接相加的特性
# 递归思想很重要,去处理列表中不止1个的
return sort_arr_v2(_less) + [_pivot] + sort_arr_v2(_greater)
python里面如何生成随机数?
方法一:
import random
print(random.randint(0, 9))
方法二:
import uuid
print(uuid.uuid4())
请举出三种常用的排序算法
快速排序、归并排序、堆排序、插入排序
任意一种排序方法的代码实现
时间复杂度 空间复杂度
类别 排序方法 ----------------------------------------------------------------稳定性
平均情况 最好 最坏 辅助存储
------------------------------------------------------------------------------------------
插入 直接插入 O(n**2) O(n) O(n**2) O(1) 稳定
shell排序 O(n**1.3) O(n) O(n**2) O(1) 不稳定
选择 直接排序 O(n**2) O(n**2) O(n**2) O(1) 不稳定
堆排序 O(n*log2(n)) O(n*log2(n)) O(n*log2(n)) O(1) 不稳定
交换 冒泡排序 O(n**2) O(n) O(n**2) O(1) 稳定
快速排序 O(n*log2(n)) O(n*log2(n)) O(n**2) O(n*log2(n)) 不稳定
归并排序 O(n*log2(n)) O(n*log2(n)) O(n*log2(n)) O(1) 稳定
基数排序 O(d(r+n)) O(d(n+rd)) O(d(r+n)) O(rd+n) 稳定
归并排序的代码:
def merge(left, right):
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
def merge_sort(lists):
# 归并排序
if len(lists) <= 1:
return lists
num = len(lists) / 2
left = merge_sort(lists[:num])
right = merge_sort(lists[num:])
return merge(left, right)
在扑克牌游戏中,需要实现一个查找顺子的算法
:(连续的数字即为顺子)
随机发N张牌,从中挑选最长顺子,并返回其长度,如果没有顺子返回0
int cards[16] = {12,3,4,10,6,5,6,8,11,9,11,11,9,12,1};
int getMaxShunZiLength(int cards[], int cardlen) {...}
(对于上面给出的数据,应该返回最长顺子:8, 9, 10, 11, 12的长度5)
def getMaxShunZiLength(cards, cardlen):
''' 查找顺子(连续的数字即为顺子) '''
arr = sorted(set(cards))
max_n, m = (0, len(arr))
for i in range(m-1):
n, j = (0, 1)
x = arr[i]
if x+1 == arr[i+1]:
# 有顺子
while i+j < m and x+j == arr[i+j]:
j = j + 1
if max_n < j:
max_n = j
return max_n
>>> cards = (12,3,4,10,6,5,6,8,11,9,11,11,9,12,1)
>>> getMaxShunZiLength(cards, len(cards))
有两个序列a, b,大小都为n,序列元素的值任意整型数,无序。
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
求解思路:
A = sum(a) - sum(b)
a[i]和b[j]进行交换后:
A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i])
= sum(a) - sum(b) - 2 * (a[i] - b[j])
= A - 2 * (a[i] - b[j])
设 x = a[i] - b[j],则
A' = A - 2x
x = (A - A') / 2
设 0 < A,则
1) x = (0..A)
x = A / 2,效果最好。
2) x 不属于(0..A)
则当前的a或者b,就是答案。
所以算法如下:
在a和b中寻找使得x=(0..A),并且最接近A/2的i和j,交换相应的i和j元素。
重新计算A后,重复前面的步骤,直到找不到(0..A)之间的x为止。
算法:
1)将2个序列合并为一个序列,并排序。为序列Source
2)拿出最大元素Big,次大元素Small。
3)在余下的序列Source[:-2]进行平分,得到序列max, min
4)将Small加到max序列,将Big加到min序列,重新计算序列和,和大的为max,小的为min。
def swap_balance(arr_a, arr_b):
''' 通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小 '''
N = len(arr_a)
sum_a = sum(arr_a)
sum_b = sum(arr_b)
# 计算序列和
diff = sum_a - sum_b
while diff != 0:
best_i = best_j = best_change = 0
for i in range(N):
for j in range(N):
change = arr_a[i] - arr_b[j]
if abs(diff - 2 * change) < abs(diff - 2 * best_change):
best_change = change
best_i = i
best_j = j
if best_change == 0:
return False
arr_a[best_i], arr_b[best_j] = arr_b[best_j], arr_a[best_i]
# 重新计算序列和
sum_a -= best_change
sum_b += best_change
diff = sum_a - sum_b
return true
用Python匹配HTML tag的时候,<.>和<.?>有什么区别?
在正则表达式中:
r'<.*>'是贪婪匹配,表示尽可能多的匹配。
r'<.*?>'是非贪婪匹配,表示尽可能少的匹配。
例如:
字符串:def
r'<.*>'的匹配结果,是全部。
r'<.*?>'的匹配结果,是''和''。
利用正则表达式从一段html文本中提取多个字段值
>>> import re
>>>
>>> content = '''
>>>
>>> 浙江省主题介绍
>>> 贵州省主题介绍
>>>
>>> '''
>>>
>>> # 获取之间的内容
>>> print('获取链接文本内容:')
获取链接文本内容:
>>> res = r'(.*?)'
>>> m = re.findall(res, content, re.S|re.M)
>>> for value in m:
... print(value)
...
浙江省主题介绍
贵州省主题介绍
>>>
>>> # 获取所有链接所有内容
>>> print('获取完整链接内容:')
获取完整链接内容:
>>> urls = re.findall(r"", content, re.I|re.S|re.M)
>>> for i in urls:
... print(i)
...
浙江省主题介绍
贵州省主题介绍
>>>
>>> # 获取中的URL
>>> print('获取链接中URL:')
获取链接中URL:
>>> res_url = r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')"
>>> link = re.findall(res_url, content, re.I|re.S|re.M)
>>> for url in link:
... print(url)
...
https://www.baidu.com/articles/zj.html
https://www.baidu.com//articles/gz.html
用Python的正则表达式匹配时间信息
>>> import datetime
>>> import re
>>> msg = datetime.datetime.now().isoformat()
'2018-06-13T20:32:42.271286'
>>> fmt = r'''(?P\d+)-(?P\d+)-(?P\d+)T(?P\d+):(?P\d+):(?P\d+)\.(?P\d+)'''
>>> re.search(fmt, msg).groupdict()
{'minute': '32', 'microsecond': '271286', 'day': '13', 'year': '2018', 'month': '06', 'second': '42', 'hour': '20'}
请解释with关键字的用法
回答一:
with关键字的前提是类需要实现__enter__和__exit__
>>> with open("test.sh") as f:
... f.read()
回答二:
1) 术语
(1) 上下文管理协议(Context Management Protocol):
包含方法 __enter__() 和 __exit__(),支持该协议的对象要实现这两个方法。
(2) 上下文管理器(Context Manager):
支持上下文管理协议的对象,这种对象实现了 __enter__() 和 __exit__() 方法。
上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。
通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。
(3) 运行时上下文(runtime context):
由上下文管理器创建,通过上下文管理器的 __enter__() 和 __exit__() 方法实现。
__enter__() 方法在语句体执行之前进入运行时上下文,__exit__() 在语句体执行完后从运行时上下文退出。
with 语句支持运行时上下文这一概念。
(4) 上下文表达式(Context Expression):
with 语句中跟在关键字 with 之后的表达式,该表达式 要返回一个上下文管理器对象。
(5) 语句体(with-body):
with 语句包裹起来的代码块。
在执行语句体之前会调用上下文管理器的 __enter__() 方法,执行完语句体之后会执行 __exit__() 方法。
2) with 语句的语法格式如下:
with context_expression [as target(s)]:
with-body
3) 例子: 使用 with 语句操作文件对象
with open(r'somefileName') as somefile:
for line in somefile:
print line
# ...more code
用两种方法按行读取一个csv文件
方法一:
with open(f_name) as f:
for row in f:
pass
方法二:
import csv
with open(f_name, newline='') as f:
obj = csv.reader(f, delimiter=' ', quotechar="|")
for row in obj:
pass
dict的items()方法与iteritems()方法的不同
py2:
dict.items()
返回一个列表,其元素是 (键, 值)。
需要大量的内存,时间,生成列表对象。
之后取值时,速度快。
dict.iteritems()
返回一个迭代器。
需要少量的内存、时间,生成返回迭代器对象。
之后取值时,速度慢。需要调用next()函数。
py3:
dict.items()
返回一个迭代器。
dict.iteritems()
废弃。
写一个函数,能够遍历一个文件夹下的所有文件和子文件夹
import os
def func(s_path):
s_dir = os.path.abspath(s_path)
for root, dirs, files in os.walk(s_dir):
pass
一个函数接受文件夹的名称作为输入参数,返回该文件夹中所有文件的全路径。请补充缺失的代码。
def print_directory_contents(sPath):
import os
s_dir = os.path.abspath(sPath)
arr_file = [os.path.join(s_dir, s) for s in os.listdir(s_dir)]
arr = [
s
for s in arr_file
if os.path.isfile(s)
]
return arr
读取文本文件info.txt(100万个商户名称),打印重复的商户名称及重复的次数,并按重复次数排序输出。
# 可能有错误
import pandas as pd
df = pd.read_csv(f_name, sep=' ')
df.group_by('商户名称')['商户名称'].agg(['重复次数', 'count'])
df.sort_values(by=('重复次数', '商户名称'), ascending=False)
进程和线程之间有什么区别和联系? 做过多线程编程吗?线程加锁的作用是什么?
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
线程的划分尺度小于进程,使得多线程程序的并发性搞。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程(Process)是最初定义在Unix等多用户、多任务操作系统环境下用于表示应用程序在内存环境中基本执行单元的概念。以Unix操作系统为例,进程是Unix操作系统环境中的基本成分、是系统资源分配的基本单位。Unix操作系统中完成的几乎所有用户管理和资源分配等工作都是通过操作系统对应用程序进程的控制来实现的。
做过多线程编程。
线程加锁的作用:
串行操作,临界区的资源。
列举几种你曾经常用的python包并且解释其功能以及用法
1) uuid
# 获取随机数
s = uuid.uuid4().hex
2) datetime
# 获取当前时间
now = datetime.datetime.now()
# 获取前3天的时间
x = now - datetime.timedelta(days=3)
3) json
info = {'a': 1, 'b': 2}
# 序列化, msg的内容是无序的
msg = json.dumps(info, ensure_ascii=False)
# 反序列化
obj = json.loads(msg)
4) collections
有序字典
info = collections.OrderedDict([('a', 1), ('b', 2)])
# 序列化, msg的内容是有序的
msg = json.dumps(info, ensure_ascii=False)
5) requests
发生请求与传递参数
import requests
r = requests.get(url='http://www.163.com')
print(r.status_code)
print(r.text)
另外python在函数编程方面提供了些什么函数与语法?
(1) 装饰器
(2) map(function, iterable)
返回一个迭代器,对iterable的每个项应用function,并yield结果。
如果传递多个iterable参数,function必须接受这么多参数,并应用到从iterables并行提取的项中。
如果有多个iterable,迭代器在最短的iterable耗尽时停止。
(3) filter(function, iterable)
每次从iterable对象中取出一个元素作用于我们的function,如果function返回True就保留该元素,如果返回False就删除该元素。
(4) reduce(function, iterable[, initializer])
将两个参数的函数累加到序列的项中,从左到右,以便将序列减少为单个值。
(5) partial(func, *args, **kwords)
返回一个新的partial对象,该对象在调用时将采用位置参数args和关键字参数关键字调用的func。
如果提供多个参数调用,它们会被追加给 args。
如果提供额外的关键字参数,它们会扩展和覆盖 keywords。
参数传递使用的是传递引用还是传递值?为什么?
1) 不可变对象作为函数参数,相当于C系语言的值传递。
2) 可变对象作为函数参数,相当于C系语言的引用传递。
python中的变量是没有类型的,我们可以把它看做一个(*void)类型的指针,变量是可以指向任何对象的,而对象才是有类型的。
而且Python中的对象有不可变对象(number,string,tuple等)和可变对象之分(list,dict等)。
Python中函数参数的传递,是传递变量的值。
Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。
而变量是对象的一个引用(又称为名字或者标签),对象的操作都是通过引用来完成的。
如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。
如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。
当前目录下有一个5G左右大小的文件,文件中,每行一条日志,格式如下:
2017-01-01 12:12:12 "a=1&b=2&c=3"
2017-01-01 12:12:12 "a=1&b=2&c=3"
2017-01-01 12:12:12 "a=1&b=2&c=3"
2017-01-01 12:12:12 "a=1&b=2&c=3"
2017-01-01 13:12:12 "a=1&b=2&c=3"
2017-01-01 13:12:12 "a=1&b=2&c=3"
2017-01-01 14:12:12 "a=1&b=2&c=3"
请利用你所掌握的语言,筛选出和"2017-01-01 13:12:12"有关的数据。
def find_msg(f_name, msg):
with open(f_name) as f:
for row in f:
if row.startswith(msg):
yield row
def main():
f_name = 'a01.log'
msg = "2017-01-01 13:12:12"
try:
x = find_msg(f_name, msg)
for i, s in enumerate(x):
print('i: {}, s: {}'.format(i, s))
except Exception as e:
print('e: {}'.format(e))
if __name__ == '__main__':
main()
场景:一个大于内存的txt日志文件,如果统计出某个字符出现的次数,请简述。
文件以字符串模式打开,分块(256MB)依次读入内存。
对每块数据,统计该数据块中,某个字符出现的次数。
str.count(s)
场景:根据字符串来筛选股票,并将股票从CSV中读取导入到程序中,并返回结果。简述如何更快的返回结果。
使用正则表达式,筛选股票。
使用pandas库,从csv文件中读取数据。
Python2和Python3的区别
回答一:
01) 默认编码
py2: ascii
py3: UTF-8 (可以使用中文变量名)
02) 字符串
py2:
unicode Unicode文本
str 8位文本 和 二进制数据
py3:
str Unicode文本(ASCII或者其它)
bytes 二进制数据(包括编码的文本)
bytearray bytes的一种可变的变体
03) 整数
py2:
int 和 log
py3:
int(支持高精度整数运算)
04) 1/2的结果,py2是0,py3是0.5。
05) py3中,!= 取代 <>
06) True 和 False
py2: 两个全局变量(名字)
可以重新赋值。
py3: 两个关键字
永远指向两个固定的对象,不允许再被重新赋值。
06) print,exec 不再是语句(py2),而是函数(py3)。
07) py3中,以下方法返回迭代器对象:
range(), filter(), map(), zip(), dict.keys(), dict.values(), dict.items()等。
08) 迭代器 必须实现
py2: next()
py3: __next__()
09) import导入
py2: 默认使用相对路径
py3: 默认使用绝对路径
10) 类
py2:
旧式类
新式类,继承object
py3: 新式类
11) 多重继承中,搜索方法
py2:
旧式类: 深度优先
新式类: 广度优先
py3: 广度优先
12) 异常
py2:
except (Exception, ValueError), e:
py3:
except (Exception, ValueError) as e:
请分别描述Python2.x和Python3.x中,import包时的路径搜索顺序
import包时的路径搜索 sys.path:
1) 程序的主目录(包内导入)
2) PYTHONPATH目录(如果已经进行了设置)
3) 标准链接库目录
4) 如何.pth文件的目录(如果存在的话)
其中 包内导入 的方式:
py2 包内导入:
1) 当前目录
2) 上一个目录
3) 找不到,再往上找
py3 包内导入:
1) 绝对导入(默认)
跳过当前包,然后搜索sys.path。
2) 相对导入
先包内,再包外。
关于python程序的运行性能方面,有什么手段能提升性能?
01) 改进算法,降低时间复杂度。
02) 使用cprofiles库,监控代码的运行次数、时间。
03) 使用第三方包Numpy, SciPy, GPULib, PyPy, Cython, SchedSkin等。
04) 使用多进程、多线程、协程
05) 使用内建函数
06) 使用join()连接字符串
07) 使用多重赋值,交换变量
08) 尽量使用局部变量
09) 尽量使用in
10) 为无限循环使用 while 1
11) 使用列表推导式
12) 使用生成器
13) 使用itertools库
14) 排序列表,使用bitsect库
15) 优先级队列,使用headpq库
16) 使用dict和set测试成员
17) 理解python列表,实际上是一个数组。
18) 使用装饰器缓存结果
说明CPython的内存管理机制
引用计数
每一个Python对象都有一个引用计数器----用于记录有多少其他对象指向(引用)这个对象。它存储在变量 refcnt 中,并通过调用C宏Py_INCREF实现引用计数增加和Py_DECREF实现引用计数减少的操作。 Py_DECREF更复杂点,当引用计数器到零时,它会运行该对象的释放函数,回收该类型的对象。
通常以下两种情况你需要考虑这个宏定义:实现自己创建数据结构,或者修改已经存在的Python C API。如果你使用Python内置的数据结构,那么不需要任何操作。
如果想不增加引用计数,可以使用弱引用或 weakrefs 引用对象。 Weakrefs对于实现缓存和代理非常有用。
垃圾回收(GC)
引用计数是在Python 2.0之前管理对象生命周期的唯一方法。它有一个弱点,它不能删除循环引用的对象。 循环引用的最简单的例子是对象引用自身。
>>> arr = []
>>> arr.append(arr)
>>> del arr
通常情况下,可以避免使用循环引用对象,但是有时是不可避免的(例如:长时间运行的程序)。
为了解决这个问题,Python 2.0引入了新的垃圾回收机制。
新GC与其他语言运行时(如JVM和CLR)的GC的主要区别在于,它仅用于寻找存在引用计数的循环引用。
循环引用只能由容器对象创建,因此Python GC不会跟踪整数,字符串等类型。
GC将对象分为3代,每一代对象都有一个计数器和一个阈值。
当对象被创建时,阈值会被自动地指派为0,也就是第0代对象。
当计数器大于某个阀值,GC就会运行在当前对象代上,回收该对象。
没被回收的对象会被移至下一代,并且将相应的计数器复位。
下一代的对象保留在下一代。
注:
分代回收
Python将所有的对象分为0,1,2三代。
所有的新建对象都是0代对象。
当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象。
垃圾回收启动时,一定会扫描所有的0代对象。
如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。
当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。
链接:http://www.cnblogs.com/vamei/p/3232088.html
在Python 3.4之前,GC有一个致命缺点----每个对象重载了__del__()方法。
因为每个对象都可以相互引用,所以GC不知道该调用那个对象的__del__()方法,这会导致GC直接跳过这些对象。
具体详细信息可以参考 gc.garbage (https://docs.python.org/2/library/gc.html#gc.garbage) 并且循环引用需要编程人员手动打破。
Python3.4介绍了一种最终的解决方法finalization approach (https://docs.python.org/3/whatsnew/3.4.html#whatsnew-pep-442),现在的GC可以打破对象的循环引用,而不在使用gc.garbage介绍的方法去回收对象。
此外,值得一提的是,如果你确定你的代码没有创建循环引用(或者你不关心内存管理),那么你可以只依赖引用计数器自动管理内存,而不使用GC去管理内存。
python的程序会内存泄漏吗?说说有没有什么方法防止及检测内存泄漏?
2) 内存泄漏
python的程序,也会出现内存泄漏的问题。
(1) python对象的引用计数不为0
(2) python调用的c代码部分,存在内存泄漏
3) 防止及检测内存泄漏
(1) 防止内存泄漏
使用 python v3.4 及更高版本。
释放资源。
(2) 检测内存泄漏
<1> python代码
[1] objgraph
一个将图结构转化成png图片表示的工具。通过它,可以把对象的引用关系绘制成图片,为最终找到内存泄漏的对方提供最好的指导。
[2] pympler
Pympler是一个开发工具,用于在运行的Python应用程序中测量,监控和分析Python对象的内存行为。
<2> c代码
Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。
Valgrind由内核(core)以及基于内核的其他调试工具组成。
内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。
start = 'http://google.com'
queue = [start]
visited = {start}
while queue:
url = queue.pop(0)
print(url)
for next_url in extract_url(url):
if next_url not in visited:
queue.append(next_url)
visited.add(next_url)
多线程版:
from concurrent.futures import ThreadPoolExecutor
start = "http://google.com"
queue = [start]
visited = {start}
pool = ThreadPoolExecutor(10)
def func(url):
for next_url in extract_url(url):
if next_url not in visited:
queue.append(next_url)
visited.add(next_url)
while queue:
url = queue.pop(0)
pool.submit(func,url)
pool.shutdown(wait=True)
在类的方法定义中,'self’是怎样的一个参数
Python中,类的方法与普通的函数只有一个特别的区别————它们必须有一个额外的第一个参数名称。
但是在调用这个方法的时候,你不为这个参数赋值,Python会提供这个值。
这个特别的变量指对象本身,按照惯例它的名称是self。
当然我们也可以用其他任何名称来代替,只是规范和标准在那建议我们一致使用self。
self在Python里不是关键字。
self代表当前对象的地址。
self能避免非限定调用造成的全局变量。
例子:
创建了一个类MyClass,实例化 MyClass 得到了 obj 这个对象。
然后调用这个对象的方法 obj.method(arg1, arg2)。
这个过程中,Python 会自动转为 obj.mehod(MyObject, arg1, arg2)。
__new__和__init__的区别
__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
1.实例方法,static method(静态方法)和class method(类方法)
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()
# 调用foo函数,参数传入1
a.foo(1)
# 调用class_foo,参数传入1
A.class_foo(1)
# 调用static_foo,参数传入1
A.static_foo(1)
打印结果:
executing foo(<__main__.A object at 0x0000027A5D874248>, 1)
executing class_foo(, 1)
executing static_foo(1)
结论:
实例方法:
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
静态方法:
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:类和实例对象都可以调用。
类方法:
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:类和实例对象都可以调用。
2.请写一个函数,用于替换某个字符串的一个或某几个字符串
函数原型str.replace(str, oldString, newString)
例如:
>>> pstr = "Hello World!";
>>> afterReplaceStr = strreplace(pstr, " World", " Tom");
那么afterReplaceStr的值为"Hello Tom!"
方法一:使用字符串替换
def strreplace_v1(msg, key, value):
''' 替换某个字符串的一个或某几个字符串 '''
msg.replace(key, value)
return msg
方法二:使用正则表达式
import re
def strreplace_v2(msg, key, value):
''' 替换某个字符串的一个或某几个字符串 '''
m = re.compile(key)
ret = m.sub(value, msg)
return ret
方法三:自己写替换
def strreplace_v3(msg, key, value):
''' 替换某个字符串的一个或某几个字符串 '''
n = len(key)
# 使用python的str.index()
# i = msg.index(key)
# 使用手写的函数
i = str_index(msg, key)
j = i + n
ret = msg[:i] + value + msg[j:]
return ret
def str_index(msg, key):
''' 查找字符串key 在 字符串msg 中的位置
手写str.index()函数
'''
i = j = 0
n = len(msg)
m = len(key)
flag = False
while i < n and not flag:
# 检测第0位的字母
if msg[i] != key[0]:
i += 1
else:
# 相同,检测后续字母
for k in range(1, m):
if msg[i+k] != key[j+k]:
i += k + 1
break
else:
# 找到
return i
raise ValueError('substring not found')
range 和 xrange区别
range
python2 返回队列。
python3 返回生成器。
一边循环一边调用,每次只返回一个值。减少内存使用量。
xrange
python2 返回生成器。
python3 废弃。
type 和 instance 的区别
type 子类和父类,不相同
instance 子类和父类,相同
什么是可变对象,什么是不可变对象
可变对象:一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值;
不可变对象:一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象指向的值复制出来一份,然后做了修改后存到另一个地址上了,但是可变对象就不会做这样的动作,而是直接在对象所指的地址上把值给改变了,而这个对象依然指向这个地址。
copy 和 deepcopy 的区别
https://www.cnblogs.com/valorchang/p/11471133.html
首先深拷贝和浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样,也就是地址的复制还是值的复制的区别。
copy.copy:浅拷贝,构造一个新的复合对象,然后只拷贝第一层的简单对象(非集合对象,例如:tuple, list, set, dict)。
copy.deepcopy:深拷贝,构造一个新的复合对象,然后递归拷贝原始对象中的数据。
结论一:
不管深拷贝还是浅拷贝对不可变数据类型都是引用内存地址
不管深拷贝还是浅拷贝对可变数据类型都是会重新创建新的内存空间
结论二:
浅拷贝:
外层是不可变类型、不管内层是否可变都是引用拷贝
外层是可变类型,不管内层是否可变都会从新创建新的内存空间
深拷贝:
外层是不可变类型,会递归判断内层数据类型、如果可变则创建新的内存地址、都为不可变就是引用拷贝
外层是可变数据类型、不管内层是否可变都会创新新的内存地址、但是内部如果为可变则递归创建、不可变则为引用地址
总结:
浅拷贝:
浅拷贝只做最顶层的数据类型判断
如果顶层是可变类型则创建新的内存空间
如果顶层是不可变数据类型就是引用拷贝
深拷贝:
深拷贝做递归拷贝,可以递归拷贝所有的内部嵌套数据(可以理解为循环遍历做浅拷贝判断)
深拷贝递归拷贝遇到可变类型则创建新的内存空间
深拷贝递归拷贝遇到不可变数据类型就是拷贝的引用
请写出一段Python代码实现删除一个list里面的重复元素
def del_repeat(arr):
''' 删除list里面的重复元素 '''
visiter = set()
arr_repeat = []
for i in range(len(arr)):
x = arr[i]
if x in visiter:
arr_repeat.append(i)
else:
visiter.add(x)
if arr_repeat:
for i in reversed(arr_repeat):
del arr[i]
给定一个数组,其中该数组中的每个元素均为字符串,删除该数组中的空白字符串。
def func(arr):
''' 删除arr中的空白字符串 '''
visiter = set()
arr_del = [i for i in range(len(arr)) if not arr[i]]
if arr_del:
for i in reversed(arr_del):
del arr[i]
使用一个装饰器,查看函数的运行时间,有什么作用
装饰器的作用:(对修改关闭,对扩展开放)
装饰器本质上是一个Python函数。
它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
import time
def deco(func):
def wrapper(*args, **kwargs):
time_begin = time.time()
func(*args, **kwargs)
time_end = time.time()
t = time_end - time_begin
print('time is {}'.format(t))
return wrapper
补充下面函数代码
def deco(func):
补充代码部分
@deco
def myfunc2(a,b):
print(" myfunc(%s, %s) called." % (a, b))
return a+b
回答:
def deco(func):
def wrapper(*args, **kwargs):
ret = func(*args, **kwargs)
return wrapper
使用Python编写一个装饰器,打印被装饰函数的输入与输出
>>> def deco(func):
... def wrapper(*args, **kwargs):
... print('args: {}, kwargs: {}'.format(args, kwargs))
... ret = func(*args, **kwargs)
... print('ret: {}'.format(ret))
... return wrapper
...
>>> @deco
... def func(*args, **kwargs):
... msg = 'func(): ...'
... return msg
...
>>> func('abc', 123, a=1, b=2)
args: ('abc', 123), kwargs: {'a': 1, 'b': 2}
ret: func(): ...
>>>
创建一个装饰器把下面函數輸出的字符串首字母大写。
def deco(func):
def wrapper(*args, **kwargs):
msg = func(*args, **kwargs)
ret = msg[0].upper() + msg[1:]
return ret
return wrapper
@deco
def greetings(word="hi there"):
return word.lower()
什么是异步调用?并请用一段简单的代码(不限语言)实现异步调用。
异步调用:一个可以无需等待被调用函数的返回值就让操作继续进行的方法。
import functools
import time
import threading
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(args)
my_thread = threading.Thread(target=func, args=args, kwargs=kwargs)
my_thread.start()
return wrapper
@deco
def foo(x,y):
c = 0
while c < 5:
c = c + 1
print('x: {}, y: {}'.format(x, y))
time.sleep(1)
foo(123, 456)
给定一个无序的数值序列,找出其中第N大的数值。
最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1)。
使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n)。
有两个有序整型数组:A和B,都是从小到大排序。要求把A和B合并成数组C,且C也是有序的。例如A=[1,3,5,7…],B=[2,4,6,8…]。合并后C=[1,2,3,4,5,6,7,8…]。请写一个方法尽可能高效率的来实现(注:不调用系统提供的函数)。
def merge_arr(arr_a, arr_b):
''' 数组合并 '''
i = j = 0
n = len(arr_a)
m = len(arr_b)
arr_c = []
while i < n and j < m:
if arr_a[i] < arr_b[j]:
arr_c.append(arr_a[i])
i = i + 1
elif arr_a[i] > arr_b[j]:
arr_c.append(arr_b[j])
j = j + 1
else:
arr_c.extend([arr_a[i]] * 2)
i = i + 1
j = j + 1
if i < n:
arr_c.extend(arr_a[i:])
elif j < m:
arr_c.extend(arr_b[j:])
return arr_c
有一张商品购买记录表T,其中包含字段uid(用户id),pid(商品id),现在要统计即购买了商品A(即pid为A)又购买了商品B(即pid为B)的用户uid。请写出对应的SQL语句。
select t01.uid
from (
select uid
from T
where T.pid = A
) as t01
join
(
select uid
from T
where T.pid = B
) as t02
on t01.uid = t02.uid
;
如何列出表’test’内name域值不为’tecmint’,web_address域值为’test.com’的所有数据?
select * from test where name != 'tecmint' and web_address = 'test.com';
写出获得学生成绩报表的sql语句,涉及的数据库表如下
班级表(表名:classes):
class_id class_name
----------------------
1 1班
2 2班
3 4班
。课程表(表名:lesson):
lesson_id lesson_name
----------------------
1 语文
2 数学
3 化学
4 物理
。学生表(表名:student):
student_id student_name class_id
------------------------------------
1 张三 1
2 李四 2
3 王强 1
4 李明 3
。成绩表(表名:scores):
score_id student_id lesson_id score
---------------------------------------------
1 1 1 87
2 1 2 67
3 2 1 56
4 2 2 90
5 3 2 88
结果要求:
写出20个linux命令
login, logout, passwd, who, su, sudo
date, cal, echo, alias, bg, fg, cd, dirs, eval, exec, uname,
ls,
ps, kill,
history,
less, more, cat,
man, info, help,
source, export, ln, unlink, unset, set,
利用Python执行shell命令并取得返回结果
方法一:
import os
s_command = 'ls -ls'
os.system(s_command)
方法二:
import subprocess
arr_commend = ['ls', '-l']
ret = subprocess.run(arr_commend, stdout=subprocess.PIPE)
msg = ret.stdout.decode()
print(msg)
简述你使用的web框架中是如何实现MVC模式的
MVC 设计模式:
模型(M)是数据的表述。
它不是真正的数据,而是数据的接口。
使用模型从数据库中获取数据时,无需知道底层数据库错综复杂的知识。
模型通常还会为数据库提供一层抽象,这样同一个模型就能使用不同的数据库。
视图(V)是你看到的界面。
它是模型的表现层。
在电脑中,视图是你在浏览器中看到的 Web 应用的页面,或者是桌面应用的 UI。
视图还提供了收集用户输入的接口。
控制器(C)控制模型和视图之间的信息流动。
它通过程序逻辑判断通过模型从数据库中获取什么信息,以及把什么信息传给视图。
它还通过视图从用户那里收集信息,并且实现业务逻辑:变更视图,或者通过模型修改数据,或者二者兼具。
Django 严格遵守 MVC 模式,但是有自己的实现逻辑。
“C”部分由框架处理,多数时候,我们的工作在模型、模板和视图中,因此 Django 经常被称为 MTV 框架。
在 MTV 开发模式中:
M 表示“模型”,即数据访问层。
这一层包含所有与数据相关的功能:访问数据的方式、验证数据的方式、数据的行为、数据之间的关系。
T 表示“模板”,即表现层。
这一层包含表现相关的决策:在网页或其他文档类型中如何显示某个东西。
V 表示“视图”,即业务逻辑层。
这一层包含访问模型和选择合适模板的逻辑。可以把视图看做模型和模板之间的桥梁。
简述你熟悉的ORM框架的使用机制和实现原理
1) 数据库连接
2) sql的select, insert, update, delete
3) 定义Field。
4) 定义Model,实现属性的查找。
5) python的元类
metaclass = BaseModel
(1) python的类映射到数据库的表
(2) Model的字段映射到数据表的字段
(3) Model的动作映射到sql语句
在django中定义了两个模型,书籍和作者,书籍有3个字段,分别是title,author,pulish_time;作者有3个字段,分别为name,age,address,其中书籍和作者是多对多的关系,查看一个书籍的所有作者和某个作者的全部书籍。
class Author(models.Model):
''' 作者 '''
name = models.CharField(max_length=128, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
address = models.CharField(max_length=256, verbose_name='地址')
class Book(models.Model):
''' 书籍 '''
title = models.CharField(max_length=128, verbose_name='名称')
pulish_time = models.DateField(verbose_name='出版时间')
author = models.ManyToManyField(Author)
# 查看一个书籍的所有作者和某个作者的全部书籍
>>> obj_Book = Book.objects.get(pk=1)
>>> obj_Book.author.all()
>>> obj_Author = Author.objects.get(pk=1)
>>> obj_Book.book_set.all()
简述图片验证码的工作流程
1) 用户请求页码
2)服务器生成图片验证码,并记录在redis中
3)浏览器显示图片验证码
4)用户输入界面上的图片验证码
5)进行服务器端校验
MyISAM和InnoDB的区别
1) InnoDB支持事务,MyISAM不支持
对于InnoDB每一条SQL语言都默认封装成事务,自动提交。
这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
2) InnoDB支持外键,而MyISAM不支持。
对一个包含外键的InnoDB表转为MYISAM会失败;
3) InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。
但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。
因此,主键不应该过大,因为主键太大,其他索引也都会很大。
而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。
主键索引和辅助索引是独立的。
4) InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。
而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
5) Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;
如何理解Mysql主从库架构
复制原理:
Mysql 的复制是一个异步的复制过程,从一个MySQL节点(称之为Master)复制到另一个MySQL节点(称之Slave)。
在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,其中两个线程(SQL 线程和 I/O 线程)在 Slave 端,另外一个线程(I/O 线程)在 Master 端。
要实现 MySQL 的复制,首先必须打开 Master 端的 Binary Log,因为整个复制过程实际上就是 Slave 从 Master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。
看上去MySQL的Replication原理非常简单,总结一下:
每个从仅可以设置一个主。
主在执行sql之后,记录二进制log文件(bin-log)。
从连接主,并从主获取binlog,存于本地relay-log,并从上次记住的位置起执行sql,一旦遇到错误则停止同步。
从这几条Replication原理来看,可以有这些推论:
主从间的数据库不是实时同步,就算网络连接正常,也存在瞬间,主从数据不一致。
如果主从的网络断开,从会在网络正常后,批量同步。
如果对从进行修改数据,那么很可能从在执行主的bin-log时出现错误而停止同步,这个是很危险的操作。所以一般情况下,非常小心的修改从上的数据。
一个衍生的配置是双主,互为主从配置,只要双方的修改不冲突,可以工作良好。
如果需要多主的话,可以用环形配置,这样任意一个节点的修改都可以同步到所有节点。
简述HTTP协议下,一个HTTP请求的数据结构。简述HTTP与HTTPS协议的差异。
HTTP请求信息包括3部分:
第一部分:请求行(数据包中的一行内容)
请求行包括三部分内容:请求方式(get/post)、请求资源路径、协议的类型与版本。
第二部分:若干消息头(W3C定义的一些有特殊含义的键值对)
消息头的样式,比如:content-type=text/html;charset=utf-8。
服务器端与浏览器端都会遵守这些消息头的约定,且会自动生成,也可通过编程的方式生成。
第三部分:实体内容。
如果请求方式是post方式,请求参数及值会放在这里。
HTTP与HTTPS协议的差异
https协议需要到ca申请证书,一般免费证书很少,需要交费。
http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。
http的连接很简单,是无状态的。
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议 要比http协议安全。
请简述浏览器是如何获取一枚网页的
回答一:
1) 浏览器发出请求:
1) 识别URL
协议、域名、文件路径名、端口号
2) 查找ip地址
1) 查寻本地hosts
2) 若本地hosts没有,查寻本地域名服务器
3) 若本地域名服务器没有,本地域名服务器查寻根域名服务器
4) 返回域名对应的ip地址
3) 用http包,封装请求
应用层
4) 使用套接字(Socket)建立连接
运输层
用tcp包,封装http包。
tcp套接字:
源IP地址、源端口号、目的IP地址和目的端口号
tcp连接“3次握手”
5) 发送请求
在tcp连接“3次握手”中,第3次握手是,将请求发出。
6) 路由寻址
网络层
用ip包,封装tcp包。
(1) 搜索路由表,寻找能与目的主机IP地址完全匹配的表目。
如果找到,则把报文发送给下一跳节点。
(2) 搜索路由表,寻找能与目标网络号相匹配的表目。
如果找到,则把报文发送给下一跳节点。
(3) 搜索路由表,寻找“默认”的表目。
如果找到,则把报文发送给下一跳节点。
(4) 若没有找到,该数据报就不能被传送。
如果不能传送的数据报来自本机,那么一般会向生成数据报的应用程序返回一个“主机不可达”或“网络不可达”的错误。
7) 关闭连接
目标主机收到了请求后,自底向上地对该请求进行处理。
链路层把数据报传给网络层,网路层将TCP数据段通过对应的Socket传给应用程序。
应用程序处理请求后产生一个应答的HTTP报文,又经过了一层层的封装、一跳跳的传输到达了源主机。
回答二:
1) 在浏览器中,输入网址
2) 浏览器查找域名的ip地址
DNS查找过程如下:
浏览器缓存
浏览器会缓存DNS记录一段时间。 有趣的是,操作系统没有告诉浏览器储存DNS记录的时间,这样不同浏览器会储存个自固定的一个时间(2分钟到30分钟不等)。
系统缓存
如果在浏览器缓存里没有找到需要的记录,浏览器会做一个系统调用(windows里是gethostbyname)。这样便可获得系统缓存中的记录。
路由器缓存
接着,前面的查询请求发向路由器,它一般会有自己的DNS缓存。
ISP DNS 缓存
接下来要check的就是ISP缓存DNS的服务器。在这一般都能找到相应的缓存记录。
递归搜索
你的ISP的DNS服务器从跟域名服务器开始进行递归搜索,从.com顶级域名服务器到Facebook的域名服务器。一般DNS服务器的缓存中会有.com域名服务器中的域名,所以到顶级服务器的匹配过程不是那么必要了。
3) 浏览器给web服务器发送一个HTTP请求
因为像Facebook主页这样的动态页面,打开后在浏览器缓存中很快甚至马上就会过期,毫无疑问他们不能从缓存中读取,所以,浏览器将把一个请求发送到Facebook所在的服务器:
4) 服务的永久重定向响应
使用重定向的原因:
(1) 搜索引擎排名
(2) 缓存友好性
5) 浏览器跟踪重定向地址
6) 服务器“处理”请求
服务器接收到获取请求,然后处理并返回一个响应。
(1) Web 服务器软件
web服务器软件(像Apache2、Nginx和IIS)接收到HTTP请求,然后确定执行什么请求处理来处理它。
请求处理就是一个能够读懂请求并且能生成HTML来进行响应的程序(像ASP.NET,PHP,RUBY...)。
(2) 请求处理
请求处理阅读请求及它的参数和cookies。
它会读取也可能更新一些数据,并讲数据存储在服务器上。
然后,需求处理会生成一个HTML响应。
7) 服务器发回一个HTML响应
8) 浏览器开始显示HTML
9) 浏览器发送获取嵌入在HTML中的对象
10) 浏览器发送异步(AJAX)请求
JS中将一个变量强制改为浮点类型的方法parseFloat(String)
根据id获取元素的原生js方法:getElementById();
将文档声明为HTML5文档类型,需要在文档头添加:
Chrome浏览器的私有样式前缀:-webkit-
CSS3 设置圆角的属性名:border-radius
CSS3 中,#是根据 id来选择元素,.是根据class 来选择元素。
form标签特有的属性请列举三个:action, method, enctype, target
正则表达式中,$是什么意识:从字符串的末尾开始从后向前匹配
typeof'123'返回:number
display和position都有哪些值?分别列举一下这些值的用途
display:block/inline/inline-block /table/table-cell/none
position: relative/absolute/fixed/static
display:block;/*当前元素以块级形式显示,默认宽度为父元素,可设定宽高,换行显示*/
display:inline;/*当前元素以行内形式显示,默认宽度为内容宽度,不可设宽高,同行显示*/
display:inline-block;/*显示时,默认宽度为内容宽度,可设宽高,同行显示*/
display:table;/*显示规则和block相同,但是样式为table的样式*/
display:table-cell;/*以table 单元格的样式显示*/
display:none;/*元素小时,位置也不占*/
position:relative;/*当前元素被设为相对定位,元素在文档流中,百分比的参照物是元素本身*/
position:absolute;/*当前元素被设为绝对定位,元素脱离文档流,定位参照物:第一个定位祖先/根元素*/
position:fixed;/*当前元素被设为固定定位,默认宽度为内容宽度,脱离文档流,参照物是视窗*/
js中也会有排序的需求,用js实现一个标准的排序算法,对某个数字数组进行由低到高的排序。
function sort_01(a) {
var i,j;
for (i=0;ia[j+1]) {
temp = a[j+1];
a[j+1]=a[j];
a[j]=temp;
flag=1;
}
}
if(flag==0) break;
}
return a;
}
var b = [2,3,8,3,1,5];
sort_01(b);
console.log(b);
创建一个js类,模拟实现方法的重载。
function A() {
this.a=null;
this.b=null;
}
var pro = A.prototype;
//模拟重载
pro.add = function() {
if (arguments.length==1) {
console.log(arguments[0]);
}
if (arguments.length==2) {
result = arguments[0]+arguments[1];
console.log(result);
}
}
var a = new A();
a.add(1);
a.add(1,2);
请解释JSONP的工作原理
JSONP是处理跨域资源访问的。
JSONP的原理是利用html页面中的script标签可跨域的原理,利用