面试题笔记

 

range 返回的是list

函数内部global声明 修改全局变量

合并两个字典:update方法 dic1.update(dic2)

GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。
多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大

set 去重

*args **kargs 不定数量参数传递

range 在py2 py3 表现不一样 python2返回列表,python3返回迭代器,节约内存.


python2返回列表,python3返回迭代器,节约内存.

一句话解释什么样的语言能够用装饰器? 函数可以作为参数传递的语言,可以使用装饰器。

1、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别。
2、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例。
3、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。
4、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。

打开文件在进行读写的时候可能会出现一些异常状况,如果按照常规的f.open写法,我们需要try,except,finally,做异常判断,并且文件最终不管遇到什么情况,都要执行finally f.close()关闭文件,with方法帮我们实现了finally中f.close(当然还有其他自定义功能,有兴趣可以研究with方法源码)。

0-1随机小数:random.random(),括号中不传参。

group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。

沒有分组用group


>>> res=re.search(r">.*<",str)
>>> str='<div class="nam">中国</div>'
>>> res=re.findall(r'<div class=".*">.*?</div>')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: findall() takes at least 2 arguments (1 given)
>>> res=re.findall(r'<div class=".*">.*?</div>',str)
>>> res
['<div class="nam">\xe4\xb8\xad\xe5\x9b\xbd</div>']
>>> print(res)
['<div class="nam">\xe4\xb8\xad\xe5\x9b\xbd</div>']
>>> res=re.findall(r'<div class=".*">(.*?)</div>',str)
>>> print(res)
['\xe4\xb8\xad\xe5\x9b\xbd']
>>>

findall 正则有分组的话,只返回匹配的分组----只有FINDALL
为什么re.findall()中有分组时,只返回分组匹配到得内容?

findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

分组就是用一对圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。从正则表达式的左边开始看,看到的第一个左括号“(”表示第一个分组,第二个表示第二个分组,依次类推,需要注意的是,有一个隐含的全局分组(就是0),就是整个正则表达式。
分完组以后,要想获得某个分组的内容,直接使用group(num)和groups()函数去直接提取就行。


消除重复name select distinct name from student


20、python2和python3区别?列举5个

 

1、Python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')

Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,比如 print 'hi'

2、python2 range(1,10)返回列表,python3中返回迭代器,节约内存

3、python2中使用ascii编码,python中使用utf-8编码

4、python2中unicode表示字符串序列,str表示字节序列

python3中str表示字符串序列,byte表示字节序列

5、python2中为正常显示中文,引入coding声明,python3中不需要

6、python2中是raw_input()函数,python3中是input()函数

 

不可变数据类型:数值型、字符串型string和元组tuple不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址),如下图用id()方法可以打印对象的id。

可变数据类型:列表list和字典dict;允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。

 

immutable adj. 不可改变的; 永恒不变的;

1. 对象类型
不可变(immutable)对象类型
int
float
decimal
complex
bool
str
tuple
range
frozenset
bytes
可变(mutable)对象类型
list
dict
set
bytearray
user-defined classes (unless specifically made immutable)

a = 1
b = a
a = 2
print(b) #输出的结果是1 修改值类型的值,只是让它指向一个新的内存地址,并不会改变变量b的值。

不可变数据类型的优点就是内存中不管有多少个引用,相同的对象只占用了一块内存,但是它的缺点就是当需要对变量进行运算从而改变变量引用的对象的值时,由于是不可变的数据类型,所以必须创建新的对象,这样就会使得一次次的改变创建了一个个新的对象,不过不再使用的内存会被垃圾回收器回收

 

1 list_a = [1,2]
2 list_b = list_a
3 list_a[0] = 3
4 print(list_b) #此时的输出结果是[3,2]

从上面的程序中可以看出,进行两次a = [1, 2, 3]操作,两次a引用的地址值是不同的,也就是说其实创建了两个不同的对象,这一点明显不同于不可变数据类型,所以对于可变数据类型来说,具有同样值的对象是不同的对象,即在内存中保存了多个同样值的对象,地址值不同。


