python开发 面试题

1、简述列表与元组的区别
答:
元组tuple与列表List相同点
元组tuple与列表List都是序列类型的容器对象,能够存听任何类型的数据、支持切片、迭代等操做。

元组tuple与列表List区别:
1.不可变与可变:两种类型除了字面上的区别(括号与方括号)以外,最重要的一点是tuple是不可变类型,大小固定,而list是可变类型、数据能够动态变化,这种差别使得二者提供的方法、应用场景、性能上都有很大的区别。
2.一样大小的数据,tuple 占用的内存空间更少,原子性的 tuple 对象还可做为字典的键。
3.同构与异构:tuple用于存储异构(heterogeneous)数据,当作没有字段名的记录来用,好比用tuple来记录一我的的身高、体重、年龄。而列表通常用于存储同构数据(homogenous),同构数据就是具备相赞成义的数据

总结:元组和列表是经常使用的数组类型,在使用过程当中,列表擅长对可变数据的操做,通常用于同构数据,而元组主要用于异构数据,数据库操做中查询出来的记录就是由元组构成的列表结构。



2、简述核心数据类型列列表中 append() | extend() | insert()方法的功能与区别
append():在列表尾部追加元素
extend():在列表尾部迭代追加元素
insert():在列表指定索引位置插入元素


3、用尽量多的方法描述如何规避在对字典进行key索引取值时引起 KeyError错误
方式一:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
ret = dic.get('name1')  #None
方式二:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
for key in dic:
    print(key,dic[key])
方式三:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
if 'name' in dic:
    print(dic['name'])



4、什么是线程? 什么是进程? 什么是协程? 在Python中多线程适用于什么场景?为何?

进程:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操做系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
广义定义:进程是一个具备必定独立功能的程序关于某个数据集合的一次运行活动。它是操做系统动态执行的基本单元,在传统的操做系统中,进程既是基本的分配单元,也是基本的执行单元。

线程:
线程(英语:thread)是操做系统可以进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运做单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每条线程并行执行不一样的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

协程:
协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序本身控制调度的。


应用场景:
多进程适合在CPU 密集型操做(cpu 操做指令比较多,如科学计算,位数多的浮点运算)
多线程适合在IO 密集型操做(读写数据操做较多的,好比爬虫)
 
why?
线程是并发 ,进程是并行
进程之间互相独立, 是系统分配资源的最小单位 同一个进程中的全部线程共享资源

并行 : 同一时刻多个任务同时在运行
并发: 在同一时间间隔内 多个任务都在运行,可是并不会在同一时刻同时运行,存在交替执行的状况

系统运行时,大部分的情况是cpu在等I/O(硬盘/内存)的读/写,这样一来线程能够来回切换 IO密集型操做使用并发更好。
cpu 密集型: 大部分时间用来作计算 逻辑判断等 cpu 动做的程序称之cpu 密集型





5、介绍一下二分查找算法 并用Python代码来实现它

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。可是,折半查找要求线性表必须采用顺序存储结构,并且表中元素按关键字有序排列
例子:
l = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88]
def func(l, aim,count):
    mid = (len(l) - 1) // 2

    if l:
        if aim > l[mid]:
            count += 1
            func(l[mid + 1:], aim, count)
        elif aim < l[mid]:
            count += 1
            func(l[:mid], aim,count)
        elif aim == l[mid]:
            count += 1
            print("找了%d次,才找到%d"%(count,aim))
    else:
        print('找不到')

func(l,66,0)#找了5次,才找到66





6、什么是装饰器,它的应用场景是什么? 请写出经过装饰器装饰一个带参数的函数的代码

装饰器:
其实装饰器本质是闭包,在不改变原函数的调用指令状况下,给原函数增长额外的功能。它的传参,返回值都是借助内层函数inner,它之因此借助内层函数inner就是为了让被装饰函数在装饰器装饰先后,没有任何区别,看起来没有变化。

应用场景是:
1. 受权(Authorization)
2. 日志(Logging)
3,函数执行时间统计
4,执行函数前预备处理
5,执行函数后清理功能
等等。。。

def wrapper(f):
    def inner(*args,**kwargs):
        ret =f(*args,**kwargs)
        return ret
    return inner

@wrapper  # func = wrapper(func) = inner
def func(a,b):
    print(a,b)
    sum = a + b
    return sum

ret = func(3,4) # inner(3,4)
print(ret)





7、简述什么是深拷贝? 什么是浅拷贝并说出以下代码得出的结果是什么?

直接赋值:其实就是对象的引用(别名)。
浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
深拷贝(deepcopy): copy 模块的 deepcopy 方法,彻底拷贝了父对象及其子对象。

x = ['lily', '20', 'hr']
y = x
x[0] = 'lucy'
z = list(x)
x[0] = ‘lilei’
请问变量 y 的结果和 z的结果分别是什么
y的结果:['lilei', '20', 'hr'] #赋值
z的结果:['lucy', '20', 'hr']  #浅拷贝

x = ['lily', 20, ['study', 'coding']]
y = x[:]
import copy
z = copy.deepcopy(x)
x[2][0] = 'lol'
请问此时变量 y 和 z 的值分别是什么? 为何?
y的结果:['lily', 20, ['lol', 'coding']]  #why  浅拷贝
z的结果:['lily', 20, ['study', 'coding']]   #why 深拷贝





8、尽量多的写出你掌握的建立字典的方式
方式一:经过关键字dict和关键字参数建立
a = dict(name='alex',age='18')
print(a)

方式二:直接赋值建立
a = {'name':'alex','age':18}
print(a,type(a))

方式三:经过二元组列表建立
li = [('name', 'alex'), ('age', 18)]
dic = dict(li)
print(dic,type(dic))

