一个python面试笔试题

init 和 new 的作用和返回值?详细描述一下类的创建过程?如何捕获类的属性定义顺序?

__new__在创建实例对象的时候调用,返回实例对象的内存地址,传递给__init__方法,就是self的值,
__init__方法是在实例对象初始化的时候调用,没有返回值
第一种回答:
1. 解析 MRO 记录(Resolving MRO entries)
      根据 MRO 规则解析继承关系
2. 确定元类(Determining the appropriate metaclass)
      查找元类的过程遵循以下规则:
      如果没有基类且没有指定 metaclass ,则使用 type()
      如果指定了 metaclass 且它不是 type() 的实例,则直接使用 metaclass
      如果指定了 type() 实例的 metaclass 或者有基类
3. 准备命名空间(Preparing the class namespace)
      当元类确定后,类的命名空间也可以确定了。
      如果元类有 __prepare__ 属性,则 namespace = metaclass.__prepare__(name, bases, **kwargs),
      否则命名空间会初始化为有序的空map(empty ordered mapping.)
4. 执行 Class 内语句(Executing the class body)
      类内的语句通过 exec(body, globals(), namespace) 来执行。
      与正常的 exec() 不同的是当类定义在一个函数内部时其可以访问当前和外层的作用域。

      即使在函数内定义的类,其内部的方法也无法访问类的作用域。
      类内的定义的变量通过类实例或类对象来访问,或者通过 __class__
5. 创建类对象(Creating the class object)
      经过以上步骤后,通过 metaclass(name, bases, namespace, **kwargs) 来创建类。
6. 关于 __init

第二种回答:
创建类实例过程:
      1、先通过类的原类的__new__方法来创建类对象
      2、在通过类的原类的__init__方法来实现对类对象的属性以及方法的赋值
      3、通过调用类的原类的__call__方法来实现对类对象的__new__方法以及__init__方法的调度
      4、调用类对象的__new__方法实现类的实例
      5、调用类对象的__init__方法实现类实例的属性以及方法的赋值 
有一个元类方法__prepare__,默认情况下,type构造方法及元类的__new__,__init__方法会收到类的
定义体,形式是名称到属性的映像,这个映射是字典,所以,这个定义体都是无序的。
声明这个类方法后,里面返回一个collections.OrderedDict()字典,就可以实现顺序记录,这个方法是在__new__方法前执行的

WSGI 概念,django 的一个 app 是单线程还是多线程,flask 呢?如果有tornado经验,可以考察下tornado的请求处理流程,比如一个get请求过来后,是如何到达server的handler处理?

[](https://blog.csdn.net/Scrat_Kong/article/details/81590318)
[](https://www.cnblogs.com/konghui/p/10574945.html)
web服务器:
    负责处理http请求,响应静态文件,常见的有Apache,Nginx以及微软的IIS.
应用服务器:
    负责处理逻辑的服务器。比如python的代码,是不能直接通过nginx这种web服务器来处理的,
    只能通过应用服务器来处理,常见的应用服务器有uWSGI、tomcat等。
web应用框架:
    一般使用某种语言,封装了常用的web功能的框架就是web应用框架,
    flask、Django以及Java中的SSH(Structs2+Spring3+Hibernate3)框架都是web应用框架。
        
WSGI全称是Web Server Gateway Interface
    是一种规范,描述web server如何与web application通信的规范。
    实现WSGI协议,必须同时实现web server和web application。Flask, Django用的就是这个协议。
uwsgi:
    与WSGI一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),
    每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。
uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。

WSGI协议主要包括server和application两部分:
    WSGI server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端;
    WSGI application接收由server转发的request,处理请求,并将处理结果返回给server。
        
WSGI协议其实是定义了一种server与application解耦的规范,
即可以有多个实现WSGI server的服务器,也可以有多个实现WSGI application的框架,
那么就可以选择任意的server和application组合实现自己的web应用。
app.run(port=5679, debug=app.config["DEBUG"], threaded=True, processes=2)
# from werkzeug.serving import run_simple
首先每次请求进来之后,对于每次请求进来之后,都会执行Flask类实例的__call__方法, 用来返回实例化的类
然后在上下文中, 要完成的操作是:
    对原生请求进行封装,生成视图函数可操作的request对象
    获取请求中的cookie信息,生成Session对象
    执行预处理函数和视图函数
    返回响应结果
    
    创建请求上下文的对象
    将请求上下文和应用上下文入栈(有两个栈)
    根据请求的URl执行响应的视图函数,返回执行结果
    将请求上下文和应用上下文出栈

检查网络是否通畅用什么工具,该工具用什么协议,如果该工具/协议失效,是否一定是网络不通

[](https://zhuanlan.zhihu.com/p/44443115)
ping

使用的是ICMP协议,是“Internet Control Message Protocol”(Internet控制消息协议)的缩写,
是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

利用的原理是这样的:
    利用网络上机器IP地址的唯一性,给目标IP地址发送一个数据包,
    再要求对方返回一个同样大小的数据包来确定两台网络机器是否连接相通,时延是多少。
主机不存活
防火墙

python 的解释器锁是什么,协程工作的操作系统原理,启动一个 ptyhon 进程消耗 CPU 资源能否突破 100%?

Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,
Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,
即在任意时刻,只有一个线程在解释器中运行。
对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
    
在多线程环境中,Python 虚拟机按以下方式执行:
    1. 设置GIL
    2. 切换到一个线程去运行
    3. 运行:
        a. 指定数量的字节码指令,或者
        b. 线程主动让出控制(可以调用time.sleep(0))
    4. 把线程设置为睡眠状态
    5. 解锁GIL
    6. 再次重复以上所有步骤

在调用外部代码(如C/C++扩展函数)的时候,GIL 将会被锁定,
直到这个函数结束为止(由于在这期间没有Python 的字节码被运行,所以不会做线程切换)
[](https://www.cnblogs.com/russellyoung/p/python-zhi-xie-cheng.html)
协程:
    是单线程下的并发,又称微线程,纤程。英文名Coroutine。
    一句话说明什么是协程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

需要强调的是:
    python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,
切换其他线程运行)
    单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,
以此来提升效率(!!!非io操作的切换与效率无关)

对比操作系统控制线程的切换,用户在单线程内控制协程的切换
    优点:
        1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
        2. 单线程内就可以实现并发的效果,最大限度地利用cpu
    缺点:
        1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,
        每个进程内开启多个线程,每个线程内开启协程
        2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
总结协程的特点:
    必须在只有一个单线程里实现并发
    修改共享数据不需加锁
    用户程序里自己保存多个控制流的上下文栈
附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,
就用到了gevent模块(select机制))
我没遇到过
    答案是有可能的。
    python单进程多个子线程随机读文件的情况下,
    每个线程都在抢占GIL锁,
    每个线程抢占后又大都在等待IO,
    导致时间片极短,
    系统频繁的调度切换,
    所以CPU sys use比较高,
    算在python进程上top里CPU显示就超过100%了。
    但只看CPU user use,还是不会超过100%的。
    综上,在IO密集型的任务里,会出现超过100%的情况。但是计算密集型则一般不会。
posted @ 2020-10-12 00:37  SBJBA  阅读(192)  评论(0编辑  收藏  举报