可变数据类型是允许同一对象的内容,即值可以变化,但是地址是不会变化的。但是需要注意一点,对可变数据类型的操作不能是直接进行新的赋值操作,比如说a = [1, 2, 3, 4, 5, 6, 7],这样的操作就不是改变值了,而是新建了一个新的对象,这里的可变只是对于类似于append、+=等这种操作。

可变数据类型赋值是产生新的对象


其实主要原因是元组内保存的是变量(也就是内存地址)。所以当变量指向对象发生变化时,如果导致变量发生变化(即不可变类型),此时元组保证该不可变类型不能修改。而如果当变量指向对象发生变化时,如果不会导致变量发生变化(即可变类型),此时元组中存储的该可变类型可以修改(因为变量本身并无变化)。


python中的不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象;

可变数据类型,允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。


列表、集合、字典都是属于可变数据类型


>>> a=[1,2,3]
>>> id(a)
139754386436248
>>> a[0]=2
>>> id(a)
139754386436248
>>> a
[2, 2, 3]
>>>


可变数据类型:当该数据类型对应变量的值发生变化时,对应内存地址并没有开辟新的内存,而是在原来的内存值上进行修改。
列表、集合、字典都是属于可变数据类型

不可变数据类型:当该数据类型对应变量的值发生变化时,原来内存中的值不变,而是会开辟一块新的内存,变量指向新的内存地址。
元祖、字符串、整型、浮点型、布尔型都是不可变数据类型


深拷贝和浅拷贝需要注意的地方就是可变元素的拷贝:

在浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样,这个是浅拷贝相对于深拷贝最根本的区别。


浅层元素(不可变)或深层元素(可变)


也可以这样理解:

深拷贝就是完全跟以前就没有任何关系了,原来的对象怎么改都不会影响当前对象

浅拷贝,原对象的list元素改变的话会改变当前对象,如果当前对象中list元素改变了,也同样会影响原对象。

浅拷贝就是藕断丝连

深拷贝就是离婚了

 

!!!字符串和list 都可以用set 去重

>>> s = "ajldjlajfdljfddd"
>>> set(s)
set(['a', 'j', 'l', 'f', 'd'])
>>> s=[12,22,33,12]
>>> set(s)
set([33, 12, 22])
>>>

>>> s
[1, 2, 3]
>>> s=[1,3,2]
>>> s.sort(reverse=False)
>>> s
[1, 2, 3]
>>>

默认sort 是从小到大排列


字典根据键从小到大排序

对dict_items进行排序

d = {'d1':2, 'd2':4, 'd4':1,'d3':3,}
res = sorted(d.items(),key=lambda d:d[1],reverse=True)
print(res)
[('d2', 4), ('d3', 3), ('d1', 2), ('d4', 1)]


对字典进行sorted ,返回字典键的排序
>>> dic={"name":"zs","age":18,"city":"深圳","tel":"1362626627"}
>>> sorted(dic)
['age', 'city', 'name', 'tel']
>>>

 

凡是在类中定义了这个__getitem__ 方法,那么它的实例对象(假定为p),可以像这样

p[key] 取值,当实例对象做p[key] 运算时,会调用类中的方法__getitem__。

一般如果想使用索引访问元素时,就可以在类中定义这个方法(__getitem__(self, key) )。

字典遍历,是遍历的KEY

>>> a
{'a': '1', 'b': '2', 'c': '3'}
>>> for key in a:
print(key+':'+a[key])
 
a:1
b:2
c:3
>>> for key in a.keys():
print(key+':'+a[key])
 
a:1
b:2
c:3


在使用上,for key in a和 for key in a.keys():完全等价。

 

利用collections库的Counter方法统计字符串每个字符出现的次数”kjalfj;ldsjafl;hdsllfdhg;lahfbl;hl;ahlf;h”

from collections import Counter


a = "kjalfj;ldsjafl;hdsllfdhg;lahfbl;hl;ahlf;h"
res = Counter(a)
print(res)
Counte()方法返回的是一个字典,字典中的值对应着前面每一个字符出现的次数:

