Python 面试总结

https://gist.github.com/prim/3e7f814187c715541ef2

https://www.gitbook.com/book/l1nwatch/interview_exercise/details

豆瓣面试官 http://www.dongwm.com/archives/liao-liao-pythonmian-shi-zhe-jian-shi-er/

写代码:

int要考虑负数,0 

 

17、@property有什么作用?如何实现成员变量的只读属性?

  @property装饰器就是负责把一个方法变成属性调用,通常用在属性的get方法和set方法,通过设置@property可以实现实例成员变量的直接访问,又保留了参数的检查。另外通过设置get方法而不定义set方法可以实现成员变量的只读属性。

 

16、简述__new__和__init__的区别

  创建一个新实例时调用__new__,初始化一个实例时用__init__,这是它们最本质的区别。

  new方法会返回所构造的对象,init则不会.

  new函数必须以cls作为第一个参数,而init则以self作为其第一个参数.

 

15、装饰器有什么作用

  装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

易重用

 

 

14、匿名函数,匿名函数有什么局限性

  匿名函数,也就是lambda函数,通常用在函数体比较简单的函数上。匿名函数顾名思义就是函数没有名字,因此不用担心函数名冲突。不过Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数。

 

 13、Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性键值对存储数据库

 

12.1、从浏览器地址栏输入网址,到网页彻底打开,中间都发生了什么?

  三大部分:一块是客户端,一块是网络传输层,一块是服务端。

  客户端部分:URL由http协议+域名+文件路径+端口,从输入网址开始,这个网址在客户端就会有一个解析,浏览器如果有钩子做出反应。在host列      表中寻找ip。

  网络传输部分:1、询问本地域名服务器,域名查询请求会发到服务商的dns服务器,服务商的dns服务器会检查缓存,如果不存在你要访问的这个域名或者缓存状态已经过期,会访问根域名服务器,2、询问根域名服务器,会有二级根域名服务器,三级根域名服务器,根域名服务器也会先检查缓存,如果无法直接返回结果,会检查这个域名是哪个dns服务器负责解析的,然后将请求转发过去,获得这个域名所对应的ip,然后返回给本地服务商的dns,本地服务商的dns就更新缓存,然后把ip返回给客户端。

  服务器端:然后到了指定ip,服务器会在80端口有一个守护进程接受这个请求,细说的话这里还有三次握手的协议,那么下面就是webserver是怎么工作的,静态页面的处理比较简单,动态脚本还需要一个解释器系统工作,执行一段代码后将返回结果输出。这里可能又涉及有服务端缓存的,数据库,负载均衡和轮询等等。

  数据返回你的电脑时,都存在一个在子网被劫持被篡改的风险,ARP欺骗,ARP协议是什么,为什么你要访问的内容会被劫持会被篡改。

 

12,HTTP 通信过程

  七步

  1 建立 TCP 连接 三次握手

  2 浏览器 向服务器发送请求命令 请求行:

    例如:GET/sample/hello.jsp HTTP/1.1

  3 浏览器发送 请求头 信息 以空白行表示结束

  

  4 服务器应答 状态行:  HTTP/1.1 200 OK

  5 服务器 发送 响应头 信息  以空白行表示结束

  

  6 服务器向浏览器发送数据

  7 服务器关闭 TCP 连接

 

11, 用多线程的方式发起一个 http 请求

http://www.jianshu.com/p/1cca792b0b15

线程基类:

import threading
class base_thread(thread.Thread):
    def __init__(self, func):
        threading.Thread.__init__(self)
        self.func = func
        # print(type(self.func))
    def run(self):
        self.func

http请求:

# -*- coding: utf-8 -*-
#!/bin/env python
# Python2.7

import requests
import json
class ConfigHttp:
    def __init__(self, host, port, headers):
        self.host = host
        self.port = port
        self.headers = headers
    # 封装HTTP GET请求方法
    def get(self, url, params):
        # params = urllib.parse.urlencode(params)
        url = "http://" + self.host + ":" + self.port + url
        try:
            r = requests.get(url, params=params, headers = self.headers)
            r.encoding = 'UTF-8'
            return r.text
        except  Exception:
            print('no json data returned')
            return {}
    # 封装HTTP POST请求方法,支持上传图片
    def post(self, url, data, files=None):
        data = eval(data)
        url = 'http://' + self.host + ':' + str(self.port)+url
        r =requests.post(url, files=files, data=data)
        print(data)
        json_response = r.text
        return json_response

 

 

10, 打印一个给定路径下的所有文件路径

使用os.walk

os.walk(top, topdown=True, onerror=None, followlinks=False) 

可以得到一个三元tupple(dirpath, dirnames, filenames), 

第一个为起始路径,第二个为起始路径下的文件夹,第三个是起始路径下的文件。

dirpath 是一个string,代表目录的路径,

dirnames 是一个list,包含了dirpath下所有子目录的名字。

filenames 是一个list,包含了非目录文件的名字。

这些名字不包含路径信息,如果需要得到全路径,需要使用os.path.join(dirpath, name).

import os
pp = '/Users/yly/Desktop/wh8xfyYvLPtW'
print os.listdir(pp), '\n'

def Test1(rootDir):
    for root,dirs,files in os.walk(rootDir):
        for filespath in files:
       # 打印文件路径
print os.path.join(root,filespath) for dirpath in dirs:
       # 打印目录名称
print os.path.join(root,dirpath)

# 使用递归
def Test2(rootDir): for lists in os.listdir(rootDir): path = os.path.join(rootDir, lists) print path if os.path.isdir(path): Test2(path) print 'Test1, 先打印第一层,再第二层' Test1(pp) print 'Test2:' Test2(pp)
['.DS_Store', '11', '123'] 

