面试总结-python基础语法

说说什么是解释性语言,什么是编译性语言?

计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。

解释性语言在运行程序的时候才会进行翻译。

编译型语言写的程序在执行之前,需要一个专门的编译过程,把程序编译成机器语言(可执行文件)。

说说Python中可变与不可变类型?

Python可变类型是列表、集合、字典,不可变有字符串(string)、元组(tuple)、数字(int,float)。

说说进程与线程?
  1. 进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。

  2. 线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而**多个线程共享内存(数据共享,共享全局变量),**从而极大地提高了程序的运行效率。

说说多进程和多线程之间的通信方式?
多进程间的通信方式:
  1. 管道(Pipe):这是最简单的通信方式,数据只能在一个方向上流动,而且只能在有共同祖先的两个进程之间使用。
  2. 命名管道(named pipe): 它与匿名管道相似,不同之处在于它可以用于没有相关性的进程之间的通信。
  3. 信号(Signal):这是一种比较复杂的通信方法,用于通知接收进程某个事件已经发生。
  4. 消息队列(Message Queue):它是由消息的链表,存放在内核中并由进程id来引用。
  5. 共享内存(Shared Memory):它允许多个进程访问同一块内存空间。
  6. 套接字(Socket):它是在网络中不同主机的进程进行双向通信的主要方式。
  7. 信号量(Semaphore):主要作为进程间以及同一进程内不同线程之间的同步手段。
  8. 文件锁(File-locking):可以用来解决多进程同时读写文件的问题。
多线程间的通信方式:
  1. 锁机制(Locks):通过互斥锁(mutex)、读-写锁(rwlock)等锁机制来实现线程间的同步。
  2. 条件变量(Condition Variables):它可以允许一个线程就某个条件(通常是共享资源的状态)进行等待,当条件发生(或者说满足)时,另外的线程可以唤醒一个或多个正在等待的线程。
  3. 信号量(Semaphore):信号量也可以用在多线程之间进行同步,尤其适用于控制对有限数量的资源的访问问题。
  4. 屏障(Barrier):屏障是一种简单的同步方式,它允许多个线程在某个点上进行同步。
  5. 消息传递(Message Passing):线程之间可以通过队列,链表等数据结构进行数据交换和通信。
进程的实现方式:

进程是操作系统进行资源分配和调度的基本单位,不同的操作系统对进程的实现方式有各自的特点。在大多数现代操作系统中,如Linux,Windows等,进程的实现主要涉及以下几个方面:

  1. 进程控制块(Process Control Block, PCB):每个进程都有一个进程控制块来存储与该进程相关的信息,如进程状态、程序计数器、CPU寄存器值、优先级、内存指针(指向该进程的代码段和数据段)等。
  2. 进程状态管理:操作系统需要跟踪并控制每个进程的状态。常见的进程状态包括新建(new)、运行(running)、等待(waiting)、就绪(ready)和终止(terminated)。
  3. 调度:操作系统决定何时以及如何将CPU等资源分配给进程,这通常由一些调度算法完成,如先来先服务(FCFS)、短作业优先(SJF)、轮转(RoundRobin)等。
  4. 上下文切换:当CPU从一个进程切换到另一个进程时,操作系统会保存当前进程的状态,并加载即将运行的进程的状态,这就是上下文切换。
  5. 创建和终止:操作系统提供了创建和终止进程的机制。例如,在Unix或Linux系统中,可以使用fork()系统调用来创建新的进程,使用exit()或者kill()来终止进程。
  6. 同步和通信:操作系统提供了各种机制让进程能够进行同步和通信,如信号量、管道、消息队列、共享内存等。
  7. 内存管理:每个进程都有自己的独立地址空间,操作系统需要对其进行管理,包括分配、回收以及保护不被其他进程侵入。
说说Python中的多线程?

Python在任意时刻,只有一个线程在解释器中运行。
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。 多线程共享主进程的资源,所以可能还会改变其中的变量,这个需加上线程锁,每次执行完一个线程再执行下一个线程。一个CPU在同一个时刻只能执行一个线程,但是当遇到IO操作或者运行一定的代码量的时候就会释放全局解释器锁,执行另外一个线程。

为什么要有GIL锁?

为了保证内存管理中引用计数的一致性。

GIL 的设计是为了解决 Python 的多线程环境中的同步问题。在 Python中,所有的数据都是全局的,如果多个线程同时访问和修改共享数据,可能导致不一致性和数据损坏。

GIL 的设计是为了避免这种情况,使得所有的线程在任意时刻只有一个线程在执行 Python 代码。这保证了在多线程环境中,所有数据的一致性。

说说Python中的多进程?

Python中的多进程是通过multiprocessing包来实现,每个进程中所有数据(包括全局变量)都各自拥有一份,互不影响。它可以利用Process类来创建一个进程对象。

进程对象的方法和线程对象的方法差不多,也有start(), run(),join()等,但是,Thread线程对象中的守护线程方法是setDeamon,而Process进程对象的守护进程是通过设置daemon属性来完成。

说说Python互斥锁与死锁?