>>> from collections import Counter
>>> a = "kjalfj;ldsjafl;hdsllfdhg;lahfbl;hl;ahlf;h"
>>> res=Counter(a)
>>> res
Counter({'l': 9, 'h': 6, ';': 6, 'f': 5, 'a': 4, 'd': 3, 'j': 3, 's': 2, 'b': 1, 'g': 1, 'k': 1})
>>>


>> a = "not 404 found 张三 99 深圳"
>>> import re
>>> re.sub("[a-zA-Z]","",a)
' 404 \xe5\xbc\xa0\xe4\xb8\x89 99 \xe6\xb7\xb1\xe5\x9c\xb3'
>>>
>>> print(re.sub("[a-zA-Z]","",a))
404 张三 99 深圳
>>> print(re.sub("[a-zA-Z1-9]","",a))
0 张三 深圳
>>> print(re.sub("[a-zA-Z0-9]","",a))
张三 深圳
>>> print(re.sub("[a-zA-Z0-9\s]","",a))
张三深圳
>>>

>>> re.split(r'[;,]',line)
['aaa bbb ccc', 'ddd\teee', 'fff']


>>> filter(lambda x:(x%2)==0 ,a)
[2, 4, 6, 8, 10]
>>> filter(lambda x:(x%2)!=0 ,a)
[1, 3, 5, 7, 9]


re.compile是将正则表达式编译成一个对象,加快速度,并重复使用。

30、a=(1,)b=(1),c=("1") 分别是什么类型的数据?

tuple int str


extend可以将另一个集合中的元素逐一添加到列表中,区别于append的整体添加


2. append() 方法向列表的尾部添加一个新的元素。只接受一个参数。
3. extend()方法只接受一个列表作为参数,并将该参数的每个元素都添加到原有的列表中

append 的是list 时,只会在原list 增加一个list元素
extend 会把list 每个元素添加到原list 后面

>>> a=[1.2]
>>> a.append([3,3,3])
>>> a
[1.2, [3, 3, 3]]
>>> a=[1.2]
>>> a.extend([3,3,3])
>>> a
[1.2, 3, 3, 3]
>>>

python:os.remove(文件名)
linux: rm 文件名

 

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2020, 7, 17, 11, 11, 25, 509182)
>>> a.strftime("%Y%m%d %H%M%S")
'20200717 111125'
>>>

 

>>> start_time = datetime.datetime.now()
>>> end_time = datetime.datetime.now()
>>> (end_time - start_time).seconds
7


34、数据库优化查询方法
外键、索引、联合查询、选择特定字段等等

.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

索引并不是越多越好,索引固然可 以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。

查询尽可能使用 limit 减少返回的行数, 减少数据传输时间和带宽浪费。

35、请列出你会的任意一种统计图(条形图、折线图等)绘制的开源库,第三方也行
pychart、matplotlib


(.*)是贪婪匹配,会把满足正则的尽可能多的往后匹配

(.*?)是非贪婪匹配,会把满足正则的尽可能少匹配


ORM,全拼Object-Relation Mapping,意为对象-关系映射。实现了数据模型与数据库的解耦,通过简单的配置就可以轻松更换数据库,而不需要修改代码只需要面向对象编程,orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句,所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可。