Test1:
/Users/yly/Desktop/wh8xfyYvLPtW/.DS_Store
/Users/yly/Desktop/wh8xfyYvLPtW/11
/Users/yly/Desktop/wh8xfyYvLPtW/12
/Users/yly/Desktop/wh8xfyYvLPtW/12/.DS_Store
/Users/yly/Desktop/wh8xfyYvLPtW/12/21
Test2:
/Users/yly/Desktop/wh8xfyYvLPtW/.DS_Store
/Users/yly/Desktop/wh8xfyYvLPtW/12
/Users/yly/Desktop/wh8xfyYvLPtW/12/.DS_Store
/Users/yly/Desktop/wh8xfyYvLPtW/12/21
/Users/yly/Desktop/wh8xfyYvLPtW/3
[Finished in 0.0s]

9,yield

  带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代,有next()方法

  yield 就是 return 返回一个值,下一次返回这个值的下一个值

  send(msg) 与 next() 的区别:send可以传递参数给 yield表达式

def g():
    print '1'
    x = yield'hello'
    print '2', 'x =', x 
    y = 5 + (yield x)
    print '3', 'y = ', y

f = g() #首先生成一个迭代器f
print f.next(), '\n' print f.send(5), '\n' print f.send(2)
1  
hello #f.next()会使生成器函数执行到yield,生成一个值然后挂起。

2 x = 5 #f.send(msg)会在生成器函数内部返回值,执行到第二个yield,生成值后挂起
5 

Traceback (most recent call last):
  File "/Users/yly/Desktop/1 2.py", line 17, in <module>
    print f.send(2)
StopIteration  #后面没有 yield 了,抛出异常
3 y =  7

 

8,数据库索引,原理,怎么用

http://tech.meituan.com/mysql-index.html

例如 字典

原理:控制磁盘IO次数的数量级 => 使用 b+树

B+树特点:插入与修改有叫稳定的对数时间复杂度

阮一峰:http://www.ruanyifeng.com/blog/2014/07/database_implementation.html

How do you build a database?https://www.reddit.com/r/Database/comments/27u6dy/how_do_you_build_a_database/ciggal8/

二叉树:最多两个子树、左小于父父小于左、在n个节点中查找,一般需要log(n)次比较

B+树:一个节点可以多个值(指针)、数据满后再增加层、父节点a个值则有按a+1个子节点

数据库事务(transaction)是指批量进行一系列数据库操作,只要有一步不成功,整个操作都不成功。所以需要有一个"操作日志",以便失败时对操作进行回滚。

特点:IO次数取决于b+数的高度h、索引的最左匹配特性

慢查询优化:建立索引:最左前缀匹配、选择区分度高的列作为索引、索引不参与计算、尽量扩展索引

 

 

7,Python 多线程 多进程

一个线程就是执行一个子程序

协程: 本质:allowing multiple entry points for suspending and resuming execution at certain locations.  允许多个入口对程序进行挂起、继续执行等操作

 

最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

 线程:I\O阻塞后,进程被挂起,不用切换页表、刷新TLB,只刷新寄存器

6,class method self

 

5,生成器

 

4,协程 

廖雪峰:

import time 

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print ('[CONSUMER] Consuming %s...' & n)
        time.sleep(1)
        r = '200 OK'

def produce(c):
    c.next()
    n = 0
    while n <5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

if  __name__ == '__main__':
    c = consumer()
    produce(c)
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

 注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:

  1. 首先调用c.next()启动生成器;

  2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;

  3. consumer通过yield拿到消息,处理,又通过yield把结果传回;

  4. produce拿到consumer处理的结果,继续生产下一条消息;

  5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

最后套用Donald Knuth的一句话总结协程的特点:

“子程序就是协程的一种特例。”

进程、线程、协程、同步、异步、回调

新建进程时,我们需要分配新的进程描述符,并且分配新的地址空间(和父地址空间的映射保持一致,但是两者同时进入COW状态)。这些过程需要一定的开销。

线程并不产生新的地址空间和资源描述符表,而是复用父进程的。

协程是一种编程组件,可以在不陷入内核的情况进行同一进程中上下文切换 

协程与生成器区别:生成器是数据的生产者,协程是数据的消费者

GIL: Global Interpreter Lock 全局排它锁

"协程就是你可以暂停执行的函数"

维基:“协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序”。

 

3, utf8 unicode gbk

各种字符编码

 UTF-8就是unicode的实现方式.

Unicode只是字符集,而UTF-X才是编码.

UTF-8 is a character encoding capable of encoding all possible characters, or code points, in Unicode. The encoding is variable-length and uses 8-bit code units.

简单来说,unicode,gbku,是字符集,而utf-8,uft-16之i就是这个值的编码方式.如"汉"的unicode值与gbk就是不一样的,假设unicode为a040,gbk为b030,而uft-8码,就是把那个值表现的形式.utf-8码完全只针对unicode来组织的,如果GBK要转utf-8必须先转unicode码,再转utf-8就OK了.

 

2,参数传递

 *args and **kwargs

  *args代表位置参数,它会接收任意多个参数并把这些参数作为元组传递给函数。

  **kwargs代表的关键字参数,字典,允许你使用没有事先定义的参数名,另外,位置参数一定要放在关键字参数的前面。

 

1,RESTful架构:

  (1)每一个URI代表一种资源;

  (2)客户端和服务器之间,传递这种资源的某种表现层;

  (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

 

enumerate(nums)

def enumerate(collection): 

    'Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...'      
     i = 0 
     it = iter(collection) 
     while 1: 
     yield (i, it.next()) 
     i += 1

 

posted @ 2017-06-19 21:55  yhidr  阅读(361)  评论(0编辑  收藏  举报