方式四:经过字典推导式建立
dic = {i:2*i for i in range(3)}
print(dic,type(dic))

方式五:dict和zip结合建立
dic = dict(zip('abc', [1, 2, 3]))
print(dic,type(dic))

方式六:经过dict.fromkeys()建立,一般用来初始化字典, 设置value的默认值
dic = dict.fromkeys(range(3), 'x')
print(dic,type(dic))



9、有列表 a =[‘apple’, ‘banana’, ‘orange’] 现须要将其中各元素经过”|”拼接起来,请写出你的实现方式,并说明为什什么你要这样实现
a =['apple', 'banana', 'orange']
b = '|'.join(a)
print(b)
why?可使用字符串方法join()进行拼接列表元素





10、根据类的命名空间相关知识 说出下面代码会得出什什么结果
class c1:
    var1 = 'apple'
    def __init__(self):
        self.var2 = 10
x = c1()
y = c1()
x.var1 = 100

# 此时下面两句句print会打印出什什么内容
print(x.var1, x.var2) #100,10
print(y.var1, y.var2) #apple,10

why:
    类实例化对象时,会建立类的实例化对象空间。 x.var1 = 100 至关于实例对象x 新开辟了一个变量空间var1  优先查找本身的名称空间 全部打印100,10
    y.var1 是 apple 是由于本身的实例空间没有找到var1变量就去类的名称空间查找 




11、请简述 __new____init__ 的区别
1 __new__方法得到空间地址(实例对象建立第一步必须建立空间)
2 将空间地址做为第一个位置参数传给__init__ ,完成实例空间赋值属性的过程   self变量等于addr变量  存储地址空间指针




12、 在Python中 子类如何重写父类的构造函数
class A(object):

    def __new__(cls, *args, **kwargs):  # c了基类object的__new__方法
        print("this is 构造方法")
        addr = super().__new__(cls)  # 必须调用父类开辟空间的方法(操做底层硬件) 默认传参 cls(当前类名)
        print("addr", addr)
        return addr

    def __init__(self, *args, **kwargs):  # 覆盖了基类object的__init__方法
        print("self", self)
        print("this is 初始化方法")
A()
# this is 构造方法
# addr <__main__.A object at 0x0000026B36E65EF0>
# self <__main__.A object at 0x0000026B36E65EF0>
# this is 初始化方法



十3、请简述Python中的实例方法 静态方法 类方法
实例方法
    定义:第一个参数必须是实例对象,该参数名通常约定为“self”,经过它来传递实例的属性和方法(也能够传类的属性和方法);
    调用:只能由实例对象调用。

类方法
    定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名通常约定为“cls”,经过它来传递类的属性和方法(不能传实例的属性和方法);
    调用:实例对象和类对象均可以调用。

静态方法
    定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,可是方法体中不能使用类或实例的任何属性和方法;
    调用:实例对象和类对象均可以调用。




十4、多态 封装 继承 是OOP的三大基石, 请简述封装的意义是什么? 并用Python来实现
封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
1. 将变化隔离; 
2. 便于使用;
3. 提升复用性; 
4. 提升安全性;

class A:
    __N=0 #类的数据属性就应该是共享的,可是语法上是能够把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才能够经过__foo的形式访问到.

a = A()
a.bar() #from A




十5、简述Python代码异常处理理中 raise 与 assert语句的做用, 默认状况下, try与assert只能触发内置异常如(TypeError,KeyError),现须要实现引起用户自定义异常(badString),请写出代码

raise的做用:python能够自动触发异常,raise(内置函数)的定义为显示的抛出异常,用户可使用raise进行判断,显式的引起异常,raise执行后程序将再也不向下执行。
assert的做用:在本身不肯定、或者怀疑会出错的时候用断言,或者在DEBUG时候用断言


class EvaException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg

user = input("请输入用户名:")
pwd = input("请输入密码:")
if user == 'alex':
    try:
        raise EvaException('用户名已存在!')
    except EvaException as e:
        print(e)

if len(pwd) < 6:
    try:
        raise EvaException('密码不能低于6位数!')
    except EvaException as e:
        print(e)


        
十六:如何实现Python多进程之间的数据共享?
使用数据库来解决如今进程之间的数据共享问题
用Manager实现数据共享
from multiprocessing import Manager,Process,Lock
def work(d,lock):
    with lock: #不加锁而操做共享的数据,确定会出现数据错乱
        d['count']-=1

if __name__ == '__main__':
    lock=Lock()
    with Manager() as m:
        dic=m.dict({'count':100})
        p_l=[]
        for i in range(100):
            p=Process(target=work,args=(dic,lock))
            p_l.append(p)
            p.start()
        for p in p_l:
            p.join()
        print(dic)




十7、简述内置函数 map() | zip() | filter() | reduce() 的功能

zip:函数用于将可迭代的对象做为参数,将对象中对应的元素打包成一个个元组,而后返回由这些元组组成的列表。若是各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。
filter 过滤 经过你的函数,过滤一个可迭代对象
map:会根据提供的函数对指定序列作映射。
reduce() 函数会对参数序列中元素进行累积。



十9、经过列表解析与三元表达式处理列表 [1,2,3,4,5], 对其中小于3的元素加2 对大于等于3的元素加3
print([i+2 for i in [1,2,3,4,5] if i < 3] + [ i+3 for i in [1,2,3,4,5] if i >= 3])


二10、简述Python中正则表达式的贪婪模式与非贪婪模式
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,
贪婪模式在整个表达式匹配成功的前提下,尽量多的匹配,
而非贪婪模式在整个表达式匹配成功的前提下,尽量少的匹配。非贪婪模式只被部分NFA引擎所支持。 
面试题一 20190621
相关文章
相关标签/搜索