39、[[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]

列表推导式的骚操作
>>> a=[[1,2],[3,4],[5,6]]
>>> [j for i in a for j in i]
[1, 2, 3, 4, 5, 6]
>>>

嵌套循环!!!

 

join 的作用!!!可迭代,中间不包括两边加间加xx
>>> x="abc"
>>> y="def"
>>> x.join(y)
'dabceabcf'
>>>


try..except..else没有捕获到异常,执行else语句。

try..except..finally不管是否捕获到异常,都执行finally语句。

zip()函数在运算时,会以一个或多个序列(可迭代对象)做为参数,返回一个元组的列表。同时将这些序列中并排的元素配对。

 

zip()参数可以接受任何类型的序列,同时也可以有两个以上的参数;当传入参数的长度不同时,zip能自动以最短序列长度为准进行截取,获得元组。

>>> a=[1,2]
>>> zip(a)
[(1,), (2,)]
>>>

\d 数字

写5条常用sql语句

 

show databases;

show tables;

desc 表名;

select * from 表名;

delete from 表名 where id=5;

update students set gender=0,hometown="北京" where id=5

python3编码:
在python中,string是UTF-8编码的字节序列,是显示和处理文本的基础
*bytes是python用来存储UTF-8字符串的原始字节序列,用b''告诉python你处理的是原始字节串
*处理原始字节串,需要通过.decode()来获取字符串,原始字节串不包含编码方式,它们就是字节序列,一堆数字,所以要告诉python(把它解码成UTF字节串)
*python编码出错时,必须使用.encode()来获取所要的字节
python3默认编码为unicode,由str类型进行表示。二进制数据使用byte类型表示。
字符串通过编码转换成字节码,字节码通过解码成为字符串
encode:str --> bytes
decode:bytes --> str

 

提高python运行效率的方法
1、使用生成器,因为可以节约大量内存

2、循环代码优化,避免过多重复代码的执行

3、核心模块用Cython PyPy等,提高效率

4、多进程、多线程、协程

5、多个if elif条件判断,可以把最有可能先发生的条件放到前面写,这样可以减少程序判断的次数,提高效率

 

list=[2,3,5,4,9,6],从小到大排序,不许用sort,输出[2,3,4,5,6,9]
利用min()方法求出最小值,原列表删除最小值,新列表加入最小值,递归调用获取最小值的函数,反复操作。


写个单例模式:

def singletone(func):
def wrapper(*args,**kargs):
if hasattr(func,"abc"):
return getattr(func,"abc")
bb= func(*args,**kargs)
setattr(func,"abc",bb)
return bb
return wrapper

#eg A=singletone(A)

@singletone
class A():
age=99
def set_age(self,age):
A.age=age

a=A()
print(a)
b=A()
print(b)
C:\Python27\python.exe D:/pycharm/alex-learn/alex-singletone.py
<__main__.A instance at 0x000000000318BF48>
<__main__.A instance at 0x000000000318BF48>

重要:

def Singleton(cls):
_instance = {}

def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]

return _singleton


@Singleton
class A(object):
a = 1

def __init__(self, x=0):
self.x = x


a1 = A(2)
a2 = A(3)
print(a1)
print(a2)

特别注意上面的_instance中的变量的生存周期

简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。这样的一个函数我们称之为闭包。实际上闭包可以看做一种更加广义的函数概念。因为其已经不再是传统意义上定义的函数。

下面这个闭包的临时变量是很重要

def outer_func():
loc_list = []
def inner_func(name):
loc_list.append(len(loc_list) + 1)
print '%s loc_list = %s' %(name, loc_list)
return inner_func

clo_func_0 = outer_func()
clo_func_0('clo_func_0')
clo_func_0('clo_func_0')
clo_func_0('clo_func_0')
clo_func_1 = outer_func()
clo_func_1('clo_func_1')
clo_func_0('clo_func_0')
clo_func_1('clo_func_1')

clo_func_0 loc_list = [1]
clo_func_0 loc_list = [1, 2]
clo_func_0 loc_list = [1, 2, 3]
clo_func_1 loc_list = [1]
clo_func_0 loc_list = [1, 2, 3, 4]
clo_func_1 loc_list = [1, 2]

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。


在基本的python语法当中,一个函数可以随意读取全局数据,但是要修改全局数据的时候有两种方法:1 global 声明全局变量 2 全局变量是可变类型数据的时候可以修改


>>> a=1.2222
>>> round(a,2)
1.22
>>>

round 保留小数

301 Moved Permanently 永久重定向,资源已永久分配新URI
400 Bad Request
403 Forbidden
404 Not Found
500 Internal Server Error


删除字典中的内容 dic.pop("key") del dic["key"]

 

列出常见MYSQL数据存储引擎
InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。
MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。
MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表

计算代码运行结果,zip函数历史文章已经说了,得出[("a",1),("b",2),("c",3), ("d",4), ("e",5)]
zip 的结果可以直接用dict 生成字典

 

首先,我们先来了解一下,页面在接受图片的过程。