互斥锁:即确保某段关键代码的数据只能又一个线程从头到尾完整执行,保证了这段代码数据的安全性,但是这样就会导致死锁。

死锁:多个子线程在等待对方解除占用状态,但是都不先解锁,互相等待,这就是死锁。

怎么避免僵尸进程?

僵尸进程是指已经完成执行并终止,但父进程还未对其进行清理的进程。这些进程在进程表中仍然占用条目,因为它们还有一个退出状态需要父进程读取。

使用wait()函数:当子进程结束后,父进程可以通过调用wait()或waitpid()函数来获取子进程的退出状态,从而使子进程不再为僵尸进程。这个函数会导致父进程阻塞,直到一个子进程结束。

python中使用join()函数

说说Python的深拷贝与浅拷贝?

不可变对象:一旦创建就不可修改的对象,包括字符串、元组、数值类型。

可变对象:可以修改的对象,包括列表、字典、集合(该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的地址,通俗点说就是原地改变。)

当对象的值发生变化,但内存地址没有改变时,则说明是可变类型

当对象的值发生变化,内存地址也发生改变时,则说明是不可变类型

浅拷贝:创建新对象,其内容是原对象的引用。

深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。

浅拷贝之所以称为浅拷贝,是它仅仅只拷贝了一层,拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已,在lst中有一个嵌套的list[3,4],如果修改了它,情况就不一样了。

当浅拷贝的值是可变对象(列表、字典、集合)时会产生一个“不是那么独立的对象”存在。有两种情况:

第一种情况:复制的对象中无复杂子对象[1,2,3,4,5,6],原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。

第二种情况:复制的对象中有复杂子对象(例如列表中的一个子元素是一个列表[1,2,3,[4,5],6]),如果不改变其中复杂子对象,浅复制的值改变并不会影响原来的值。但是改变原来的值中的复杂子对象的值会影响浅复制的值。

说说Python中yeild和return的区别?

共同点:return和yield都用来返回值;在一次性地返回所有值场景中return和yield的作用是一样的。

不同点:如果要返回的数据是通过for等循环生成的迭代器类型数据(如列表、元组),return只能在循环外部一次性地返回,yeild则可以在循环内部逐个元素返回(yield函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行)

说说Python中set的底层实现?

散列表/哈希表。set只是默认键和值是相同的

注:散列表是根据关键字而直接进行访问值的数据结构。也就是说散列表建立了关键字和存储地址之间的一种直接映射关系。

# 使用set去重
my_list = [1, 2, 2, 3, 3, 4, 5, 5]
my_list = list(set(my_list))
print(my_list)  
说说Python中字典与set区别?

1.字典是一系列无序的键值对的组合;集合set()里的元素默认键值是一样的,是单一的一个元素。
2.从python3.6后,字典有序;集合无序
3.字典键不能重复;集合set()元素不能重复

说说Python中__init__和__new__和__call__的区别?

__init__是初始化方法

__new__实例化对象

__call__允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.call() 是相同

构造方法=创建对象+初始化对象=new+init

__new__方法是在实例创建之前被调用,是一个静态方法,主要的功能就是创建一个类的实例并返回

__init__方法是在实例创建之后被调用,主要的功能是设置实例的一些属性初始值

实际测试:__new__在__init__之前被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数(self),然后__init__给这个实例(self)设置一些参数

说说Python 中的is和==区别?

is比较的是两个对象的id值是否相等,也就是比较两个对象是否为同一个实例对象,是否指向同一个内存地址。

==比较的是两个对象的内容是否相等,默认会调用对象的eq()方法。

说说函数调用参数的传递方式是值传递还是引用传递?

Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。 函数的传值到底是值传递还是引用传递、要分情况:

不可变参数用值传递:像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象。

可变参数是引用传递:比如像列表,字典这样的对象是通过引用传递、和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变。

说说对缺省参数的理解?

缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。

*args是不定长参数,它可以表示输入参数是不确定的,可以是任意多个。它将所有传入的位置参数封装为一个元组

**kwargs是关键字参数,赋值的时候是以键值对的方式,参数可以是任意多对在定义函数的时候

def foo(*args):
    print(args)

foo(1, 2, 3) # (1, 2, 3)
foo('a', 'b', 'c') 

def bar(**kwargs):
    print(kwargs)

bar(a=1, b=2, c=3) # {'a': 1, 'b': 2, 'c': 3}
bar(name='Alice', age=18) # {'name': 'Alice', 'age': 18}
说说Python中什么元素为假?

0,空字符串、空列表、空字典、空元组、None、False

说说lambda函数?

在Python中,lambda函数是一种匿名函数,它可以在需要时动态创建,通常用于一次性的、简单的函数调用。

# 使用lambda函数进行列表排序
lst = [(1, 3), (2, 2), (3, 1)]
lst.sort(key=lambda x: x[1])
print(lst) # [(3, 1), (2, 2), (1, 3)]

# 使用lambda函数过滤列表
lst = [1, 2, 3, 4, 5, 6]
result = list(filter(lambda x: x % 2 == 0, lst))
print(result) # [2, 4, 6]

