当前位置: 首页>后端>正文

python面试题

python主要数据类型有哪些,那些是可变的,那些是不可变的?

数字(int) 不可变类型
字符串(str) 不可变类型
列表(list) 可变类型
元祖 (tuple) 不可变类型
字典(dict) 可变类型
集合(set) 可变类型

什么是可变数据类型,什么是不可变数据类型?

id: 内存地址
value: 值
1.可变类型:在id不变的情况下,value可以变,则称为可变类型,如列表,字典

  1. 不可变类型:value一旦改变,id也改变,则称为不可变类型(id变,意味着创建了新的内存空间)

list和tuple有什么不同

1.list是可变数据类型,不能做字典的key,tuple是不可变数据类型,可以当做字典的key
2.list具有添加,删除,修改的方法,tuple没有
3.定义tuple时如果只有一个元素,那么元素后面得加,(1,)

python是如何进行内存管理的?

https://www.cnblogs.com/wangyuhangboke/p/7802253.html

python如何实现单例

https://www.cnblogs.com/ctztake/p/8076048.html

cookie和session有什么区别?

1.cookie数据存放在客户的浏览器上(客户端),session会在一定时间内保存在服务器上
2.由于cookie是存放在浏览器客户端的,所以cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie 欺骗,,session放在客户端,比较安全,如果主要考虑到安全应当使用session
3.session保存在服务器上.当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用cookie
4.session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到.而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的.cookie只能是子路径访问父路径设置的cookie
5.cookie本身最大支持4096字节,相对于cookie,session能存放更多字节

给定一个整数数组,返回两个数的索引,使得他们相加和目标值相等,可以假定每个输入都有且只有一个解例如:nums=[2,7,11,15],目标值是9,因为2+7=9所以返回[0,1]

def f(l,aim):
    for i in range(len(l)):
        for j in range(i,len(l)):
            if l[i]+l[j]==aim:
                print('[%s,%s]'%(i,j))

nums=[2,7,11,15]
f(nums,17)

写出常用的HTTP 请求方法

GET 请求指定的页面信息,并返回实体主体。
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
DELETE 请求服务器删除指定的页面。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断

python2 和Python3 有那些显著的区别

https://www.runoob.com/python/python-2x-3x.html
1.print函数

2.Unicode
Python 2 有 ASCII str() 类型,unicode() 是单独的,不是 byte 类型。
现在, 在 Python 3,我们最终有了 Unicode (utf-8) 字符串,以及一个字节类:byte 和 bytearrays。
由于 Python3.X 源码文件默认使用utf-8编码,这就使得以下代码是合法的:

>>> 中国 = 'china'
>>>print(中国)
china

3.除法运算
对于'/':
python 2.x中:整数相除的结果是一个整数,把小数部分完全忽略掉,浮点数除法会保留小数点的部分得到一个浮点数的结果。
python 3.x中:对于整数之间的相除,结果也会是浮点数。
对于'//':
python 2.x和python 3.x中是一致的。

4.异常处理:
在 Python 3 中处理异常也轻微的改变了,在 Python 3 中我们现在使用 as 作为关键词。
捕获异常的语法由 except exc, var 改为 except exc as var。
使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常。 Python 2.6已经支持这两种语法。

  1. 在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。
  2. 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。
    在2.x时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在3.x中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。

5.不等运算符
Python 2.x中不等于有两种写法 != 和 <>
Python 3.x中去掉了<>, 只有!=一种写法

6.去掉了repr表达式Python 2.x 中反引号相当于repr函数的作用
Python 3.x 中去掉了``这种写法,只允许使用repr函数

7.多个模块被改名
StringIO模块现在被合并到新的io模组内。 new, md5, gopherlib等模块被删除。 Python 2.6已经支援新的io模组。
httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib被合并到http包内。
取消了exec语句,只剩下exec()函数。 Python 2.6已经支援exec()函数。

8.数据类型
1)Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long
2)新增了bytes类型,对应于2.X版本的八位串
3)dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有 dict.has_key(),用 in替代它吧 。

如何理解迭代器和生成器?