每张图片的显示是先由浏览器发送请求,然后服务器接受请求,返回请求内容。如果一个页面有上百张图片,哪怕是很小的图标,都需要经历一次这样的过程。那么,毋庸置疑,肯定会由于请求数量的增加让整个页面的加载速度降低。正应为如此,精灵图(sprite)应运而生,图片整合技术,将大量的小图标整合到一张图,从而减少服务器接收和发送请求的次数,提高页面的加载速度。
分别从前端、后端、数据库阐述web项目的性能优化
该题目网上有很多方法,我不想截图网上的长串文字,看的头疼,按我自己的理解说几点。


前端优化:
1、减少http请求、例如制作精灵图。
2、html和CSS放在页面上部,javascript放在页面下面,因为js加载比HTML和Css加载慢,所以要优先加载html和css,以防页面显示不全,性能差,也影响用户体验差。
后端优化:
1、缓存存储读写次数高,变化少的数据,比如网站首页的信息、商品的信息等。应用程序读取数据时,一般是先从缓存中读取,如果读取不到或数据已失效,再访问磁盘数据库,并将数据再次写入缓存。
2、异步方式,如果有耗时操作,可以采用异步,比如celery。
3、代码优化,避免循环和判断次数太多,如果多个if else判断,优先判断最有可能先发生的情况。
数据库优化:
1、如有条件,数据可以存放于redis,读取速度快。
2、建立索引、外键等。

 

为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

 

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

 

因此:跨域问题 是针对ajax的一种限制。


CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

1、session 在服务器端,cookie 在客户端(浏览器)。
2、session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效,存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置。
3、cookie安全性比session差。

进程:

1、操作系统进行资源分配和调度的基本单位,多个进程之间相互独立

2、稳定性好,如果一个进程崩溃,不影响其他进程,但是进程消耗资源大,开启的进程数量有限制

 

线程:

1、CPU进行资源分配和调度的基本单位,线程是进程的一部分,是比进程更小的能独立运行的基本单位,一个进程下的多个线程可以共享该进程的所有资源。

2、如果IO操作密集,则可以多线程运行效率高,缺点是如果一个线程崩溃,都会造成进程的崩溃。

 

应用:

IO密集的用多线程,在用户输入,sleep 时候,可以切换到其他线程执行,减少等待的时间

CPU密集的用多进程,因为假如IO操作少,用多线程的话,因为线程共享一个全局解释器锁,当前运行的线程会霸占GIL,其他线程没有GIL,就不能充分利用多核CPU的优势、


io 密集型用多线程,cpu 密集型用多进程

any 任何的,任一的;

python:any():只要迭代器中有一个元素为真就为真

all():迭代器中所有的判断项返回都是真,结果才为真


>>> a=[True,False]
>>> any(a)
True
>>> all(a)
False
>>> any
<built-in function any>
>>> all
<built-in function all>
>>>


2)使用 = 而不是 ==(导致“SyntaxError: invalid syntax”)

IOError:输入输出异常
AttributeError:试图访问一个对象没有的属性
ImportError:无法引入模块或包,基本是路径问题
IndentationError:语法错误,代码没有正确的对齐
IndexError:下标索引超出序列边界
KeyError:试图访问你字典里不存在的键
SyntaxError:Python代码逻辑语法出错,不能执行
NameError:使用一个还未赋予对象的变量


复制不可变数据类型,不管copy还是deepcopy,都是同一个地址当浅复制的值是不可变对象(数值,字符串,元组)时和=“赋值”的情况一样,对象的id值与浅复制原来的值相同。


__init__:对象初始化方法

__new__:创建对象时候执行的方法,单列模式会用到

__str__:当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据

__del__:删除对象执行的方法

sys.argv 命令行参数,包括文件名


生成器是特殊的迭代器:

1、列表表达式的【】改为()即可变成生成器。

2、函数在返回值得时候出现yield就变成生成器,而不是函数了


空格strip()

sorted 返回新的list
sort 在原有的list上修改,无返回值

 

使用lambda函数对list排序foo = [-5,8,0,4,9,-4,-20,-2,8,2,-4],输出结果为[0,2,4,8,8,9,-2,-4,-4,-5,-20],正数从小到大,负数从大到小】(传两个条件,x<0和abs(x))