# 使用lambda函数进行列表映射
lst = [1, 2, 3, 4, 5]
result = list(map(lambda x: x * 2, lst))
print(result) # [2, 4, 6, 8, 10]

add = lambda x, y: x + y
result = add(3, 5)
print(result) # 8
说说垃圾回收机制

Python采用了自动垃圾回收机制,它可以自动检测和回收不再使用的对象,从而释放内存空间。

Python的垃圾回收机制基于引用计数,即每个对象都有一个引用计数器,记录当前有多少个引用指向这个对象。当一个对象的引用计数器变为0时,即没有任何引用指向它时,这个对象就变成了垃圾,可以被回收。Python会定期检查所有的对象,将引用计数器为0的对象回收。

此外,Python还采用了循环引用垃圾回收机制,以解决对象之间存在循环引用的问题。当两个或多个对象之间互相引用,但没有其他引用指向它们时,这些对象就成了不可达对象。Python的垃圾回收机制会检测这些不可达对象,并将它们回收。

Python的垃圾回收机制还包括了分代回收机制,即将对象分为不同的代,每个代使用不同的垃圾回收策略。新创建的对象通常被分配在0代,随着时间的推移,如果它们仍然存在,它们将被移到更高的代,最终在某一代中被回收。

迭代器和生成器

迭代器:

  • 迭代器,英文 Iterator,它首先是个对象,其次它是访问可迭代序列(Iterable)的一种方式。通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。
  • 迭代器又是一个特殊的对象,特殊在于它必须实现两个方法: __ iter__和__next__.

迭代器几个特点

  • 是有去无回的,迭代器只能前进不能回退!也就是说一旦迭代结束,要想再使用此迭代器对象从头开始遍历元素,将是不可行的!
  • 迭代器无需提前知道整个列表的所有元素,
  • 无需加载所有元素到RAM中尽而它是节省内存的(memory-efficient).

生成器:

  • 生成器对象(generator object)一定也是迭代器对象(Iterator object)创建生成器的几种方法
  • 生成器:使用了 yield 的函数被称为生成器(generator),在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next()
    方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

如果数据集有某种逻辑,就不必存储在一个列表中,只需编写一个生成器,它将在需要时生成这些值,基本不占用内存。

带参装饰器和非带参装饰器:

装饰器在Python中是一个非常强大的功能,可以用来修改或增强函数的行为。带参数和不带参数的装饰器都有共同的目标,但它们的实现方式和使用场景有所不同。它的价值在于为原函数f增加一些行为,前提必须不能破坏函数f,所以肯定不能改变f的内部结构,所以只能在调用f前后定义一些行为。

不带参数的装饰器:

这是最基础的装饰器形式,它接收一个函数,并返回一个新的函数。

def my_decorator(func):
    def wrapper():
        print("Something before the function call")
        func()
        print("Something after the function call")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

带参数的装饰器:

如果你想让装饰器接受自定义的参数,那么你需要在编写装饰器时多加一层嵌套。

def decorator_with_args(dec_arg1, dec_arg2):
    def actual_decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Decorator argument 1 = {dec_arg1}")
            print(f"Decorator argument 2 = {dec_arg2}")
            func(*args, **kwargs)
        return wrapper
    return actual_decorator

@decorator_with_args("arg1", "arg2")
def say_hello(name):
    print(f"Hello, {name}")

在这个例子中,装饰器decorator_with_args接受两个参数,并在调用被装饰的函数之前打印这些参数。这使得装饰器的行为可以更容易地进行自定义。

总结起来,不带参数的装饰器是一种简单的方式,用于在不改变原始函数代码的情况下添加一些通用的功能,比如日志或计时等;而带参数的装饰器则提供了更高的灵活性,允许我们定制装饰器的行为。

docker怎么实现隔离?

Docker 使用 Linux 内核的特性来提供其容器的隔离。以下是 Docker 如何使用这些特性进行内存等资源的隔离的一般概述:

1. cgroups(控制组):

Docker 使用 Linux 的 cgroups 功能来限制和隔离资源,包括 CPU、内存、磁盘 I/O 等。cgroups 允许Docker 对每一个容器分配可用资源的子集。

例如,对于内存,你可以使用 --memory参数在运行容器时设置内存限制。当容器达到这个限制时,它不会被允许使用更多的内存。这样可以防止一个容器耗尽系统的所有内存,影响其他容器或主机系统。

docker run -it --memory=2g ubuntu:18.04

2. namespaces (命名空间):

Docker 使用 Linux 的命名空间功能来提供工作区的隔离。不同的命名空间关注不同的隔离方面,例如 PID 命名空间隔离进程ID,NET 命名空间隔离网络接口,MNT 命名空间隔离挂载点等。

每个容器运行在各自独立的命名空间下,从而实现相互隔离。例如,每个容器都有自己的网络栈,所以每个容器都可以有自己的 IP地址、路由规则等,并且不会影响其它容器或者主机。

通过这两大机制,Docker 保证了每个容器都在独立安全的环境中运行,仿佛它们各自运行在自己的操作系统中,确保了资源的有效隔离和管理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值