可以直接作用于for循环的对象统称为可迭代对象:Iterable。含有iter方法
迭代器:含有iternext的对象就是迭代器
生成器:生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写iter()和next()方法了,只需要一个yiled关键字。是可迭代对象,实现了延迟计算,生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处

闭包

闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

当一个内嵌函数引用其外部作作用域的变量,我们就会得到一个闭包. 总结一下,创建一个闭包必须满足以下几点:

必须有一个内嵌函数
内嵌函数必须引用外部函数中的变量
外部函数的返回值必须是内嵌函数

什么是装饰器

装饰器的本质 :闭包函数
功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能

实际上是一种设计模式,开放封闭原则,对扩展是开放的,对修改是封闭的

请写一个装饰器打印输出一个函数执行的时间

#装饰器的本质就是一个闭包函数,在不改变原函数的调用方式和源代码的情况下,在这个函数前后加上扩展功能
import time
def wrapepr(fun):
    def inner(*args,**kwargs):
        start=time.time()
        fun()
        end=time.time()
        print('执行时间%s'%(end-start))
    return inner

@wrapepr
def aa():
    time.sleep(1)
    print('aa.....')
aa()

什么是进程,线程,协程?

进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
线程:程序执行流的最小操作,每个进程有一个地址空间,而且默认就有一个控制线程,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
协程:是单线程下的并发,又称微线程,纤程协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的,

如何在Python中拷贝一个对象,并说说他们的区别

https://www.cnblogs.com/ctztake/p/8194275.html
赋值:只是创建一个变量,该变量指向原来内存地址
浅拷贝:,在内存中只额外创建第一层数据 copy.copy()
深拷贝:在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化) copy.deepcopy()

请简单解释python中的staticmethod(静态方法)和classmethod(类方法)

普通方法 默认有一个self对象传进来,并且只能被对象调用——绑定到对象
类方法 用@classmethod装饰,默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用——绑定到类
静态方法 用@staticmethod装饰,没有默认参数,并且可以被类和对象(不推荐)调用——非绑定

对列表元素去重并保持原先顺序

l=[1,2,3,4,1,2,5,7,8,4,6]
s=set(l)
l1=list(s)
l1.sort(key=l.index)
print(l1)

*args和**kwargs分别代表什么,举例说明**kwargs的用法

*args:表示按照位置传值多出来的值都给args,且以元祖的方式呈现
**kwargs:表示按照关键字传值把多余的传值都给kwargs以字典的方式呈现
 
def f(*args,**kwargs):
   print(args) # ('xm', 21)
    print(kwargs) # {"addr": "sz", "school": "qh"}
 
f('xm',21,addr='sz',school='qh')

什么是lambda函数?它有什么好处?

lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数
lambda函数:首要用途是指点短小的回调函数
lambda [arguments]:expression

>>> a=lambdax,y:x+y
>>> a(3,11)
>>>14

Python中pass语句的作用是什么?

pass语句不会执行任何操作,一般作为占位符或者创建占位程序,

whileFalse:
    pass

Python 正则模块re里面的match()和search()的区别?

re模块中match(pattern,string[,flags]),检查string的开头是否与pattern匹配。
re模块中search(pattern,string[,flags]),在string搜索pattern的第一个匹配值。

>>>print(re.match(‘super’, ‘superstition’).span())

(0, 5)

>>>print(re.match(‘super’, ‘insuperable’))

None

>>>print(re.search(‘super’, ‘superstition’).span())

(0, 5)

>>>print(re.search(‘super’, ‘insuperable’).span())

(2, 7)

下面代码会输出什么:

def f(x,l=[]):
    for i in range(x):
        l.append(i*i)
    print l

f(2)
f(3,[3,2,1])
f(3)

答案:

[0, 1]
[3, 2, 1, 0, 1, 4]
[0, 1, 0, 1, 4]

谈谈python类的继承

经典类: 没有继承object类的类都叫做经典类
新式类: 继承object类的类叫做新式类
python3中统一都是新式类,pyhon2中才分新式类与经典类
python允许多继承


python面试题,第1张
class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

阅读下面的代码,它的输出结果是什么?

class A(object):
    def go(self):
        print "go A go!"
    def stop(self):
        print "stop A stop!"
    def pause(self):
        raise Exception("Not Implemented")