传两个条件,key是tuple,False 在前,False优先,排序也是,从小到大,先false,后true

>>> a=lambda x:(x<0,abs(x))
>>> a(1)
(False, 1)
>>>


>>> a=[True,False]
>>> a.sort()
>>> a
[False, True]
>>> a.sort()

key 嵌套 ,再看一下73题

字典排序:关键是把字典变成列表元祖(zip 或者.items),然后排序,再转换成字典(字典生成式)
>>> a
{'link': 1, 'ccc': 232, 'avc': 2}
>>> sorted(a.items(),key=lambda x : x[0])
[('avc', 2), ('ccc', 232), ('link', 1)]
>>> { i[0]:i[1] for i in sorted(a.items(),key=lambda x : x[0])}
{'link': 1, 'ccc': 232, 'avc': 2}
>>>

对字典直接进行sorted 返回的只是键的排序!!!!!
>>> a
{'link': 1, 'ccc': 232, 'avc': 2}
>>> sorted(a)
['avc', 'ccc', 'link']
>>>

列表推导式、字典推导式、生成器

 


绑定变量使用预编译语句是预防SQL注入的最佳方式
参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物,不会影响行进路线,无非跑的快点与慢点的区别。

re.split(r":| ")
>>> a=" i love:ss"
>>> import re
>>> re.split(":| ",a)
['', 'i', 'love', 'ss']
>>> a=" i love:ss"
>>> a.split(" ")
['', 'i', 'love:ss']
>>>
遇到分割符,前后要划分,第一个是分隔符,则分割后第一个元素是空字符串!!!!!

正则开始^结尾$ ,记得用r


MyISAM 与 InnoDB 区别
1、InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM就不可以了;

2、MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及安全性较高的应用;

3、InnoDB 支持外键,MyISAM 不支持;

4、对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM表中可以和其他字段一起建立联合索引;

5、清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重建表。


字符串出现的次数:
>>> str="a x sss a"
>>> str.count("a")
2
>>> str.count("s")
3
>>>


>>> str="a x sss a"
>>> str.count("a")
2
>>> str.count("s")
3
>>>
>>>
>>> from collections import Counter
>>> Counter(str)
Counter({' ': 3, 's': 3, 'a': 2, 'x': 1})
>>>


str.upper()
str.lower()

两种方法去除空格,替换和分割重组!!!!!replace ,split

正则,没有4和7 [0-3,5-6,8-9]

int("1.4")报错,int(1.4)输出1

python垃圾回收主要以引用计数为主
引用计数算法
当有1个变量保存了对象的引用时,此对象的引用计数就会加1;
当使用del删除变量指向的对象时,如果对象的引用计数不为1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除。

findall结果无需加group(),search需要加group()提取!!!!!!!!!!


简述乐观锁和悲观锁

 

悲观锁, 就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

 

乐观锁,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量


Python中函数参数是引用传递(注意不是值传递)。对于不可变类型(数值型、字符串、元组),因变量不能修改,所以运算不会影响到变量自身;而对于可变类型(列表字典)来说,函数体运算可能会更改传入的参数变量。

 

无名、有名分组
(1)正则表达式—无名分组
从正则表 达式的左边开始看,看到的第一个左括号“(”表示表示第一个分组,第二个表示第二个分组, 依次类推。

需要注意的是,有一个隐含的全局分组(就是索引号为0的分组),就是整个正则 表达式匹配的结果

 

(2)正则表达式—有名分组
命名分组就是给具体有默认分组编号的组另外再起一个别名,方便以后的引用。 命令分组的语法格式如下: (?P<name>正则表达式)

 

语法格式中的字符P必须是大写的“P”,name是一个合法的标识符,表示分组的别名。

s = "ip='230.192.168.78',version='1.0.0'"

res = re.search(r"ip='(?P<ip>\d+\.\d+\.\d+\.\d+).*", s)

print res.group('ip')#通过命名分组引用分组

 

正则表达式—后向引用
当用“()”定义了一个正则表达式分组后,正则引擎就会把匹配的组按照顺序进行编号,然后存 入缓存中。这样我们就可以在后面对已经匹配过的内容进行引用,这就叫后向引用。

(1)通过索引引用
\数字 \1表示引用第一个分组,\2引用第二个分组,以此类推,\n引用第n个组,而\0则表示引用整个 被匹配的正则表达式本身。

 

交换字符串的位置

import re

s = 'abc.xyz' # 交换.号两边的字符串

res = re.sub(r'(.*)\.(.*)', r'\2.\1', s)

print res

>>>xyz.abc

 

(2) (?P=name)通过命名分组名进行引用
(?P=name) 字符P必须是大写的P,name表示命名分组的分组名

 

(?P<name>)(?P=name) 引用分组的值匹配值必须与第一个分组匹配值相等才能匹配到

例如:

1) 引用前一个分组,前后值相同都是2,故能匹配到
>>> re.match(r'(?P<xst>\d)(?P=xst)','22').groups()

