• 面试题--基础


    面试情况

    目录

    热点考题

    1.什么是反向代理?

    # web 服务器中,部署的方式大致类似,主要就是使用Nginx 实现分流,转发,负载均衡,以及分担服务器的压力。Nginx部署简单,内存消耗少,成本低。Nginx既可以做正向代理,也可以做反向代理
    
    #正向代理:请求经过代理服务器从局域网发出,然后到达互联网上的服务器
     特点:服务端不知道真正的客户端是谁
     作用:1.访问本来无法访问的服务器
    	  2.加速访问服务器
          3.cache作用(正向/反向都是用缓存技术):如果用户A访问服务器B上的某数据J之前,已经有人通过代理服务器得到数据J,那么代理服务器就会把数据保存一段时间,这是代理服务器就会把缓存的数据直接发送给用户A,专业术语(cache命中)
    # 反向代理:请求从互联网出发,先进入代理服务器,在转发给局域网内的服务器
     特点:客户端并不知道真正的服务端是谁
     作用:1.保护和隐藏原始资源服务器:(如图2.1)用户A始终认为他访问的是原始服务器B而不是代理服务器Z,但实际上反向代理服务器接收用户A的应答,从原始资源服务器B中取得用户A的需求资源,然后发送给用户A,由于防火墙的作用,只允许代理服务器A访问原始资源服务器B,尽管这个虚拟环境下,防火墙和反向代理的共同作用保护了原始资源服务器B,但是用户A不知道
    	  2.负载均衡:(如图2.2)当反向代理服务器不知一个的时候,我们甚至可以把他们做成集群,让不同的代理服务器Z去应答不同的用户,然后发送不同用户需要的资源
    当然反向代理服务器像正向代理服务器一样拥有CACHE的作用,它可以缓存原始资源服务器B的资源,而不是每次都要向原始资源服务器B请求数据,特别是一些静态的数据,比如图片和文件,如果这些反向代理服务器能够做到和用户X来自同一个网络,那么用户X访问反向代理服务器X,就会得到很高质量的速度。(CDN的核心技术就是用反向代理)
    反向代理的结论:与正向代理正好相反,对于客户端而言它就是原始服务器,并且任何特别的设置。客户端向反向代理的命名空间发送普通请求,接着反向代理将判断向原始服务器转交请求,并将获取的内容返回给客户端,就像这些内容本来就是它自己的
    
    基本上,网上做正反向代理的程序很多,能做正向代理的软件大部分也可以做反向代理。开源软件中最流行的就是squid,既可以做正向代理,也有很多人用来做反向代理的前端服务器。另外MS ISA也可以用来在WINDOWS平台下做正向代理。反向代理中最主要的实践就是WEB服务,近些年来最火的就是Nginx了。网上有人说NGINX不能做正向代理,其实是不对的。NGINX也可以做正向代理,不过用的人比较少了。
    #区别:正向代理的对象是客户端,反向代理的对象是服务端
    
    # 透明代理:客户端根本不需要知道有代理服务器的存在,它改编了你的request fields(报文),并会传送真实IP,加密的透明代理是属于匿名代理,意思是不用设置代理了实践的例子:很多公司使用行为管理软件
    
    用户A和用户B并不知道行为管理设备充当透明代理行为,当用户A或用户B向服务器A或服务器B提交请求的时候,透明代理设备根据自身策略拦截并修改用户A或B的报文,并作为实际的请求方,向服务器A或B发送请求,当接收信息回传,透明代理再根据自身的设置把允许的报文发回至用户A或B,如图(3.1),如果透明代理设置不允许访问服务器B,那么用户A或者用户B就不会得到服务器B的数据。
    
    
    

    1560903041403

    1560903128640

    1560930957167

    1560931452738

    1560934310076

    2.谈谈你对多进程,多线程,以及协程的理解,项目是否用?

    #进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫做程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大
    # 多进程的使用使用场景:适合在CPU密集型操作(CPU操作指令比较多,比如:浮点运算)
    进程:并行(同一时刻多个任务同时运行)
    实现并行的库:mulitprocessing
    
    #线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,多核线程共享内存(数据共享,共享全局变量),从而极大的提高了程序的运行效率
    # 多线程的使用场景:适合在IO密集型操作(读写数据操作比较多的,比如爬虫)
    线程:并发(在同一时间段内多个任务都在运行,但是不会在同一时刻同时运行,存在交替执行的情况)
    实现并发的库:threading
    
    #协程:是一种用户态的轻量级线程,协程的调度完全由用户控制,协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下问和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快
    
    

    3.什么是多线程竞争?

    线程是非独立的,同一个进程里面线程是数据共享的,当各个线程访问数据资源时,会出现竞争状态时,数据几乎同步会被多个线程占用,造成数据混乱,造成线程不安全,就是多线程竞争
    
    
    

    锁和GIL

    # 怎么解决多线程竞争问题?--锁
    # 锁的好处:确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行,可以解决多线程资源竞争下的原子操作问题
    #锁的坏处:组织了多线程并发执行,包含锁的偶段代码实际只能以单线程模式执行,效率就大大地下降了
    锁的致命问题:死锁
    解释一下什么是锁?
    #锁(Lock):Python提供的对线程控制的对象。有互斥锁,死锁,可重入锁
    死锁:如果若干个子线程在系统资源竞争时,都在等待对方某部分资源接触占用状态,结果是都不愿意先解锁,程序就无法执行下去,这就是死锁(程序并没有挂掉)
    GIL锁:全局解释器锁(只有在Cpython中里面有)
    作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以Cpython里面的多线程其实是伪多线程,所以python里面常常用协程技术来代替多线程,
    
    #进程和线程的切换由系统决定的,而协程是由哦我们自己决定的,而模块gevent下切换是遇到耗时操作才会切换到
    三者的关系:进程里面有线程,线程里面有协程
    

    4.什么是线程安全,什么是互斥锁?

    每个对象对应于一个可称为“互斥锁”的标记,这个标记用来包保证在任一时刻只能由一个线程访问该对象
    
    同一个进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一个已经对其进行操作,导致最终结果出现错误,慈此时需要对被操作对象添加互斥u哦,保证每个线程对该对象的操作都得到正确的结果
    

    5.cpu,内存,硬盘之间的关系,例如在硬盘中有一个文件,里面只有两个数字1,如果要在页面上显示这个文件中的两个数相加,具体的流程是如何实现的

    内存:计算机内存储器,
    硬盘是属于计算机外存储器,
    CPU通常只和内存交换户据,断电后数据会丢失
    硬盘首先读取这个文件,将数字发送到内存中,内存将数据发送到CPU中进行数据处理,处理完成后发送到内存,再发送到硬盘中展示
    
    

    6.打开浏览器输入www.baidu.com,回车到页面展示百度页面的过程一共发生了什么

    # 1. 在浏览器中输入URL
    URL: 统一资源定位符,用于定位互联网的资源,主要包括:协议,网络地址,资源路径
    # 2. 域名解析
    浏览器不知道baidu.com是什么东西,需要查找百度所在服务器的IP地址,才能找到目标
    
    #为什么我们要使用域名而不是直接访问IP地址?(很简单:不好记)
    
    域名解析的流程:
    	浏览器缓存--浏览器有百度DNS则会缓存DNS,若没有转至下面
        系统缓存--从Host文件中查找对应的百度域名和IP,若没有转至下面
        路由器缓存--一般路由器也会缓存域名信息
        ISP DNS缓存 -- 例如到电信的DNS上查找缓存,如果没有找到则会向 根域名服务器查找域名对应IP
        
    # 3. 在本地dns服务器向顶级域.com发起请求,顶级域接收到请求,告诉本地dns服务器域名的解释服务器的地址,并不是告诉本地服务器域名和IP地址的对应关系
    # 4. 本地dns服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。
    # 5. IP地址返回给本地服务器处理请求,服务器一般都会安装一个用于接收处理请求的应用—web server常见的web server产品有apache、nginx等并且决定采用哪种方式来处理这个请求,读取请求,然后形成html响应。
    # 6. 客户端浏览器开始处理,解析渲染页面可视化
    

    7.数据库的外连接和内连接

    返回的结果集选取了两个表中所有相匹配的数据,舍弃了不匹配的数据。由于内连接是从结果表中删除与其他连接表中没有匹配的所有行,所以内连接可能会造成信息的丢失。内连接语法如下:
    select fieldlist from table1 [inner] join table2 on table1.column = table2.column
    
    外连接不仅包含符合连接条件的行,还包含左表(左连接时)、右表(右连接时)或两个边接表(全外连接)中的所有数据行。SQL外连接共有三种类型:左外连接(关键字为LEFT OUTER JOIN)、右外连接(关键字为RIGHT OUTER JOIN)和全外连接(关键字为FULL OUTER JOIN)。外连接的用法和内连接一样,只是将INNER JOIN关键字替换为相应的外连接关键字即可。
    内连接只显示符合连接条件的记录,外连接除了显示符合条件的记录外,还显示表中的记录,例如,如果使用左外连接,还显示左表中的记录。
    SELECT XXX FROM XXX LEFT [OUTER] JOIN XXX ON XXX
    
    
    

    8.redis常用的数据类型

    1561033558004

    在具体描述这几种数据类型之前,我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:
    
             首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示:
             type代表一个value对象具体是何种数据类型,
    
             encoding是不同数据类型在redis内部的存储方式,
    
             比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。
           这里需要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。通过上图我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给Redis不同数据类型提供一个统一的管理接口
        
        
    #String
    #Hash
    #List
    #Set
    #Sorted set
    #pub/sub
    #Transactions
    

    9.什么是RestFul?

    #REST: 是一种架构风格,一种Web Service可以满足REST的几个条件,通常就成这个系统是Resrful的
    #条件:C/S架构,无状态,可以cache,分层
    # REST的三要素:
    1.唯一的自然标识
    2.简单的方法
    3.一定的表达方式
    REST 是以 资源 为中心, 名词即资源的地址, 动词即施加于名词上的一些有限操作, 表达是对各种资源形态的抽象.
    以HTTP为例, 名词即为URI(统一资源标识), 动词包括POST, GET, PUT, DELETE等(还有其它不常用的2个,所以 整个动词集合是有限的), 资源的形态(如text, html, image, pdf等)
    
    RPC与REST的区别
    RPC:一般采用TCP通信协议,性能高,灵活性低
        以动词为中心的(就是一些方法:get、post)
        当你要需要加入新功能时,你必须要添加更多的动词, 这时候服务器端需要实现 相应的动词(方法), 客户端需要知道这个新的动词并进行调用.
    REST:一般采用HTTP通信协议,性能相对较低,灵活性高
        以名词为中心(一些资源的地址:URL)
        假使我请求的是 hostname/index/, 无论这个URI对应的服务怎么变化,客户端是无需 关注和更新的,而这种变化对客户端也是透明的.
        
    至于其它的区别,如对实现语言的依赖, 耦合性等,这些都是上面提到的这个根本区别所衍生的.
        
        当你每天使用HTTP冲浪时,你都在使用 REST 与远程的服务器进行亲密接触. 当你使用Gtalk和同事朋友沟通时,你则是在享受着 RPC 的便利.
        
    

    10.HTTP/HTTPS

    HTTPS和HTTP的区别主要如下:
    1.HTTPS需要ca申请证书,一般免费证书较少,因此需要一定费用
    2.HTTP是超文本传输协议,信息是铭文传输,HTTPS则是具有安全性的ssl加密传输协议
    3.HTTP和HTTPS使用的是完全不同的链接方式,用的端口不一样,前者是80 后者是443
    4.http的链接很简单是无状态的,HTTPS协议是SSL+http协议构建的可以进行加密传输,身份认证的网络协议,比http安全
    
    HTTP属于TCP/IP模型中的运用层协议,所以通信的过程其实是对应数据的入栈和出栈。 
    一、HTTP和HTTPS的基本概念
    HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
    HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
    HTTPS协议的主要作用:1.建立一个信息安全通道,来保证数据传输的安全;2.确认网站的真实性
    
    HTTP特点:1.支持客户/服务器模式(C/S)
    		 2.简单快速:客户端请求服务时,只需要发送请求方法和路径,请求方法有GET/POST/HEAD,每种防范规定了客户与服务器练习的类型不同,由于HTTP协议简单,使得http服务器的程序规模小,通信速度快
        	 3.灵活:http允许传输任意类型的数据对象
             4.无连接:含义是显示每次链接只能处理一个请求,服务器处理完客户端的请求,并接受到客户的应答后,即断开链接,节省传输时间
             5.无状态:http协议就是无状态协议,无状态是指协议对于事物处理没有记忆功能,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快
     
    HTTP工作流程:
    	第一步:建立TCP/IP连接,客户端与服务器通过Socket三次握手进行连接
    
        第二步:客户端向服务端发起HTTP请求(例如:POST/login.html http/1.1)
    
        第三步:客户端发送请求头信息,请求内容,最后会发送一空白行,标示客户端请求完毕
    
        第四步:服务器做出应答,表示对于客户端请求的应答,例如:HTTP/1.1 200 OK
    
        第五步:服务器向客户端发送应答头信息
    
        第六步:服务器向客户端发送请求头信息后,也会发送一空白行,标示应答头信息发送完毕,接着就以Content-type要求的数据格式发送数据给客户端
    
        第七步:服务端关闭TCP连接,如果服务器或者客户端增Connection:keep-alive就表示客户端与服务器端继续保存连接,在下次请求时可以继续使用这次的连接
            
    HTTPS的特点:HTTPS是HTTP协议的修改,它加密数据并确保其机密性。其配置可保护用户在与网站交互时免于窃取个人信息和计费数据。
    优点:提供优质的保密的信息,保证了用户户据的安全性,同时一定成度上保护了服务端,使用恶意攻击和伪装数据的成本大大提高
    缺点:1.https的技术门槛高
    	2. 大多数网站并不关心数据的安全性和保密性
        3. https加重了服务器的复古但
        4.http网站任然大鬼哦没的使用
        
    HTTPS的工作流程
    第一步:客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
    
    第二步:Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
    
    第三步:客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
    
    第四步:客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
    
    第五步:Web服务器利用自己的私钥解密出会话密钥。
    
    第六步:Web服务器利用会话密钥加密与客户端之间的通信。
    
    

    一下为http经过的几层模型

    1561036953556

    11.docker 创建镜像

    
    

    12.队列,链表

    栈##
    栈是一种动态集合,它是一种LIFO(last in first out后进先出)结构
    栈的实现:
    (1)数组
    (2)链表
    栈要记录的数据:
    (1)栈顶位置top
    注意这个top有两种理解方式,一种是表示栈的最后一个数据的位置,另一种是表示栈的最后一个数据的下一个位置,这两种理解对栈的操作代码有一定的影响
    (2)栈最大大小size
    栈的操作:
    (1)STACK_EMPTY():判断栈是否为空
    (2)PUSH(X):向栈中添加一个值,注意栈是否为满的
    (3)POP():从栈中弹出一个值,注意栈是否为空
    
    栈的简要实现:github栈
    栈的应用:
    (1)括号匹配问题
    队列##
    与栈不同,它是一种FIFO(first in first out先进先出)结构
    队列的实现:
    (1)数组
    (2)链表
    队列要记录的数据:
    (1)队首位置head:第一个元素位置
    (2)队尾位置tail:下一个元素要插入的位置(最后一个元素的下一个位置)
    (3)队列最大大小size
    队列的操作:
    (1)ENQUEUE(x):入队
    (2)DEQUEUE():出队
    (3)EMPTY():队列为空,head=tail
    (4)FULL():队列为满,head=(tail+1)%size
    
    队列的简要实现:github队列
    队列的应用:
    (1)
    链表##
    与数组中元素地址连续不同,链表中两个元素地址不一定连续,而是由专门的一个指针指明该元素的后一个(前一个)元素的地址。
    链表种类:
    (1)单向链表:只有指向后一个元素的指针
    (2)双向链表:有指向后一个和前一个元素的指针
    (3)循环链表:链表内存在一个环
    链表节点(Node)记录的数据:
    (1)要存储的数据data
    (2)下一个节点地址Node* next
    (3)若是双向链表还要存储前一个节点地址Node prev
    链表(LinkedList)记录的数据:
    (1)链表的头指针Node head
    (2)可能还记录链表的尾指针 Node* tail
    链表的操作:
    (1)SEARCH(x):链表的搜索
    (2)INSERT(i,x):链表的插入,在第i个位置插入x
    (3)DELETE(x):链表的删除
    哨兵(sentinel):
    为了减少边界条件的判断(是否为空链表等等),引入哨兵,使得链表永远不为“空”。
    指针和对象的实现:
    有些语言比如Java没有指针(C中就存在指针),这时我们需要考虑指针的替代实现方式。
    (1)用二维数组表示指针
    我们可以设置一个n*3的数组记录n个节点,那个3就表示存储的数据、前一个元素的坐标(index)和后一个元素的坐标。
    (2)用一维数组表示指针
    
    树##
    树的种类:
    (1)二叉树
    二叉树要存储4个数据,分别是节点携带的信息和其父节点、左右子节点的指针。
    (2)分支无限制的有根树:
    上面二叉树每个节点最多有两个子节点,而分支无限制的有根数则没有这个限制,可能有3个、5个甚至更多子节点。所以存储这种数据结构的问题在于我们事先并不知道应该设置多少个child指针,若设置的少了不能满足要求,设置的过多又会浪费空间。所以这里提出一种新的描述这种数据结构的方法——左孩子右兄弟表示法,这种方法每个节点设置3个指针:父指针、从左数第一个孩子的指针、其右侧相邻的兄弟指针,如下图所示
    
    堆##
    堆实际上是以数组形式存储的二叉树
    堆需要存储的数据:
    (1)数组的大小max-size
    (2)堆元素个数size,这里size要小于max-size
    堆中元素通过坐标来确定父节点、左右子节点,具体来说:
    一个节点i的父节点:[i/2]
    一个节点i的左子节点:[i2]
    一个节点i的右子节点:[i2+1]
    堆的分类:
    (1)最大堆
    满足所有节点都比其父节点值小(小于等于)的堆
    A[i/2]>=A[i]
    (2)最小堆
    满足所有节点都比其父节点值大(大于等于)的堆
    A[i/2]<=A[i]
    堆的操作:
    (1)维护堆的性质(HEAPIFY)
    这里指维护最大堆或最小堆的性质。假设一个数组中下标为i的节点的子节点满足最大(小)堆性质,但自身不一定满足这个性质,这时就需要HEAPIFY,具体来说是要比较这个节点和其两个子节点的大小,将其中的大(小)的和该节点位置交换,这样这个节点及其两个子节点就满足最大(小)堆的性质了,但是可能交换后子节点不满足堆的性质,所以这里要递归调用HEAPIFY,直到达到最下层节点,这样就维护了堆的性质。HEAPIFY耗时O(lgn)
    (2)建堆(BUILD-HEAPIFY)
    从中间那个元素开始到第一个元素,逐一调用HEAPIFY函数,即可完成建堆。
    逐一从中间那个元素开始递减而不是从第一个元素递增,这时为了保证每次调用HEAPIFY都能保证该节点的子节点都满足最大(小)堆的性质,否则无法调用HEAPIFY。中间那个元素是第一个可能不满足最大(小)堆性质的节点,所以从这里开始维护(HEAPIFY)。一个建堆的例子如下所示:[5,3,17,10,84,19,6,22,9]
    
    
    建堆
    
    建堆的期望时间为O(n)
    
    堆的应用:
    (1)堆排序(详见排序算法)
    (2)优先队列
    
    
    

    1561335196938

    ## python中实现双链表,栈,队列
    1.双链表
    
    class Node(object):
        def __init__(self, value=None):
            self._prev = None
            self.data = value
            self._next = None
            
        def __str__(self):
            return "Node(%s)" %s self.data
        
    class DoubleLinkedlist(object):
    	def __init__(self):
    		self._head = None()
            
        def insert(self, value):
            element = Node(value)
            element._next = self._head
            self._head._prev = element
            self._head = element
            
    
        def search(self, value):
            if not self._head._next:
                raise ValueError("the linked list is empty")
            temp = self._head
            while temp.data != value:
                temp = temp._next
            return temp
    
        def delete(self, value):
            element = self.search(value)
            if not element:
                raise ValueError('delete error: the value not found')
            element._prev._next = element._next
            element._next._prev = element._prev
            return element.data
    
        def __str__(self):
            values = []
            temp = self._head
            while temp and temp.data:
                values.append(temp.data)
                temp = temp._next
            return "DoubleLinkedList(%s)"%values
    
        
    2.栈
    class Stack(object):
        def __init__(self):
            self._top = 0
            self._stack = []
    
        def put(self, data):
            self._stack.insert(self._top, data)
            self._top += 1
    
        def pop(self):
            if self.isEmpty():
                raise ValueError('stack 为空')
            self._top -= 1
            data = self._stack[self._top]
    
            return data
    
        def isEmpty(self):
            if self._top == 0:
                return True
            else:
                return False
    
        def __str__(self):
            return "Stack(%s)"%self._stack
    
    3.队列
    
    class Queue(object):
        def __init__(self, max_size=float('inf')):
            self._max_size = max_size
            self._top = 0
            self._tail = 0
            self._queue = []
    
        def put(self, value):
            if self.isFull():
                raise ValueError("the queue is full")
            self._queue.insert(self._tail, value)
            self._tail += 1
    
        def pop(self):
            if self.isEmpty():
                raise ValueError("the queue is empty")
            data = self._queue.pop(self._top)
            self._top += 1
            return data
    
        def isEmpty(self):
            if self._top == self._tail:
                return True
            else:
                return False
    
        def isFull(self):
            if self._tail == self._max_size:
                return True
            else:
                return False
    
        def __str__(self):
            return "Queue(%s)"%self._queue
    
    
    

    13. 什么是Ajax?

    Ajax = 异步 JavaScript 和XML。
    Ajax是一种用于创建快速动态网页的技术。
    通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
    传统的网页(不使用 Ajax)如果需要更新内容,必需重载整个网页面。
    
    发送请求的四个步骤:
    (1)初始化XMLHTTPRequest对象。
    (2)为XMLHTTPRequest对象指定一个回调函数,用于对返回结果进行处理。
    (3)创建一个与服务器的连接。
    (4)向服务器发送请求。
    
    
    

    14.什么是虚拟机?

    通过软件模拟具有湾镇反硬件系统功能的,运行在一个完全隔离环境中的完整的计算机系统
    

    权重

    1561436035877

    mongdo 使用内存上限

    python基础

    一.基础语法

    1.2 a=1,b=2,不用中间变量交换a 和b 的值?(2018-3-29-lxy)
    方法一:
    1. a = a+b
    2. b = a-b
    3. a = a-b
    方法二:
    1. a = a^b
    2. b =b^a
    3. a = a^b
    方法三:
    1. a,b = b,a
    
    1.3 print 调用Python 中底层的什么方法?(2018-3-30-lxy)
    print 方法默认调用sys.stdout.write 方法,即往控制台打印字符串。
    
    1.4 下面这段代码的输出结果将是什么?请解释?(2018-3-30-lxy)
    1. class Parent(object):
    2. 		x = 1
    3. class Child1(Parent):
    4. 		pass
    5. class Child2(Parent):
    6. 		pass
    7. print Parent.x, Child1.x, Child2.x
    8. Child1.x = 2
    9. print parent.x, Child1.x, Child2.x
    10. parent.x = 3
    11. print Parent.x, Child1.x, Child2.x
    
    
    结果为:
    1 1 1 #继承自父类的类属性x,所以都一样,指向同一块内存地址。
    1 2 1 #更改Child1,Child1 的x 指向了新的内存地址。
    3 2 3 #更改Parent,Parent 的x 指向了新的内存地址。
    
    1.5 简述你对input()函数的理解?
    在Python3 中,input()获取用户输入,不论用户输入的是什么,获取到的都是字符串类型的。
    在Python2 中有raw_input()和input(), raw_input()和Python3 中的input()作用是一样的,
    input()输入的是什么数据类型的,获取到的就是什么数据类型的。
    
    2.1 阅读下面的代码,写出A0,A1 至An 的最终值。(2018-3-30-lxy)
    1. A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
    2. A1 = range(10)
    3. A2 = [i for i in A1 if i in A0]
    4. A3 = [A0[s] for s in A0]
    5. A4 = [i for i in A1 if i in A3]
    6. A5 = {i:i*i for i in A1}
    7. A6 = [[i,i*i] for i in A1]
    
    ............
    
    结果是:
    1. A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4}
    2. A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    3. A2 = []
    4. A3 = [1, 3, 2, 5, 4]
    1. A4 = [1, 2, 3, 4, 5]
    2. A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
    3. A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36],[7, 49],[8, 64], [9,81]]
    
    
    2.2 range 和xrange 的区别?(2018-3-30-lxy)

    目前再python3版本种xrange已经被取消

    两者用法相同,不同的是range 返回的结果是一个列表,而xrange 的结果是一个生成器,前者是直接开辟一块内存空间来保存列表,后者是边循环边使用,只有使用时才会开辟内存空间,所以当列表很长时,使用xrange 性能要比range 好。

    1. l = []
    2. for i in xrange(10):
    3. l.append({‘num’:i})
    4. print l
    ############
    
    1. l = []
    2. a = {‘num’:0}
    3. for i in xrange(10):
    4. a[‘num’] = i
    5. l.append(a)
    6. print l
    
    以上两段代码的运行结果是否相同,如果不相同,原因是什么?
    上方代码的结果:
    1. [{‘num’:0},{‘num’:1},{‘num’:2},{‘num’:3},{‘num’:4},{‘num’:5},{‘num’:6},{‘num’:7},{‘num’:8},
    {‘num’:9}]
    下方代码结果:
    1. [{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},{‘num’:9},
    {‘num’:9}]
    
    原因是:字典是可变对象,在下方的l.append(a)的操作中是把字典a 的引用传到列表l 中,当后
    续操作修改a[‘num’]的值的时候,l 中的值也会跟着改变,相当于浅拷贝。
    
    3.1 4G 内存怎么读取一个5G 的数据?(2018-3-30-lxy)
    方法一:
    可以通过生成器,分多次读取,每次读取数量相对少的数据(比如500MB)进行处理,处理结束后
    在读取后面的500MB 的数据。
    方法二:
    可以通过linux 命令split 切割成小文件,然后再对数据进行处理,此方法效率比较高。可以按照行
    数切割,可以按照文件大小切割。
    
    3.2 现在考虑有一个jsonline 格式的文件file.txt 大小约为10K,之前处理文件的代码如下所示:(2018-3-30-lxy)
    1. def get_lines():
    2. 		l = []
    3. 		with open(‘file.txt’,‘rb’) as f:
    4. 			for eachline in f:
    5. 				l.append(eachline)
    6. 		return l
    7. if __name__ == ‘__main__’:
    8. 		for e in get_lines():
    9. 			process(e) #处理每一行数据
    
    现在要处理一个大小为10G 的文件,但是内存只有4G,如果在只修改get_lines 函数而其他代码保持不变的情况下,应该如何实现?需要考虑的问题都有哪些?
    1. def get_lines():
    2. 		l = []
    3.		with open(‘file.txt’,’rb’) as f:
    4. 			data = f.readlines(60000)
    5. 		l.append(data)
    6. 		yield l
    
    要考虑到的问题有:
    内存只有4G 无法一次性读入10G 的文件,需要分批读入。分批读入数据要记录每次读入数据的位置。分批每次读入数据的大小,太小就会在读取操作上花费过多时间。
    
    3.3 read、readline 和readlines 的区别? (2018-4-16-lxy)

    read:读取整个文件。
    readline:读取下一行,使用生成器方法。
    readlines:读取整个文件到一个迭代器以供我们遍历。

    4.2 介绍一下except 的作用和用法?(2018-4-16-lxy)

    except: #捕获所有异常
    except: <异常名>: #捕获指定异常
    except:<异常名1, 异常名2> : 捕获异常1 或者异常2
    except:<异常名>,<数据>:捕获指定异常及其附加的数据
    except:<异常名1,异常名2>:<数据>:捕获异常名1 或者异常名2,及附加的数据

    5.1 常用的Python 标准库都有哪些?(2018-3-30-lxy)

    os 操作系统,time 时间,random 随机,pymysql 连接数据库,threading 线程,multiprocessing进程,queue 队列。
    第三方库:django 和flask 也是第三方库,requests,virtualenv, selenium,scrapy,xadmin,celery,re,hashlib,md5。
    常用的科学计算库(如Numpy,Scipy,Pandas)。

    5.2 赋值、浅拷贝和深拷贝的区别?(2018-3-30-lxy)

    一、赋值
    在Python 中,对象的赋值就是简单的对象引用,这点和C++不同,如下所示:

    16.a = [1,2,"hello",['python', 'C++']]
    17.b = a
    

    在上述情况下,a 和b 是一样的,他们指向同一片内存,b 不过是a 的别名,是引用。我们可以使用b is a 去判断,返回True,表明他们地址相同,内容相同,也可以使用id()函数来查看两个列表的地址是否相同。
    赋值操作(包括对象作为参数、返回值)不会开辟新的内存空间,它只是复制了对象的引用。也就是说除了b 这个名字之外,没有其他的内存开销。修改了a,也就影响了b,同理,修改了b,也就影响了a。

    二、浅拷贝(shallow copy)

    浅拷贝会创建新对象,其内容非原对象本身的引用,而是原对象内第一层对象的引用。
    浅拷贝有三种形式:切片操作、工厂函数、copy 模块中的copy 函数。
    比如上述的列表a;
    	切片操作:b = a[:] 或者b = [x for x in a];
    	工厂函数:b = list(a);
    	copy 函数:b = copy.copy(a);
        
    1、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
    
    

    1561364929082

    三、深拷贝(deep copy)

    深拷贝只有一种形式,copy 模块中的deepcopy()函数。
    深拷贝和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。因此,它的时间和空间开销要高。
    2、b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
    
    
    

    1561364993788

    5.3__init__ 和__new__的区别?(2018-3-30-lxy)

    init 在对象创建后,对对象进行初始化。
    new 是在对象创建之前创建一个对象,并将该对象返回给init。

    5.4 Python 里面如何生成随机数?(2018-3-30-lxy)
    在Python 中用于生成随机数的模块是random,在使用前需要import. 如下例子可以酌情列
    举:
    random.random():生成一个0-1 之间的随机浮点数;
    random.uniform(a, b):生成[a,b]之间的浮点数;
    random.randint(a, b):生成[a,b]之间的整数;
    random.randrange(a, b, step):在指定的集合(a,b)中,以step为基数随机取一个数;
    random.choice(sequence):从特定序列中随机取一个元素,这里的序列可以是字符串,列表,元组等。
    
    5.5 输入某年某月某日,判断这一天是这一年的第几天?(可以用Python 标准
    库)(2018-3-30-lxy)
    1. import datetime
    2. def dayofyear():
    3. 		year = input("请输入年份:")
    4. 		month = input("请输入月份:")
    5. 		day = input("请输入天:")
    6. 		date1 = datetime.date(year=int(year),month=int(month),day=int(day))
    7. 		date2 = datetime.date(year=int(year),month=1,day=1)
    8. 		return (date1 - date2 + 1).days
    
    5.6 打乱一个排好序的list 对象alist?(2018-3-30-lxy)
    1. import random
    2. random.shuffle(alist)
    
    5.7 说明一下os.path 和sys.path 分别代表什么?(2018-3-30-lxy)

    os.path 主要是用于对系统路径文件的操作。
    sys.path 主要是对Python 解释器的系统环境参数的操作(动态的改变Python 解释器搜索路径)。

    5.8 Python 中的os 模块常见方法?(2018-4-16-lxy)

    os.remove()删除文件
    os.rename()重命名文件
    os.walk()生成目录树下的所有文件名
    os.chdir()改变目录

    os.mkdir/makedirs 创建目录/多层目录
    os.rmdir/removedirs 删除目录/多层目录
    os.listdir()列出指定目录的文件
    os.getcwd()取得当前工作目录
    os.chmod()改变目录权限
    os.path.basename()去掉目录路径,返回文件名
    os.path.dirname()去掉文件名,返回目录路径
    os.path.join()将分离的各部分组合成一个路径名
    os.path.split()返回(dirname(),basename())元组
    os.path.splitext()(返回filename,extension)元组os.path.getatimectimemtime 分别返回最近访问、创建、修改时间
    os.path.getsize()返回文件大小
    os.path.exists()是否存在
    os.path.isabs()是否为绝对路径
    os.path.isdir()是否为目录
    os.path.isfile()是否为文件

    5.9 Python 的sys 模块常用方法?(2018-4-16-lxy)
    sys.argv 命令行参数List,第一个元素是程序本身路径
    sys.modules.keys() 返回所有已经导入的模块列表
    sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback 当前处理的异常详细信息
    sys.exit(n) 退出程序,正常退出时exit(0)
    sys.hexversion 获取Python 解释程序的版本值,16 进制格式如:0x020403F0
    sys.version 获取Python 解释程序的版本信息
    sys.maxint 最大的Int 值
    sys.maxunicode 最大的Unicode 值
    sys.modules 返回系统导入的模块字段,key 是模块名,value 是模块
    sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH 环境变量的值
    sys.platform 返回操作系统平台名称
    sys.stdout 标准输出
    sys.stdin 标准输入
    sys.stderr 错误输出
    sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息
    sys.exec_prefix 返回平台独立的python 文件安装的位置
    sys.byteorder 本地字节规则的指示器,big-endian 平台的值是'big',little-endian 平台的值是'little'
    sys.copyright 记录python 版权相关的东西
    sys.api_version 解释器的C 的API 版本
    sys.version_info 元组则提供一个更简单的方法来使你的程序具备Python 版本要求功能
    
    5.10 unittest 是什么?(2018-4-16-lxy)

    在Python 中,unittest 是Python 中的单元测试框架。它拥有支持共享搭建、自动测试、在测试中暂停代码、将不同测试迭代成一组,等的功能。

    5.11 模块和包是什么?(2018-4-16-lxy)

    在Python 中,模块是搭建程序的一种方式。每一个Python 代码文件都是一个模块,并可以引用其他的模块,比如对象和属性。
    一个包含许多Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹。

    6.1 Python 是强语言类型还是弱语言类型?(2018-3-30-lxy)

    Python 是强类型的动态脚本语言。
    强类型:不允许不同类型相加。
    动态:不使用显示数据类型声明,且确定一个变量的类型是在第一次给它赋值的时候。
    脚本语言:一般也是解释型语言,运行代码只需要一个解释器,不需要编译。

    6.2 谈一下什么是解释性语言,什么是编译性语言? (2018-3-30-lxy)

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

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

    6.3 Python 中有日志吗?怎么使用? (2018-3-30-lxy)
    有日志。
    Python 自带logging 模块,调用logging.basicConfig()方法,配置需要的日志等级和相应的参数,
    Python 解释器会按照配置的参数生成相应的日志。
    
    6.4 Python 是如何进行类型转换的?(2018-3-30-lxy)
    内建函数封装了各种转换函数,可以使用目标类型关键字强制类型转换,进制之间的转换可以用
    int(‘str’,base=’n’)将特定进制的字符串转换为十进制,再用相应的进制转换函数将十进制转换
    为目标进制。
    可以使用内置函数直接转换的有:
    list---->tuple tuple(list)
    tuple---->list list(tuple)
    
    6.5 Python2 与Python3 的区别?(2018-3-30-lxy)
    1. 核心类差异
    1. Python3 对Unicode 字符的原生支持。
      Python2 中使用ASCII 码作为默认编码方式导致string 有两种类型str 和unicode,Python3 只
      支持unicode 的string。Python2 和Python3 字节和字符对应关系为:

    1561376946130

    6.10 什么是Python 的命名空间?(2018-4-16-lxy)

    在Python 中,所有的名字都存在于一个空间中,它们在该空间中存在和被操作——这就是命名空间。它就好像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象。

    6.11 你所遵循的代码规范是什么?请举例说明其要求?(2018-4-20-lxy)

    PEP8 规范。

    1. 变量
      常量:大写加下划线USER_CONSTANT。
      私有变量: 小写和一个前导下划线_private_value。
      Python 中不存在私有变量一说,若是遇到需要保护的变量,使用小写和一个前导下划线。但这只是
      程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。但实际上,外部类还
      是可以访问到这个变量。
      内置变量: 小写,两个前导下划线和两个后置下划线__class__

    两个前导下划线会导致变量在解释期间被更名。这是为了避免内置变量和其他变量产生冲突。用户定义的变量要严格避免这种风格。以免导致混乱。

    1. 函数和方法
      总体而言应该使用,小写和下划线。但有些比较老的库使用的是混合大小写,即首单词小写,之后
      每个单词第一个字母大写,其余小写。但现在,小写和下划线已成为规范。
      私有方法:小写和一个前导下划线
      这里和私有变量一样,并不是真正的私有访问权限。同时也应该注意一般函数不要使用两个前导下
      划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。
      特殊方法:小写和两个前导下划线,两个后置下划线
      这种风格只应用于特殊函数,比如操作符重载等。
      函数参数: 小写和下划线,缺省值等号两边无空格

    2. 类总是使用驼峰格式命名,即所有单词首字母大写其余字母小写。类名应该简明,精确,并足以从
      中理解类所完成的工作。常见的一个方法是使用表示其类型或者特性的后缀,例如:
      SQLEngine,MimeTypes 对于基类而言,可以使用一个Base 或者Abstract 前缀BaseCookie,
      AbstractGroup
    3. 模块和包
      除特殊模块__init__ 之外,模块名称都使用不带下划线的小写字母。
      若是它们实现一个协议,那么通常使用lib 为后缀,例如:
      import smtplib
      import os
      import sys
    4. 关于参数
      5.1 不要用断言来实现静态类型检测。断言可以用于检查参数,但不应仅仅是进行静态类型检测。
      Python 是动态类型语言,静态类型检测违背了其设计思想。断言应该用于避免函数不被毫无意义的调用。
      5.2 不要滥用args 和**kwargs。args 和**kwargs 参数可能会破坏函数的健壮性。它们使签名变得模糊,而且代码常常开始在不应该的地方构建小的参数解析器。
    5. 其他
      6.1 使用has 或is 前缀命名布尔元素
      is_connect = True
      has_member = False
      6.2 用复数形式命名序列
      members = ['user_1', 'user_2']
      6.3 用显式名称命名字典
      person_address = {'user_1':'10 road WD', 'user_2' : '20 street huafu'}
      6.4 避免通用名称
      诸如list, dict, sequence 或者element 这样的名称应该避免。
      6.5 避免现有名称
      诸如os, sys 这种系统已经存在的名称应该避免。
    6. 一些数字
      一行列数: PEP 8 规定为79 列。根据自己的情况,比如不要超过满屏时编辑器的显示列数。
      一个函数: 不要超过30 行代码, 即可显示在一个屏幕类,可以不使用垂直游标即可看到整个函数。
      一个类: 不要超过200 行代码,不要有超过10 个方法。一个模块不要超过500 行。
    7. 验证脚本
      可以安装一个pep8 脚本用于验证你的代码风格是否符合PEP8。

    二、数据结构

    1.字典
    1.6 现有字典d={‘a’:24,’g’:52,’l’:12,’k’:33}请按字典中的value
    值进行排序? (2018-4-23-lxy)
    sorted(d.items(),key = lambda x:x[1])
    
    
    2.字符串
    2.1 如何理解Python 中字符串中的字符?(2018-3-30-lxy)

    有三种不同的含义:
    1、转义字符2、路径名中用来连接路径名3、编写太长代码手动软换行。

    2.4 请按alist 中元素的age 由大到小排序(2018-3-30-lxy)

    alist [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]

    def sort_by_age(list1):

    ​ return sorted(alist, key=lambda x:x["age"],reverse=True)

    3.列表

    列表.extend(Iterable):将可迭代对象中的元素追加到列表。

    1.# 有两个列表a 和b a.extend(b) 会将b 中的元素追加到列表a 中
    2.In [10]: a = [11, 22, 33]
    3.In [11]: b = [44, 55, 66]
    4.In [12]: a.extend(b)
    5.In [13]: a
    6.Out[13]: [11, 22, 33, 44, 55, 66]# 有列表c 和字符串d c.extend(d) 会将字符串d 中的每个字符拆开作为元素插入到列表
    c
    7.In [14]: c = ['j', 'a', 'v', 'a']
    8.In [15]: d = "python"
    9.In [16]: c.extend(d)
    10.In [17]: c
    11.Out[17]: ['j', 'a', 'v', 'a', 'p', 'y', 't', 'h', 'o','n']
    

    3)删除
    del 列表名[index]:删除指定索引的数据。

    1.In [25]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除索引是1 的数据
    2.In [26]: del name_list[1]
    3.In [27]: name_list
    4.Out[27]: ['zhangsan', 'wangwu', 'zhaoliu']
    

    列表名.remove(数据):删除第一个出现的指定数据。

    5.In [30]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu", "lisi"]# 删除第一次出现的lisi 的数据
    6.In [31]: name_list.remove("lisi")
    7.In [32]: name_list
    8.Out[32]: ['zhangsan', 'wangwu', 'zhaoliu', 'lisi']
    
    列表名.pop():删除末尾的数据,返回值: 返回被删除的元素。
    9.In [33]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除最后一个元素zhaoliu 并将元素zhaoliu 返回
    10.In [34]: name_list.pop()
    11.Out[34]: 'zhaoliu'
    12.In [35]: name_list
    13.Out[35]: ['zhangsan', 'lisi', 'wangwu']
    列表名.pop(index):删除指定索引的数据,返回被删除的元素。
    14.In [36]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]# 删除索引为1 的数据lisi
    15.In [37]: name_list.pop(1)
    16.Out[37]: 'lisi'
    17.In [38]: name_list
    18.Out[38]: ['zhangsan', 'wangwu', 'zhaoliu']
    列表名.clear():清空整个列表的元素。
    19.In [40]: name_list = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
    20.In [41]: name_list.clear()
    21.In [42]: name_list
    22.Out[42]: []
    
    4)排序
    列表名.sort():升序排序从小到大。
    23.In [43]: a = [33, 44, 22, 66, 11]
    24.In [44]: a.sort()
    25.In [45]: a
    26.Out[45]: [11, 22, 33, 44, 66]
    列表名.sort(reverse=True):降序排序从大到小。
    27.In [46]: a = [33, 44, 22, 66, 11]
    28.In [47]: a.sort(reverse=True)
    29.In [48]: a
    30.Out[48]: [66, 44, 33, 22, 11]
    列表名.reverse():列表逆序、反转。
    31.In [50]: a = [11, 22, 33, 44, 55]
    32.In [51]: a.reverse()
    33.In [52]: a
    34.Out[52]: [55, 44, 33, 22, 11]
    5)统计相关
    len(列表名):得到列表的长度。
    35.In [53]: a = [11, 22, 33, 44, 55]
    36.In [54]: len(a)
    37.Out[54]: 5
        列表名.count(数据):数据在列表中出现的次数。
    38.In [56]: a = [11, 22, 11, 33, 11]
    39.In [57]: a.count(11)
    40.Out[57]: 3
    列表名.index(数据):数据在列表中首次出现时的索引,没有查到会报错。
    41.In [59]: a = [11, 22, 33, 44, 22]
    42.In [60]: a.index(22)
    43.Out[60]: 1
    if 数据in 列表: 判断列表中是否包含某元素。
    44.a = [11, 22, 33, 44 ,55]
    45.if 33 in a:
    46. print("找到了....")
    
    注意事项
    3.1 下面代码的输出结果将是什么?(2018-3-30-lxy)
    1. list = ['a', 'b', 'c', 'd', 'e']
    2. print list[10:]
    下面的代码将输出[],不会产生IndexError 错误。就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。
    例如,尝试获取list[10]和之后的成员,会导致IndexError。
    然而,尝试获取列表的切片,开始的index 超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致bug 很难被追踪到。
    
    
    3.2 写一个列表生成式,产生一个公差为11 的等差数列(2018-3-30-lxy)
    1. print([x*11 for x in range(10)])
    
    3.3 给定两个列表,怎么找出他们相同的元素和不同的元素? (2018-3-30-lxy)
    1. list1 = [1,2,3]
    2. list2 = [3,4,5]
    3. set1 = set(list1)
    4. set2 = set(list2)
    5. print(set1&set2)
    6. print(set1^set2)
    
    3.4 请写出一段Python 代码实现删除一个list 里面的重复元素?(2018-3-30-lxy)
    比较容易记忆的是用内置的set:
    1. l1 = ['b','c','d','b','c','a','a']
    2. l2 = list(set(l1))
    3. print l2
    如果想要保持他们原来的排序:
    用list 类的sort 方法:
    1. l1 = ['b','c','d','b','c','a','a']
    2. l2 = list(set(l1))
    3. l2.sort(key=l1.index)
    4. print l2
    也可以这样写:
    1. l1 = ['b','c','d','b','c','a','a']
    2. l2 = sorted(set(l1),key=l1.index)
    3. print l2
    也可以用遍历:
    1. l1 = ['b', 'c', 'd', 'b', 'c', 'a', 'a']
    2. l2 = []
    3. for i in l1:
    4. if not i in l2:
    5. l2.append(i)
    6. print l2
    
    3.8.将以下3 个函数按照执行效率高低排序(2018-4-16-lxy)
    1. def f1(lIn):
    2. l1 = sorted(lIn)
    3. l2 = [i for i in l1 if i<0.5]
    4. return [i*i for i in l2]
    5.
    6.
    7. def f2(lIn):
    8. l1 = [i for i in l1 if i<0.5]
    9. l2 = sorted(l1)
    10. return [i*i for i in l2]
    11.
    12.
    13. def f3(lIn):
    14. l1 = [i*i for i in lIn]
    15. l2 = sorted(l1)
    16. return [i for i in l1 if i<(0.5*0.5)]
    按执行效率从高到低排列:f2、f1 和f3。要证明这个答案是正确的,你应该知道如何分析自己代码的性能。Python中有一个很好的程序分析包,可以满足这个需求。
    
    1. import random
    2. import cProfile
    3. lIn = [random.random() for i in range(100000)]
    4. cProfile.run('f1(lIn)')
    5. cProfile.run('f2(lIn)')
    6. cProfile.run('f3(lIn)')
    
    1. 集合
      set:set 集合,在Python 中的书写方式的{},集合与之前列表、元组类似,可以存储多个数据,但是这些数据是不重复的。集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric_difference(对称差集)等数学运算.
      快速去除列表中的重复元素
      1.In [4]: a = [11,22,33,33,44,22,55]
      2.
      3.In [5]: set(a)
      4.Out[5]: {11, 22, 33, 44, 55}
      交集:共有的部分
      1.In [7]: a = {11,22,33,44,55}
      2.In [8]: b = {22,44,55,66,77}
      3.In [9]: a&b
      4.Out[9]: {22, 44, 55}
          
      并集:总共的部分
      1.In [11]: a = {11,22,33,44,55}
      2.In [12]: b = {22,44,55,66,77}
      3.In [13]: a | b
      4.Out[13]: {11, 22, 33, 44, 55, 66, 77}
      差集:另一个集合中没有的部分
      1.In [15]: a = {11,22,33,44,55}
      2.In [16]: b = {22,44,55,66,77}
      3.In [17]: b - a
      4.Out[17]: {66, 77}
      对称差集(在a 或b 中,但不会同时出现在二者中)
      1.In [19]: a = {11,22,33,44,55}
      2.In [20]: b = {22,44,55,66,77}
      3.In [21]: a ^ b
      4.Out[21]: {11, 33, 66, 77}
    

    python综述

    Python语言和C++,java等其他编程语言相比,他是一种解释型脚本语言,代码在执行时,会一行一行的解释成CPU能理解的机器码,同时它又是跨平台的,可以允许windows,linux,mac等系统上,同样的程序逻辑,可能C语言需要1000行代码,java有100行,但是python实现可能只需要20行,这极大程度上提升了企业的项目开发效率,
    记得之前就有一篇权威报道,到2014年为止,麻省、哈弗等顶尖高校都已经使用python作为教学语言,现在国内的高校,也开始设置python的专业课程,现在对于企业项目后台开发而言,不是说一定要用python开发,但现在语言本身的性能差距在实际开发的过程中,相对于业务功能合理设计、代码编写架构质量等,语言底层造成的性能损失越来越可以忽略不计,针对于一些特定的功能模块,python当前也出现了pypy,JIT等大幅度提高python程序运行效率的相关技术,能够满足大多数功能的需求业务场景
    
    具体选用python后,新项目推荐使用python3,08年python3版本发布后,十几年来python3生态圈第三方库已经非常具备完备和弃权,而官方已经宣布python2在2020年将不在维护,另外python3本身性能也和相较于python2有一定的提升
    

    Linux基础和git

    Linux

    7.1 Linux 的基本命令(怎么区分一个文件还是文件夹)(2018-3-30-lxy)

    ls -F 在显示名称的时候会在文件夹后添加“/”,在文件后面加“*”。

    7.2 日志以什么格式,存放在哪里?(2018-3-30-lxy)

    日志以文本可以存储在“/var/log/”目录下后缀名为.log。

    7.3 Linux 查看某个服务的端口? (2018-3-30-lxy)

    netstat命令参数:

      -t : 指明显示TCP端口

      -u : 指明显示UDP端口

      -l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序)

      -p : 显示进程标识符和程序名称,每一个套接字/端口都属于一个程序。

      -n : 不进行DNS轮询,显示IP(可以加速操作)

    即可显示当前服务器上所有端口及进程服务,于grep结合可查看某个具体端口及服务情况··

    netstat -ntlp //查看当前所有tcp端口·

    netstat -ntulp |grep 80 //查看所有80端口使用情况·

    netstat -an | grep 3306 //查看所有3306端口使用情况·

    查看一台服务器上面哪些服务及端口

    netstat -lanp

    查看一个服务有几个端口。比如要查看mysqld

    ps -ef |grep mysqld

    查看某一端口的连接数量,比如3306端口

    netstat -pnt |grep :3306 |wc

    查看某一端口的连接客户端IP 比如3306端口

    netstat -anp |grep 3306

    netstat -an 查看网络端口 lsof -i :port,使用lsof -i :port就能看见所指定端口运行的程序,同时还有当前连接。 nmap 端口扫描netstat -nupl  (UDP类型的端口)netstat -ntpl  (TCP类型的端口)netstat -anp 显示系统端口使用情况
    
    
    7.4 ubuntu 系统如何设置开机自启动一个程序? (2018-3-30-lxy)

    直接修改/etc/rc0.d ~ /etc/rc6.d 和/etc/rcS.d 文件夹的内容,添加需启动的程序,S 开头的表示启动,K 开头的表示不启动。

    7.6 Linux 重定向命令有哪些?有什么区别?(2018-4-16-lxy)

    1、重定向>
    Linux 允许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中。如:ls >test.txt ( test.txt 如果不存在,则创建,存在则覆盖其内容)。
    2、重定向>>

    这个是将输出内容追加到目标文件中。如果文件不存在,就创建文件;如果文件存在,则将新的内容追加到那个文件的末尾,该文件中的原有内容不受影响。

    7.7 软连接和硬链接的区别?(2018-4-16-lxy)

    软连接类似Windows 的快捷方式,当删除源文件时,那么软链接也失效了。硬链接可以理解为源文件的一个别名,多个别名所代表的是同一个文件。当rm 一个文件的时候,那么此文件的硬链接数减1,当硬链接数为0 的时候,文件被删除。

    7.8 10 个常用的Linux 命令?(2018-4-20-lxy)

    pwd 显示工作路径
    ls 查看目录中的文件

    cd /home 进入'/ home' 目录'
    cd .. 返回上一级目录
    cd ../.. 返回上两级目录
    mkdir dir1 创建一个叫做'dir1' 的目录'
    rm -f file1 删除一个叫做'file1' 的文件',-f 参数,忽略不存在的文件,从不给出提示。
    rmdir dir1 删除一个叫做'dir1' 的目录'
    groupadd group_name 创建一个新用户组
    groupdel group_name 删除一个用户组
    tar -cvf archive.tar file1 创建一个非压缩的tarball
    tar -cvf archive.tar file1 file2 dir1 创建一个包含了'file1', 'file2' 以及'dir1'的档案文件
    tar -tf archive.tar 显示一个包中的内容
    tar -xvf archive.tar 释放一个包
    tar -xvf archive.tar -C /tmp 将压缩包释放到/tmp 目录下
    tar -cvfj archive.tar.bz2 dir1 创建一个bzip2 格式的压缩包
    tar -xvfj archive.tar.bz2 解压一个bzip2 格式的压缩包
    tar -cvfz archive.tar.gz dir1 创建一个gzip 格式的压缩包
    tar -xvfz archive.tar.gz 解压一个gzip 格式的压缩包
    reboot 重新启动操作系统
    shutdown –r now 重新启动操作系统,shutdown 会给别的用户提示
    shutdown -h now 立刻关机,其中now 相当于时间为0 的状态
    shutdown -h 20:25 系统在今天的20:25 会关机
    shutdown -h +10 系统再过十分钟后自动关机
    init 0 关机 init 6 重启

    git

    7.10 git 合并文件有冲突,如何处理? (2018-3-30-lxy)

    1、git merge 冲突了,根据提示找到冲突的文件,解决冲突如果文件有冲突,那么会有类似的标记

    2、修改完之后,执行git add 冲突文件名
    3、git commit 注意:没有-m 选项进去类似于vim 的操作界面,把conflict 相关的行删除掉
    直接push 就可以了,因为刚刚已经执行过相关merge 操作了。

    7.11 git 创建分支,合并分支
    首先,创建分支dev,切换到dev分支
    $ git checkout -b dev
    Switched to a new branch 'dev'
    git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
    $ git branch dev
    $ git checkout dev
    Switched to branch 'dev'
    
    然后,用git branch命令查看当前分支:
    $ git branch
    * dev
      master
      
    git branch命令会列出所有分支,当前分支前面会标一个*号。
    
    然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:
    Creating a new branch is quick.
    然后提交:
    $ git add readme.txt 
    $ git commit -m "branch test"
    [dev b17d20e] branch test
     1 file changed, 1 insertion(+)
     
    现在,dev分支的工作完成,我们就可以切换回master分支:
    $ git checkout master
    Switched to branch 'master'
    切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:
    
    现在,我们把dev分支的工作成果合并到master分支上:
    $ git merge dev
    Updating d46f35e..b17d20e
    Fast-forward
     readme.txt | 1 +
     1 file changed, 1 insertion(+)
     
     git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
    
    注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
    
    当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。
     合并完成后,就可以放心地删除dev分支了:
     $ git branch -d dev
    Deleted branch dev (was b17d20e).
    删除后,查看branch,就只剩下master分支了:
    $ git branch
    * master
    
    
    创建与合并分支
    阅读: 9909301
    在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
    
    一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
    
    git-br-initial
    
    每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
    
    当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
    
    git-br-create
    
    你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
    
    不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
    
    git-br-dev-fd
    
    假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
    
    git-br-ff-merge
    
    所以Git合并分支也很快!就改改指针,工作区内容也不变!
    
    合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
    
    git-br-rm
    
    真是太神奇了,你看得出来有些提交是通过分支完成的吗?
    
    下面开始实战。
    
    首先,我们创建dev分支,然后切换到dev分支:
    
    $ git checkout -b dev
    Switched to a new branch 'dev'
    git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
    
    $ git branch dev
    $ git checkout dev
    Switched to branch 'dev'
    然后,用git branch命令查看当前分支:
    
    $ git branch
    * dev
      master
    git branch命令会列出所有分支,当前分支前面会标一个*号。
    
    然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:
    
    Creating a new branch is quick.
    然后提交:
    
    $ git add readme.txt 
    $ git commit -m "branch test"
    [dev b17d20e] branch test
     1 file changed, 1 insertion(+)
    现在,dev分支的工作完成,我们就可以切换回master分支:
    
    $ git checkout master
    Switched to branch 'master'
    切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:
    
    git-br-on-master
    
    现在,我们把dev分支的工作成果合并到master分支上:
    
    $ git merge dev
    Updating d46f35e..b17d20e
    Fast-forward
     readme.txt | 1 +
     1 file changed, 1 insertion(+)
    git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
    
    注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
    
    当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。
    
    合并完成后,就可以放心地删除dev分支了:
    
    $ git branch -d dev
    Deleted branch dev (was b17d20e).
    删除后,查看branch,就只剩下master分支了:
    
    $ git branch
    * master
    因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
    
    
    
    小结
    Git鼓励大量使用分支:
    
    查看分支:git branch
    
    创建分支:git branch <name>
    
    切换分支:git checkout <name>
    
    创建+切换分支:git checkout -b <name>
    
    合并某分支到当前分支:git merge <name>
    
    删除分支:git branch -d <name>
    
    
  • 相关阅读:
    Django使用Mysql已存在数据表的方法
    ajax加载验证码这样不断刷新的文件无法刷新问题
    flask ajax发送请求返回400
    flask启动找不到路由问题
    Python开发之路
    文件读写的简单应用
    sql 简单查询修改
    kafka 查询 SQL Query
    kafka条件查询excel拼接
    shelve模块
  • 原文地址:https://www.cnblogs.com/yang950718/p/11079419.html
Copyright © 2020-2023  润新知