hechengQAQ

导航

 

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.谈谈对缺省参数的理解?
 缺省参数表示默认参数,当在对应位置传了参数,就使用这个参数,若没有传参,就使用默认设置的参数
21.break和continue的区别?
break代表循环的结束,终止符,而continue表示跳过当前循环进入下一个循环
 22.is 和 ==的区别?
==判断是否相等,而is不仅判断是否相等,还判断id内存地址是否相等,两者都相等了才返回True
23.__new__() 和 __init__()的区别?
两者在对象实例化的时候会调用,__new__是构造函数,创建实例化的时调用,有一个cls参数代表当前类,必须要有返回值;__init__是初始化函数,创建实例化后调用,有一个self参数代表当前实例,不需要有返回值。
24.yieldreturn的相同点和区别?
相同点:都是返回程序的执行结果;
区别:yield返回结果但程序还没有结束,return返回结果表示程序已经结束执行
25.列举5个python常用标准库并说明其作用?
  • os:提供不少于操作系统相关联的函数
  • sys:提供了访问Python解释器相关信息的接口,比如命令行参数、标准输入输出等。通常用于命令行参数。
  • datetime:日期时间
  • re:正则匹配
  • math:数学运算
  • unitest:进行模块的单元测试
  • random:提供生成伪随机数的函数
  • threading:多线程编程相关功能
  • time:提供了时间相关的函数和类,比如计时器
  • json:提供对json数据的序列化反序列化操作
  • socket:提供了网络编程相关的功能,比如创建 TCP/UDP 连接等。
  • logging:提供了日志记录相关的功能。
 
26.谈谈你知道的几种设计模式?

单例模式:保证一个类仅有一个实例,并提供一个访问他的全局访问点。
装饰器模式:不修改元类代码和继承的情况下动态扩展类的功能。
迭代器模式: 提供一个方法顺序访问一个聚合对象中各个元素。

 
27.python2与python3区别?
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 run

3.缓存:装饰器可以用于缓存函数的计算结果,以便在相同的输入参数下避免重复计算。这对于提高性能和减少计算时间很有帮助。

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)  # 输出:120

4.认证和权限控制:装饰器可以用于验证用户的身份和权限,以确保只有授权用户才能访问某些功能。这在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())  # 输出: 3

2.实现私有变量:由于闭包的特性,内部函数可以访问外部函数的变量,但外部函数无法直接访问内部函数的变量。

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())  # 输出: 20

3.封装函数逻辑:闭包可以将一些逻辑封装在内部函数中,并提供一个简洁的接口给外部调用。

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

 
posted on 2023-04-13 16:45  hechengQAQ  阅读(12920)  评论(1编辑  收藏  举报