('2',)

>>> re.match(r'(?P<xst>\d)(?P=xst)','22').group()

'22'

2) 引用前一个分组,前后值不相同分别为2和3,故不能匹配到
>>> re.match(r'(?P<xst>\d)(?P=xst)','23').group()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

AttributeError: 'NoneType' object has no attribute 'group

 


3.集合的交集& ,s.intersection()

4.集合的并集 | ,s. union()

random.random()生成0-1之间的随机小数,所以乘以100,生成0-100的随机数

精简代码,lambda省去了定义函数,map省去了写for循环过程


引用计数,删除对象,调用__del__方法

GET请求因为数据参数是暴露在URL中的,所以安全性比较低,比如密码是不能暴露的,就不能使用GET请求;POST请求中,请求参数信息是放在请求头的,所以安全性较高,可以使用。


多进程多线程的锁

由于多线程共享内存,所以我们只要在该进程中创建一个锁,然后锁定相应的代码块即可,因为内存的共享,使得不同子线程面对的就是同一把锁,如下代码所示。这样可以使得每个线程对x进行修改后,x最后依然保持原值
但是在多进程中,由于每个子进程都会有自己的独立内存,所以如果按以上方式创建进程,那么实际上在函数f中的lock对象会根据LEGB原则读取到外面的lock对象,也就是说lock=Lock()这条语句也会被包括进每个子进程中,从而每个子进程不仅会在内存创建函数f,也会创建自己独立的锁对象,这样违背了一锁原则,从而无法起到同步作用。所以多进程中正确的加锁方式应该是先在主进程中创建一个锁,然后以参数的形式传给每个进程,这样相当于不同的子进程面对的是同一个锁。虽然实际上,每个子进程还是会在自己的内存中保存自己的锁对象,即如果获取每个进程的锁的id,那么其id还是不同的,说明其是不同的对象,但是因为这个锁的对象是在主进程创建的,子进程只是在自己的内存中复制了主进程中锁的状态,所以尽管不同子进程内存中也有自己的锁对象,但是这个锁对象的状态是一样的,这是最本质的,即我们实际上是需要不同线程或进程的锁是同步的,状态是一致,就可以认为是同一把锁,从而可以实现保护作用


多线程公用一把锁,不需要传锁给子线程,多进程需要把锁传给子进程
from multiprocessing import Process,Lock

最后需要注意的一点是,创建多线程或多进程,都必须要先经过主模块判断,即必须在if __name__=='__main__':语句之后才行,这是为了保护资源的一种强制性机制


python 之 动态特性: 程序在运行的时候可以修改,增加方法,增加属性

Q.1. Python 的特点和优点是什么?

Python 可以作为编程的入门语言,因为他具备以下特质:

1. 解释性

2. 动态特性

3. 面向对象

4. 语法简洁

5. 开源

6. 丰富的社区资源

缺点:速度慢,代码不能加密,线程不能利用多cpu问题

深拷贝是将对象本身复制给另一个对象。这意味着如果对对象的副本进行更改时不会影响原对象。

三元表达式 [on true] if [expression]else [on false]

>>> a=5 if 1<0 else 8
>>> a
8
>>>


dir() 函数返回对象中的所有成员 (任何类型)


什么是猴子补丁?在运行时动态修改类和模块

