1.python中有哪些可变类型与不可变类型?
可变:list、dict、set
不可变:tuple、str、整型(int、float、complex)
注意:可变对象可以在原来地址上修改元素,不可变则不行(即不能在自己身上增删改),若要修改可以使用对象拼接赋值给新的对象,总之不能修改自身
2.什么是堆?什么是栈?栈和堆的区别是什么?
堆:是一种无序的数据结构,可以看成完全二叉树,没有特定的操作顺序,一般用于动态分配内存空间。
栈:后进先出的数据结构,有栈顶和栈低,一般用于存储局部变量、函数调用以及程序执行过程中的临时数据。
区别:最大区别在于它们的内存分配方式不同,栈由系统自动分配和释放,而堆的分配和释放需要程序员手动控制。栈的空间相对较小,通常只有几MB,而堆的空间比较大,但容易产生内存碎片问题。因此,在选择使用栈还是堆时,需要考虑到具体的应用场景和内存管理的效率。
3.简述数组,链表,队列,堆栈的区别?
数组和链表是存储概念的数据结构,数组的存储数据的空间是连续的,而链表是非连续的。
队列和堆栈式存取概念的数据结构,队列先进先出,堆栈后进先出,可以用数组和链表来实现。
4.面向对象的三个特性是什么?
封装:根据职责将属性和方法封装到一个抽象的类中定义类的准则。
继承:实现代码的重用,相同的代码不需要重复的编写。
多态:不同的子类调用相同的父类,产生不同的结果。
5.什么是闭包?
闭包是指在一个函数内部定义另一个函数,并且这个内部函数能够访问外部函数的变量和参数,即使外部函数已经执行完毕,这些变量和参数仍然存在于内存中,并可以被内部函数使用。闭包常常用来实现一些高阶函数的功能,例如装饰器、回调函数等。
6.匿名函数/函数/闭包/对象在做实参时有什么区别?
函数:当函数作为参数传递时,仅传递其功能。
匿名函数:与函数类似,只有它们的功能作为参数传递。
闭包:当闭包作为参数传递时,函数和闭包内的数据都会被传递,从而可以同时传递功能和上下文。
对象:当实例对象作为参数传递时,它的方法和属性也会被传递。
7.什么是进程、线程、协程、多进程、多线程?有什么区别?有什么使用场景?
(1)概念
进程:操作系统中进行资源分配和调度的基本单位,一个进程可以包含多个线程。每个进程都有独立的内存空间,并且各个进程之间相互独立,不能直接访问对方的内存。
线程:是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,这些线程共享进程的内存空间和系统资源,但每个线程都拥有自己的栈空间、寄存器和程序计数器等线程私有的信息。
协程:一个线程可以包含多个协程,协程通常是在单个线程中运行的,但线程是由操作系统调度的,而协程则是由程序主动控制的。
多线程:指一个程序中创建多个线程,这些线程共享分配给进程的内存空间,可共享资源。
多进程:是指在操作系统中创建多个独立的进程,每个进程有自己独立的内存空间和系统资源。这些进程通过进程间通信(IPC)来共享数据和协作完成任务。
(2)区别
进程切换需要的资源很大,效率相对低。
线程切换需要的资源一般,效率比进程高。
协程切换任务资源很小,三者中效率最高。
(3)场景
线程:适用于需要利用多核CPU并发处理任务,同时又不需要独立内存空间的场景,如Web服务器、桌面应用程序等。
进程:适用于需要进行大量计算或者需要充分利用CPU资源的场景,如并行计算、大数据处理等(cpu密集型任务)。协程:适用于IO密集型的应用场景,如网络爬虫、异步编程等---》同样适用于线程。
8.协程为何比线程还快?
协程是轻量级的,在单个线程中运行,因此不存在资源竞争,死锁问题,而线程切换由系统控制,需要消耗更多的开销。但要利用多核cpu,还是得线程
9.什么是迭代器,为什么要使用它?
拥有__iter__、__next__魔法方法的对象就是迭代器,保存的是获取数据的方式而不是结果,所以想用的时候就可以生成,节省内存空间,它是一个可以记住遍历的位置的对象。
10.什么是生成器,为什么要使用它?
生成器是特殊的迭代器,使用yield和next函数,有生成器表达式,生成器函数,都是为了节约内存。
11.简述迭代器、生成器的区别?
生成器是迭代器,但使用方式不同,生成器函数使用yield,还有生成器表达式,迭代器使用__next__进行元素迭代。
使用场景不同:在处理巨大的数据集合时,建议使用生成器来节省内存。在遍历容器对象时,使用迭代器很方便。
12.什么是装饰器,为什么要使用它?
装饰器是闭包的形式,外层函数返回内层函数,在不修改源代码的情况下,为函数动态增加新功能就需要使用。
13.什么是线程安全?
线程安全指的是多个线程同时访问共享数据时,不会出现任何问题或错误的特性。这意味着在一个多线程应用程序中,当多个线程同时访问共享资源(例如变量或对象)时,它们不会干扰彼此或产生无法预测的结果。
14.标准库有哪些线程安全的队列?
Python Queue模块有三种队列:
FIFO队列先进先出.(线程安全)
LifoQueue类似于堆,即先进后出(线程安全)
PriorityQueue优先级队列,级别越低,越先出来(线程安全)
15.什么是GIL?
全局解释器锁,python在多线程的时候,线程会获取GIL锁,获取到的执行操作,等释放后,其他线程再获取锁执行 ,保证同一时间只有一个线程在执行。它是cpython的一个概念,因为cpython线程不是安全的,所以GIL是必须的。
16.什么时候释放GIL锁?
时间片耗尽(cpu时间);
任务遇到I/O等待时;
执行任务结束;
执行到字节码阈值时;
17.互斥锁与GIL的区别?
互斥锁是等一个线程任务结束后,才执行下一个线程,在这期间其他线程是阻塞;
GIL是若线程进入I/O等待,会释放锁给其他线程执行,在这期间线程任务是没有结束的。
18. python高并发解决方案有哪些?
1.多线程,充分利用多核cpu
2.使用协程或异步处理io任务(gelent/asyncio)
3.使用缓存,对一些高频数据的处理
19.谈谈对不定⻓参数的理解?
*args和**kwargs,在不确定需要传多少参数时使用,args表示位置参数,元组形式保存,kwargs表示关键字参数20.谈谈对缺省参数的理解?
缺省参数表示默认参数,当在对应位置传了参数,就使用这个参数,若没有传参,就使用默认设置的参数
break代表循环的结束,终止符,而continue表示跳过当前循环进入下一个循环
is
和 ==
的区别?==判断是否相等,而is不仅判断是否相等,还判断id内存地址是否相等,两者都相等了才返回True
__new__()
和 __init__()
的区别?两者在对象实例化的时候会调用,__new__是构造函数,创建实例化的时调用,有一个cls参数代表当前类,必须要有返回值;__init__是初始化函数,创建实例化后调用,有一个self参数代表当前实例,不需要有返回值。
yield
和return
的相同点和区别?相同点:都是返回程序的执行结果;区别:yield返回结果但程序还没有结束,return返回结果表示程序已经结束执行
- os:提供不少于操作系统相关联的函数
- sys:提供了访问Python解释器相关信息的接口,比如命令行参数、标准输入输出等。通常用于命令行参数。
- datetime:日期时间
- re:正则匹配
- math:数学运算
- unitest:进行模块的单元测试
- random:提供生成伪随机数的函数
- threading:多线程编程相关功能
- time:提供了时间相关的函数和类,比如计时器
- json:提供对json数据的序列化反序列化操作
- socket:提供了网络编程相关的功能,比如创建 TCP/UDP 连接等。
- logging:提供了日志记录相关的功能。
单例模式:保证一个类仅有一个实例,并提供一个访问他的全局访问点。
装饰器模式:不修改元类代码和继承的情况下动态扩展类的功能。
迭代器模式: 提供一个方法顺序访问一个聚合对象中各个元素。
range:python2返回列表;python3是可迭代对象输出print:python2 print '';python3 print()输入input: python2 raw_input;python3 input编码:python2 ascii;python3 utf-8
28.装饰器的使用场景?闭包的使用场景?
装饰器:
1.记录日志:装饰器可以用于记录函数的调用信息,包括输入参数和返回值。这对于调试和性能分析非常有用。
def log(func): def wrapper(*args, **kwargs): print(f"Calling function {func.__name__}") result = func(*args, **kwargs) print(f"Function {func.__name__} returned {result}") return result return wrapper @log def add(a, b): return a + b add(1, 2) # 输出:Calling function add Function add returned 3
2.计时:装饰器可以用于测量函数的执行时间。这对于性能优化和代码分析很有帮助。
import time def timer(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"Function {func.__name__} took {end_time - start_time} seconds to run") return result return wrapper @timer def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2) fibonacci(10) # 输出:Function fibonacci took 0.001234567 seconds to run3.缓存:装饰器可以用于缓存函数的计算结果,以便在相同的输入参数下避免重复计算。这对于提高性能和减少计算时间很有帮助。
def cache(func): cached_results = {} def wrapper(*args, **kwargs): key = (args, tuple(kwargs.items())) if key not in cached_results: cached_results[key] = func(*args, **kwargs) return cached_results[key] return wrapper @cache def factorial(n): if n <= 1: return 1 return n * factorial(n-1) factorial(5) # 输出:1204.认证和权限控制:装饰器可以用于验证用户的身份和权限,以确保只有授权用户才能访问某些功能。这在Web应用程序和API开发中非常常见。
闭包场景:
1.保留状态信息:闭包可以用来保存函数的状态信息,使函数在不同调用之间保持一致的状态。
def counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment # 创建一个计数器实例 c = counter() # 调用计数器函数,每次调用都会增加计数器的值 print(c()) # 输出: 1 print(c()) # 输出: 2 print(c()) # 输出: 32.实现私有变量:由于闭包的特性,内部函数可以访问外部函数的变量,但外部函数无法直接访问内部函数的变量。
def private_variable(value): def get(): return value def set(new_value): nonlocal value value = new_value return get, set # 创建一个私有变量实例 get_value, set_value = private_variable(10) # 获取私有变量的值 print(get_value()) # 输出: 10 # 修改私有变量的值 set_value(20) print(get_value()) # 输出: 203.封装函数逻辑:闭包可以将一些逻辑封装在内部函数中,并提供一个简洁的接口给外部调用。
def fibonacci(): a, b = 0, 1 def next_number(): nonlocal a, b result = a a, b = b, a + b return result return next_number # 创建一个斐波那契数列生成器 fib = fibonacci() # 生成斐波那契数列的前10个数 for _ in range(10): print(fib()) # 输出: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
参考链接:https://blog.csdn.net/weixin_41622043/article/details/103426652