zoukankan      html  css  js  c++  java
  • 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), '
    '
    
    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(), '
    ' print f.send(5), '
    ' 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.  允许多个入口对程序进行挂起、继续执行等操作

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

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

     线程:IO阻塞后,进程被挂起,不用切换页表、刷新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

  • 相关阅读:
    AOP & 拦截器
    过滤器 & 监听器 & 拦截器
    @PropertySouce注解 读取 properties文件
    SpringBoot整合freemarker 引用基础
    lombok工具插件安装(idea、eclipse)
    Spring Spring boot 获取IOC中的bean,ApplicationContext
    logback 生成 catalina.base_IS_UNDEFINED 问题处理 &如何在eclipse/idea中添加VM参数
    springboot读取系统级环境变量,和读写系统属性以及unittest来获取环境变量的方法
    C#变量命名规则
    C#中的注释
  • 原文地址:https://www.cnblogs.com/IDRI/p/7050782.html
Copyright © 2011-2022 走看看