i.issupper() 判断是否是大写

与正索引不同,负索引是从右边开始检索。

>>> a=[1,2,3]
>>> a[-1]
3
>>> a[0]
1

如何随机打乱列表中元素,要求不引用额外的内存空间?
我们用 random 包中的 shuffle() 函数来实现。
>>> a=[1,3,3,3,2]
>>> random.shuffle(a)
>>> a
[2, 3, 3, 1, 3]
>>>
shuffle() 方法将序列的所有元素随机排序。
返回值
该函数没有返回值。


upper lower
像 @ 和$这样的字符即满足大写也满足小写。


>>> a=1.2222
>>> a/3
0.4074
>>> a//3
0.0
>>>

//运算符执行地板除法,返回结果的整数部分 (向下取整)。

问什么标识符不建议使用下划线开头?

因为在 Python 中以下划线开头的变量为私有变量,如果你不想让变量私有,就不要使用下划线开头。

先来看看解封装

mytuple=3,4,5
print(mytuple)#(3, 4, 5)
这将3,4,5封装到元组mytuple中

现在我们将这些值解封装到变量x,y,z中

mytuple=3,4,5
print(mytuple) #(3, 4, 5)
x,y,z=mytuple
print(x+y+z) #12

以单个下划线开头的变量或方法仅供内部使用


Python的主要功能是什么?

Python是一种解释型语言。与C语言等语言不同,Python不需要在运行之前进行编译。

Python是动态语言,当您声明变量或类似变量时,您不需要声明变量的类型。

Python适合面向对象的编程,因为它允许类的定义以及组合和继承。Python没有访问说明(如C ++的public,private)。

在Python中,函数是第一类对象。它们可以分配给变量。类也是第一类对象

编写Python代码很快,但运行比较慢。Python允许基于C的扩展,例如numpy函数库。

Python可用于许多领域。Web应用程序开发,自动化,数学建模,大数据应用程序等等。它也经常被用作“胶水”代码。

python中的内存管理由Python私有堆空间管理。所有Python对象和数据结构都位于私有堆中。程序员无权访问此私有堆。python解释器负责处理这个问题。

它是导入模块时使用的环境变量。每当导入模块时,也会查找PYTHONPATH以检查各个目录中是否存在导入的模块。解释器使用它来确定要加载的模块。


当我们导入一个模块时:import xxx,默认情况下python解析器会搜索当前目录、已安装的内置模块和第三方模块

当运行脚本文件和导入模块不再同一目录下

import sys

sys.path.append(r‘/home/***/work/’)

就能继续import进去该模块了

永久添加路径到sys.path中,方式有三,如下:
1)将写好的py文件放到 已经添加到系统环境变量的 目录下 ;
2) 在 /usr/lib/python2.6/site-packages 下面新建一个.pth 文件(以pth作为后缀名)
将模块的路径写进去,一行一个路径,如: vim pythonmodule.pth
/home/liu/shell/config
/home/liu/shell/base
3) 使用PYTHONPATH环境变量
export PYTHONPATH=$PYTHONPATH:/home/liu/shell/config

[:: - 1]用于反转数组或序列的顺序。

random.random()方法返回[0,1]范围内的浮点数。该函数生成随机浮点数。随机类使用的方法是隐藏实例的绑定方法。

在Python中,capitalize()函数可以将字符串的第一个字母大写。如果字符串在开头已经包含大写字母,那么它将返回原始字符串。

生成器和迭代器区别


list删除用del,remove,remove的是value
remove 只删除匹配到的第一个数据

>>> a=[1,2,3,3,]
>>> del a[1]
>>> a
[1, 3, 3]
>>> a.remove(3)
>>> a
[1, 3]
>>>

 


python面试题之迭代器和生成器的区别
1 迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身。对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数,iter()是python的内置函数。iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数。在没有后续元素时,next()会抛出一个StopIteration异常

2 生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)

区别:生成器能做到迭代器能做的所有事,而且因为自动创建了__iter__()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常

 

posted @ 2020-07-20 16:54  峡谷恶霸  阅读(175)  评论(0编辑  收藏  举报