class B(A):
    def go(self):
        super(B, self).go()
        print "go B go!"

class C(A):
    def go(self):
        super(C, self).go()
        print "go C go!"
    def stop(self):
        super(C, self).stop()
        print "stop C stop!"

class D(B,C):
    def go(self):
        super(D, self).go()
        print "go D go!"
    def stop(self):
        super(D, self).stop()
        print "stop D stop!"
    def pause(self):
        print "wait D wait!"

class E(B,C): pass

a = A()
b = B()
c = C()
d = D()
e = E()

说明下列代码的输出结果

a.go()
b.go()
c.go()
d.go()
e.go()

a.stop()
b.stop()
c.stop()
d.stop()
e.stop()

a.pause()
b.pause()
c.pause()
d.pause()
e.pause()

答案

输出结果以注释的形式表示:

a.go()
# go A go!

b.go()
# go A go!
# go B go!

c.go()
# go A go!
# go C go!

d.go()
# go A go!
# go C go!
# go B go!
# go D go!

e.go()
# go A go!
# go C go!
# go B go!

a.stop()
# stop A stop!

b.stop()
# stop A stop!

c.stop()
# stop A stop!
# stop C stop!

d.stop()
# stop A stop!
# stop C stop!
# stop D stop!

e.stop()
# stop A stop!

a.pause()
# ... Exception: Not Implemented

b.pause()
# ... Exception: Not Implemented

c.pause()
# ... Exception: 
Not Implemented

d.pause()
# wait D wait!

e.pause()
# ...Exception: Not Implemented

描述对super、pass、yield、lambda关键字修饰的理解

super:在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,
事实上,super 和父类没有实质性的关联。
super(cls, inst) 获得的是 cls 在 inst 的 MRO 列表中的下一个类。

pass 不做任何事情,一般用做占位语句

yield 是一个类似 return 的关键字,他不会终止当前函数,只是这个函数返回的是个生成器。yield可以保存状态,当下次执行时会从上次执行玩的地方开始执行

lamda表达式就是定义一个匿名函数,数据结构简单,可作为函数的参数

大致描述一下python GIL的机制

GIL全局解释器锁,本质也是互斥锁,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全,有了GIL的存在,同一时刻同一进程中只有一个线程被执行
GIL对性能的影响:
对于计算密集性来说,开多线程不能提高效率,甚至可能不如串行(因为要来回切换),
但对于io密集性来说,开启多线程可以明显提高效率,因为遇到io得阻塞,阻塞时间远大于程序执行时间,所欲GIL对IO密集来说,影响不是很大

python中多线程和多进程的区别

  1. 线程共享创建它的进程的地址空间; 进程有自己的地址空间。

2.线程可以直接访问其进程的数据; 进程具有自己的父进程的数据的副本。

3.线程可以直接与其进程的其他线程通信; 进程必须使用进程间通信来与兄弟进程进行通信。

4.新线程很容易创建; 新进程需要父进程的副本。线程创建开销小

5.线程可以对相同进程的线程进行相当的控制; 进程只能控制子进程。

6.对主线程的更改(取消,优先级更改等)可能会影响进程的其他线程的行为; 对父进程的更改不会影响子进程。

请用两个队列来实现一个栈

class Stock:
    def __init__(self):
        self.queueA=[]
        self.queueB=[]
    def push(self, node):
        self.queueA.append(node)
    def pop(self):
        if len(self.queueA)==0:
            return None
        while len(self.queueA)!=1:
            self.queueB.append(self.queueA.pop(0))
        self.queueA,self.queueB=self.queueB,self.queueA #交换是为了下一次的pop
        return self.queueB.pop()

请用两个栈实现一个队列

class Queue:
    def __init__(self):
        self.stockA=[]
        self.stockB=[]
    def push(self, node):
        self.stockA.append(node)
    def pop(self):
        if self.stockB==[]:
            if self.stockA==[]:
                return None
            else:
                for i in range(len(self.stockA)):
                    self.stockB.append(self.stockA.pop())
        return self.stockB.pop()

https://www.xamrdz.com/backend/3ks1940567.html

相关文章: