python 面试题总结

python是强类型语言,因为他不允许不用类型的数据相加,又有说python是弱类型语言,因为变量声明的时候不需要加上类型,数据类型是由右边的值决定的。

可变与不可变类型

主要核心类型中,数字,字符串,元组是不可变的,列表,字典,集合是可变的。
对不可变的类型重新赋值,实际上是重新创建一个不可变类型的对象,并将原来的变量重新指向新创建的对象 (如果没有其他变量引用原有对象的话(即引用计数为0),原有对象就会被回收)。

浅拷贝与深拷贝的实现方式、区别

实现方式:赋值:list1 = [1,2,3] list2 = list1 两个指针指向同一个内存地址。
浅拷贝:list1 = [[1,2,3],4,5] list2 = list.copy() list1和list2内存地址不同,但是里边嵌套的列表内存地址相同。
深拷贝:list1 = [[1,2,3],4,5] list2 = list1.deepcopy() list1和list2内存地址不用,里边嵌套的列表也不同。

new() 与 init()的区别;

init()是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
new()是在实例被创建前调用,因为它的任务就是创建实例然后返回该实例,是个静态方法。
也就是说,new()在init()之前被调用,new()返回的实例将会传递给init()的第一个参数,然后init()在初始化对象的属性。
我们可以把类当做制造商,__new__方法就是前期的原材料购买环节,__init__方法就可以在原材料的基础上进行加工,初始化商品。

你知道几种设计模式;

策略模式、适配器模式、工厂模式、装饰器模式、单例模式
策略模式:
策略模式是一种与行为相关的设计模式,允许你在运行时根据指定的上下文确定程序的动作。可以在两个类中封装不同的算法,并在程序运行时确定具体使用哪一种。
适配器模式:
适配器模式是一个结构性的设计模式,允许通过不同的接口为一个类赋予新的用途,这使得使用不同调用方式的系统都能够使用这个类。
将一个接口转换为客户希望的另一个接口,该模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
工厂模式:
工厂模式是一种创建型的设计模式,作用如其名称:就像工厂一样生产对象实例的类。
这个模式的主要目的是将可能设计到很多类的对象的创建过程封装到一个单独的方法中,通过给定的上下文输出指定的对象实例。
装饰器模式:
装饰器模式是一个结构性模式,允许我们根据情况,在运行时为一个对象添加新的或者附加的行为。
目的是为给一个特定的对象实例应用扩展的函数方法,并且同时也能够产生没有新方法的原对象。
单例模式:
单例模式是一个创见型的模式,功能是确保运行时对某个类只存在一个实例对象,并且提供一个全局访问点来访问这个实例对象。
因为对于调用单例的其他对象而言,这个全局唯一的访问点“协调”了对单例对象的访问请求,所以调用者看到的单例内变量将会是同一份。

列表推导式和生成器的优劣;

列表推导式是将所有的值一次性返回。数据量太大的话会占用很多的内存。
生成器式将列表推导式的[]改成(),不会将所有的值一次性的返回,一次返回一个结果。
列表推导式可以遍历任意次,生成器只能遍历一次

generator = (i for i in range(1,5))
print(next(generator))
print(next(generator))
for i in generator:
    print(i)
for i in generator:
    print(i)
    
打印结果:
1
2
3
4

什么是装饰器

在不改变原有函数结构的前提下,给函数添加一个额外的功能。

实现单例模式的几种方式。

一、使用模块:

把相关的函数和数据定义在一个模块中,要使用的时候,直接在其他文件中导入此文件中的对象,这个对象就是单例模式的对象。

二、使用装饰器实现:
def test(cls):
            instance = {}
            def _test(*args, **kwargs)
                if cls not in instance:
                    instance[cls] = cls(*args, **kwargs)
                return instance[cls]
            return _test
三、基于__new__方法实现
class Singleton(object):
    _instance = None
    _first_init = False
    def __init__(self, name):
        # 如果_first_init = False,初始化实例属性
        if not Singleton._first_init:
            self.name = name
            Singleton._first_init = True
    def __new__(cls, *args, **kwargs):
        # 如果实例为空,创建它
        if not cls._instance:
            cls._instance = object.__new__(cls)
        # 否则只是返回第一次创建的实例
        return cls._instance
obj1 = Singleton('a')
obj2 = Singleton('b')
print(obj1,obj2)

python实现多线程

import threading # threading模块是使用多线程的前提
import time
def music(func):
    for i in range(2):
        print("I was listening to %s. %s"% (func, time.time()))
        time.sleep(1)
def move(func):
    for i in range(2):
        print("I was at the %s! %s"% (func, time.time()))
        time.sleep(5)
threads = [] # 创建threads数组,创建线程t1,使用threading.Thread()方法,这个方法中target=music,args方法对music进行传参,把创建好的线程装到threads数组中。接着以同样的方法创建线程t2
t1 = threading.Thread(target=music, args=('爱情买卖',))
threads.append(t1)
t2 = threading.Thread(target=move, args=('阿凡达',))
threads.append(t2)
if __name__ == '__main__':
    for t in threads: # 通过for循环遍历数组,(数组被装载了t1和t2两个线程)
        t.setDaemon(True) # 将线程声明为守护线程
        t.start() # 开始线程活动
    t.join() #join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。注意: join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。
print("all over %s" % time.time())

介绍下垃圾回收:引用计数/分代回收/孤立引用环;

当python某个对象引用计数为0,说明该对象无引用,python会自动启动"垃圾回收",将无用的对象冲内存中清除,但是频繁的垃圾回收,会大大降低python的工作效率,所以,python只在特定的条件下自动启动垃圾回收。

引用计数:

python是根据引用计数自动管理内存的。可通过sys包中的getrefcount(对象名)来查看某个对象的引用计数(查看引用计数的时候, 在使用sys.getrefcount()函数时,函数会引用一次, 所以会比预期的引用计数多一个,如果查看的是数字或者字母,因为他们在系统中属于常驻内存,为公用对象,所以输出的结果比较特殊)。如果一个对象的引用计数为0,则该对象会被解释器进行回收,对象在内存中消失。当对象被创建的时候,引用计数+1,当对象被其他指针引用的时候,+1,当对象的引用被删除的时候。引用计数-1
python内置关键字del删除的是对象的引用,而不是内存中的对象。

分代回收:

分代回收策略,该策略假设,存活时间越长的对象,越不可能在后边的程序中变成垃圾。python将所有的对象分为0,1,2三代对象。所有新建的对象都是0代对象,当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象,垃圾回收启东时,一定会扫描所有的0代对象,如果0代对象经过一定次数的垃圾回收,那么就启动对0代和1代的扫描清理,当1代也经历了一定次数垃圾回收后,那么就启动对0,1,2代,即所有对象进行扫描。

孤立引用环:
例如:
list1 = [1,2,3]
list2 = list1
list1.append(list2)
del list1
del list2

这两个列表对象相互引用,形成孤立的引用环,当删除list1,list2的时候,以上两个列表在程序中将无法被调用,但是其实引用计数并不为0,不会被垃圾回收
为了回收这样的引用环,python复制每一个对象的引用计数,然后python遍历所有的引用环涉及到的对象,该出仅有list1和list2,当遍历到list1是,由于list1引用了list2,故将list2的引用计数减1,同理,当遍历到list2的时候讲list1的引用计数减1,结果它们的值都为0,最后将不为0的对象保留,为0的对象进行垃圾回收。

多进程与多线程的区别;CPU密集型适合用什么;

进程:进程是程序在计算机上的一次执行活动,当运行一个程序的时候,就启动了一个进程。
多线程:在单个程序中同时运行多个线程完成不同的工作
线程共享内存空间,进程的内存是独立的。
同一个进程的线程之间可以相互交流,两个进程想通信,必须通过一个中间代理来实现。
一个线程可以操作同一个进程里的其他线程,但进程只能操作子进程。
优缺点:
1.
多进程的优点是稳定性好,一个子进程崩溃了,不会影响主进程和其他进程,但是缺点是创建进程的代价非常大,因为操作系统要给每一个进程分配固定的资源。
2.
多线程的优点是效率高,但是缺点是任何一个线程崩溃都可能造成整个进程的崩溃,因为他们共享了进程的内存池。

CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多
IO密集型指的是系统的CPU性能相对硬盘、内存要好很多
CPU密集型适合用多线程开发

进程通信的方式有几种;

共享存储器系统, 管道通信系统, 消息传递系统, 客户机服务器系统

介绍下协程;

从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协程中, yield 通常出现在表达式的右边(例如, datum = yield),可以产出值,也可以不产出 —— 如果 yield 关键字后面没有表达式,那么生成器产出 None。

协程可能会从调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是next(…) 函数。
yield 关键字甚至还可以不接收或传出数据。不管数据如何流动, yield 都是一种流程控制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激活其他的协程
最先调用 next(sc) 函数这一步通常称为“预激”(prime)协程(即,让协程向前执行到第一个 yield 表达式,准备好作为活跃的协程使用

使用协程计算移动平均值
def average():
    total = 0.0
    count = 0
    avg = None
    while True:
        num = yield avg
        total += num
        count += 1
        avg = total / count
ag = averager()
# 预激协程
print(next(ag)) # None 也可以ag.send(None)效果和next(ag)一样。j
# print(ag.send(None))
print(ag.send(10)) # 10 执行到第二个yield表达式停止。
print(ag.send(20)) # 15 如果后边没有yield表达式则生成器对象会抛出StopIteration的异常(停止迭代),异常对象的 value 属性保存着返回的值。 yield from 结构会在内部自动捕获 StopIteration 异常。对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把value 属性的值变成 yield from 表达式的值。
ag.close() # 终止协程
uwsgi 和 Nginx

uwsgi 可以看作是一个应用程序,帮助我们实现WSGI协议,Http协议,这样我们可以不再关注网络通信的底层实现,将精力更多放在处理HTTP请求数据,返回HTML。利用uWIGS可以是我们的web应用得到更强的并发能力

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器 其特点是占有内存少,并发能力强
它具有反向代理服务器的所有特点,并且配置简单,支持对大于1kb的文件进行压缩,静态文件缓存,可以大大提高访问效率。Nginx接受来自客户端的Http请求发送给uWSGI,uWSGI处理请求并将关键信息传递给web应用(django,flask等),应用返回Response经由uWSGI发送给Nginx,Nginx再发送给客户端。
Nginx常用命令:
sudo service nginx start 启动Nginx服务器
sudo service nginx stop 停止nginx服务器
sudo service nginx status 查看nginx服务状态
service nginx restart

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值