精华内容
下载资源
问答
  • 吐血总结!50道Python面试题集锦(附答案)

    万次阅读 多人点赞 2019-07-05 20:56:12
    在本文中,我将总结Python面试中最常见的50个问题。每道题都提供参考答案,希望能够帮助你在2019年求职面试中脱颖而出,找到一份高薪工作。这些面试题涉及Python基础知识、Python编程、数据分析以及Python函数库等多...

    Python是目前编程领域最受欢迎的语言。在本文中,我将总结Python面试中最常见的50个问题。每道题都提供参考答案,希望能够帮助你在2019年求职面试中脱颖而出,找到一份高薪工作。这些面试题涉及Python基础知识、Python编程、数据分析以及Python函数库等多个方面。

    Q1、Python中的列表和元组有什么区别?

    Q2、Python的主要功能是什么?

    Python是一种解释型语言。与C语言等语言不同,Python不需要在运行之前进行编译。

    Python是动态语言,当您声明变量或类似变量时,您不需要声明变量的类型。

    Python适合面向对象的编程,因为它允许类的定义以及组合和继承。Python没有访问说明(如C ++的public,private)。

    在Python中,函数是第一类对象。它们可以分配给变量。类也是第一类对象

    编写Python代码很快,但运行比较慢。Python允许基于C的扩展,例如numpy函数库。

    Python可用于许多领域。Web应用程序开发,自动化,数学建模,大数据应用程序等等。它也经常被用作“胶水”代码。

    Q3、Python是通用编程语言吗?

    Python能够编写脚本,但从一般意义上讲,它被认为是一种通用编程语言。

    Q4、Python是如何解释语言的?

    Python在运行之前不需要对程序进行解释。因此,Python是一种解释型语言。

    Q5、什么是pep?

    PEP代表Python Enhancement Proposal。它是一组规则,指定如何格式化Python代码以获得最大可读性。

    Q6、如何在Python中管理内存?

    python中的内存管理由Python私有堆空间管理。所有Python对象和数据结构都位于私有堆中。程序员无权访问此私有堆。python解释器负责处理这个问题。

    Python对象的堆空间分配由Python的内存管理器完成。核心API提供了一些程序员编写代码的工具。

    Python还有一个内置的垃圾收集器,它可以回收所有未使用的内存,并使其可用于堆空间。

    Q7、Python中的命名空间是什么?

    命名空间是一个命名系统,用于确保名称是唯一性,以避免命名冲突。

    Q8、什么是PYTHONPATH?

    它是导入模块时使用的环境变量。每当导入模块时,也会查找PYTHONPATH以检查各个目录中是否存在导入的模块。解释器使用它来确定要加载的模块。

    Q9、什么是python模块?Python中有哪些常用的内置模块?

    Python模块是包含Python代码的.py文件。此代码可以是函数类或变量。一些常用的内置模块包括:sys、math、random、data time、JSON。

    Q10、Python中的局部变量和全局变量是什么?

    全局变量:在函数外或全局空间中声明的变量称为全局变量。这些变量可以由程序中的任何函数访问。

    局部变量:在函数内声明的任何变量都称为局部变量。此变量存在于局部空间中,而不是全局空间中。

    Q11、python是否区分大小写?

    是。Python是一种区分大小写的语言。

    Q12、什么是Python中的类型转换?

    类型转换是指将一种数据类型转换为另一种数据类型。

    int()  - 将任何数据类型转换为整数类型

    float()  - 将任何数据类型转换为float类型

    ord()  - 将字符转换为整数

    hex() - 将整数转换为十六进制

    oct()  - 将整数转换为八进制

    tuple() - 此函数用于转换为元组。

    set() - 此函数在转换为set后返回类型。

    list() - 此函数用于将任何数据类型转换为列表类型。

    dict() - 此函数用于将顺序元组(键,值)转换为字典。

    str() - 用于将整数转换为字符串。

    complex(real,imag)  - 此函数将实数转换为复数(实数,图像)数。

    Q13、如何在Windows上安装Python并设置路径变量?

    要在Windows上安装Python,请按照以下步骤操作:

    从以下链接安装python:https://http://www.python.org/downloads/

    下载之后,将其安装在您的PC上。在命令提示符下使用以下命令查找PC上安装PYTHON的位置:cmd python。

    然后转到高级系统设置并添加新变量并将其命名为PYTHON_NAME并粘贴复制的路径。

    查找路径变量,选择其值并选择“编辑”。

    如果值不存在,请在值的末尾添加分号,然后键入%PYTHON_HOME%

    Q14、python中是否需要缩进?

    缩进是Python必需的。它指定了一个代码块。循环,类,函数等中的所有代码都在缩进块中指定。通常使用四个空格字符来完成。如果您的代码没有必要缩进,它将无法准确执行并且也会抛出错误。

    Q15、Python数组和列表有什么区别?

    Python中的数组和列表具有相同的存储数据方式。但是,数组只能包含单个数据类型元素,而列表可以包含任何数据类型元素。

    Q16、Python中的函数是什么?

    函数是一个代码块,只有在被调用时才会执行。要在Python中定义函数,需要使用def关键字。

    Q17、什么是__init__?

    __init__是Python中的方法或者结构。在创建类的新对象/实例时,将自动调用此方法来分配内存。所有类都有__init__方法。

    Q18、什么是lambda函数?

    lambda函数也叫匿名函数,该函数可以包含任意数量的参数,但只能有一个执行操作的语句。

    Q19、Python中的self是什么?

    self是类的实例或对象。在Python中,self包含在第一个参数中。但是,Java中的情况并非如此,它是可选的。它有助于区分具有局部变量的类的方法和属性。init方法中的self变量引用新创建的对象,而在其他方法中,它引用其方法被调用的对象。

    Q20、区分break,continue和pass?

    Q21、[:: - 1}表示什么?

    [:: - 1]用于反转数组或序列的顺序。

    Q22、如何在Python中随机化列表中的元素?

    可以使用shuffle函数进行随机列表元素。举例如下:

     

    代码输出为:

     

    Q23、什么是python迭代器?

    迭代器是可以遍历或迭代的对象。

    Q24、如何在Python中生成随机数?

    random模块是用于生成随机数的标准模块。该方法定义为:

     

     

    random.random()方法返回[0,1]范围内的浮点数。该函数生成随机浮点数。随机类使用的方法是隐藏实例的绑定方法。可以使用Random的实例来显示创建不同线程实例的多线程程序。其中使用的其他随机生成器是:

    randrange(a,b):它选择一个整数并定义[a,b]之间的范围。它通过从指定范围中随机选择元素来返回元素。它不构建范围对象。

    uniform(a,b):它选择一个在[a,b)范围内定义的浮点数

    normalvariate(mean,sdev):它用于正态分布,其中mean是平均值,sdev是用于标准偏差的sigma。

    使用和实例化的Random类创建一个独立的多个随机数生成器。

    Q25、range&xrange有什么区别?

    在大多数情况下,xrange和range在功能方面完全相同。它们都提供了一种生成整数列表的方法,唯一的区别是range返回一个Python列表对象,x range返回一个xrange对象。这就表示xrange实际上在运行时并不是生成静态列表。它使用称为yielding的特殊技术根据需要创建值。该技术与一种称为生成器的对象一起使用。因此如果你有一个非常巨大的列表,那么就要考虑xrange。

    Q26、如何在python中写注释?

    Python中的注释以#字符开头。也可以使用doc-strings(三重引号中包含的字符串)进行注释。

    Q27、什么是pickling和unpickling?

    Pickle模块接受任何Python对象并将其转换为字符串表示形式,并使用dump函数将其转储到文件中,此过程称为pickling。从存储的字符串中检索原始Python对象的过程称为unpickling。

    Q28、python中的生成器是什么?

    返回可迭代项集的函数称为生成器。

    Q29、你如何把字符串的第一个字母大写?

    在Python中,capitalize()函数可以将字符串的第一个字母大写。如果字符串在开头已经包含大写字母,那么它将返回原始字符串。

    Q30、如何将字符串转换为全小写?

    要将字符串转换为小写,可以使用lower()函数。

    Q31、如何在python中注释多行?

    注释多行代码时。所有要注释的行都要在开头前加#。还可以使用快捷方式来注释多行,就是按住Ctrl键并在每个想要包含#字符的地方左键单击并键入一次#。

    Q32、什么是Python中的文档Docstrings?

    Docstrings实际上不是注释,它们是文档字符串。这些文档字符串在三引号内。它们没有分配给任何变量,因此有时也用于注释。

    Q33、operators中的is、not和in各有什么功能?

    Operators是特殊函数,它们比较一个或多个值并产生相应的结果。其中is:当2个操作数为true时返回true(例如:“a”是'a')

    not:返回布尔值的倒数

    in:检查某个元素是否存在于某个序列中

    Q34、Python中help()和dir()函数的用法是什么?

    Help()和dir()这两个函数都可以从Python解释器直接访问,并用于查看内置函数的合并转储。

    help()函数:help()函数用于显示文档字符串,还可以查看与模块,关键字,属性等相关的使用信息。

    dir()函数:dir()函数用于显示定义的符号。

    Q35、当Python退出时,为什么不清除所有分配的内存?

    当Python退出时,尤其是那些对其他对象具有循环引用的Python模块或者从全局名称空间引用的对象并没有被解除分配或释放。

    无法解除分配C库保留的那些内存部分。

    退出时,由于拥有自己的高效清理机制,Python会尝试取消分配/销毁其他所有对象。

    Q36、Python中的字典是什么?

    Python中的内置数据类型称为字典。它定义了键和值之间的一对一关系。字典包含一对键及其对应的值。字典由键索引。

    Q37、如何在python中使用三元运算符?

    三元运算符是用于显示条件语句的运算符。这包含true或false值,并且必须为其评估语句。其基本语法为:

    三元运算符是用于显示条件语句的运算符。这包含true或false值,并且必须为其评估语句。其基本语法为:

    [on_true] if [expression] else [on_false] x,y = 25,50big = x if x <y else y

    Q38、为什么使用* args,** kwargs?

    当我们不确定将多少个参数传递给函数,或者我们想要将存储的列表或参数元组传递给函数时,我们使用* args。**当我们不知道将多少关键字参数传递给函数时使用kwargs,或者它可以用于将字典的值作为关键字参数传递。标识符args和kwargs是一个约定,你也可以使用* bob和** billy。

    Q39、len()函数有什么作用?

    len()函数可用于确定字符串,列表,数组等的长度。

    Q40、在Python中split(),sub(),subn()功能。

    如果要修改字符串,Python的“re”模块提供了3种方法。他们是:

    split() - 使用正则表达式模式将给定字符串“拆分”到列表中。

    sub() - 查找正则表达式模式匹配的所有子字符串,然后用不同的字符串替换它们

    subn() - 它类似于sub(),并且还返回新字符串。

    Q41、什么是负指数,功能是什么?

    Python中的序列是索引的,它由正数和负数组成。积极的数字使用'0'作为第一个索引,'1'作为第二个索引,进程继续使用。

    负数的索引从'-1'开始,表示序列中的最后一个索引,' - 2'作为倒数第二个索引,序列像正数一样前进。

    负索引用于从字符串中删除任何换行符,并允许该字符串除了作为S [: - 1]给出的最后一个字符。负索引还用于显示索引以正确的顺序表示字符串。

    Q42、什么是Python包?

    Python包是包含多个模块的命名空间。

    Q43、如何在Python中删除文件?

    要在Python中删除文件,您需要导入OS模块。之后,您需要使用os.remove()函数。

    Q44、什么是python的内置类型?

    Python中的内置类型如下:整型、浮点型、复数、字符串、布尔等。

    Q45、NumPy中有哪些操作Python列表的函数?

    Python的列表是高效的通用容器。它们支持(相当)有效的插入,删除,追加和连接,Python的列表推导使它们易于构造和操作。

    它们有一定的局限性:它们不支持像素化加法和乘法等“向量化”操作,并且它们可以包含不同类型的对象这一事实意味着Python必须存储每个元素的类型信息,并且必须执行类型调度代码在对每个元素进行操作时。

    NumPy不仅效率更高; 它也更方便。你可以免费获得大量的向量和矩阵运算,这有时可以避免不必要的工作。它们也得到有效实施。

    NumPy数组更快,你可以使用NumPy,FFT,卷积,快速搜索,基本统计,线性代数,直方图等内置。

    Q46、如何将值添加到python数组?

    可以使用append(),extend()和insert(i,x)函数将元素添加到数组中。

    Q47、如何删除python数组的值?

    可以使用pop()或remove()方法删除数组元素。这两个函数之间的区别在于前者返回已删除的值,而后者则不返回。

    Q48、Python有OOps概念吗?

    Python是一种面向对象的编程语言。这意味着可以通过创建对象模型在python中解决任何程序。同时Python可以被视为程序语言和结构语言。

    Q49、深拷贝和浅拷贝有什么区别?

    在创建新实例类型时使用浅拷贝,并保留在新实例中复制的值。浅拷贝用于复制引用指针,就像复制值一样。这些引用指向原始对象,并且在类的任何成员中所做的更改也将影响它的原始副本。浅拷贝允许更快地执行程序,它取决于所使用的数据的大小。

    深拷贝用于存储已复制的值。深拷贝不会将引用指针复制到对象。它引用一个对象,并存储一些其他对象指向的新对象。原始副本中所做的更改不会影响使用该对象的任何其他副本。由于为每个被调用的对象创建了某些副本,因此深拷贝会使程序的执行速度变慢。

    Q50、如何在Python中实现多线程?

    Python有一个多线程库,但是用多线程来加速代码的效果并不是那么的好,

    Python有一个名为Global Interpreter Lock(GIL)的结构。GIL确保每次只能执行一个“线程”。一个线程获取GIL执行相关操作,然后将GIL传递到下一个线程。

    虽然看起来程序被多线程并行执行,但它们实际上只是轮流使用相同的CPU核心。

    所有这些GIL传递都增加了执行的开销。这意味着多线程并不能让程序运行的更快。

    展开全文
  • python面试

    千次阅读 多人点赞 2019-08-12 09:43:39
    python面试之路 最近在刷面试题,所以需要看大量的 Python 相关的面试题,从大量的题目中总结了很多的知识,同时也对一些题目进行拓展了,但是在看了网上的大部分面试题不是很满意,一个是有些部分还是 Python2 的...

    python面试之路

    最近在刷面试题,所以需要看大量的 Python 相关的面试题,从大量的题目中总结了很多的知识,同时也对一些题目进行拓展了,但是在看了网上的大部分面试题不是很满意,一个是有些部分还是 Python2 的代码,另一个就是回答的很简单,有些关键的题目,也没有点出为什么,最重要的是还有一些复制粘贴根本就跑不通,这种相信大家深有体会吧,这样就导致我们可能需要去找其他人发的类似的教程。难受啊,所以我决定针对市面上大多的 Python 题目做一个分析,同时也希望大家尽可能的做到举一反三,而不是局限于题目本身。大概就这样吧,有你看过的题目也有你没看到过的。

    所以题目如下:
    语言特性

    1.谈谈对 Python 和其他语言的区别
    2.简述解释型和编译型编程语言
    3.Python 的解释器种类以及相关特点?
    4.说说你知道的Python3 和 Python2 之间的区别?
    5.Python3 和 Python2 中 int 和 long 区别?
    6.xrange 和 range 的区别?
    编码规范

    7.什么是 PEP8?
    8.了解 Python 之禅么?
    9.了解 docstring 么?
    10.了解类型注解么?
    11.例举你知道 Python 对象的命名规范,例如方法或者类等
    12.Python 中的注释有几种?
    13.如何优雅的给一个函数加注释?
    14.如何给变量加注释?
    15.Python 代码缩进中是否支持 Tab 键和空格混用。
    16.是否可以在一句 import 中导入多个库?
    17.在给 Py 文件命名的时候需要注意什么?
    18.例举几个规范 Python 代码风格的工具
    数据类型

    字符串

    19.列举 Python 中的基本数据类型?
    20.如何区别可变数据类型和不可变数据类型
    21.将"hello world"转换为首字母大写"Hello World"
    22.如何检测字符串中只含有数字?
    23.将字符串"ilovechina"进行反转
    24.Python 中的字符串格式化方式你知道哪些?
    25.有一个字符串开头和末尾都有空格,比如“ adabdw ”,要求写一个函数把这个字符串的前后空格都去掉。
    26.获取字符串”123456“最后的两个字符。
    27.一个编码为 GBK 的字符串 S,要将其转成 UTF-8 编码的字符串,应如何操作?
    28. (1)s=“info:xiaoZhang 33 shandong”,用正则切分字符串输出’info’, ‘xiaoZhang’, ‘33’, ‘shandong’ a = "你好 中国 ",去除多余空格只留一个空格。
    29. (1)怎样将字符串转换为小写 (2)单引号、双引号、三引号的区别?
    列表

    30.已知 AList = [1,2,3,1,2],对 AList 列表元素去重,写出具体过程。
    31.如何实现 “1,2,3” 变成 [“1”,“2”,“3”]
    32.给定两个 list,A 和 B,找出相同元素和不同元素
    33.[[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]
    34.合并列表[1,5,7,9]和[2,2,6,8]
    35.如何打乱一个列表的元素?

    字典
    36.字典操作中 del 和 pop 有什么区别
    37.按照字典的内的年龄排序
    在这里插入图片描述
    42.如何交换字典 {“A”:1,“B”:2}的键和值?
    43.Python 里面如何实现 tuple 和 list 的转换?
    44.我们知道对于列表可以使用切片操作进行部分元素的选择,那么如何对生成器类型的对象实现相同的功能呢?
    45.请将[i for i in range(3)]改成生成器
    46.a="hello"和 b="你好"编码成 bytes 类型
    47.下面的代码输出结果是什么?
    在这里插入图片描述
    操作类题目
    49.Python 交换两个变量的值
    50.在读文件操作的时候会使用 read、readline 或者 readlines,简述它们各自的作用
    51.json 序列化时,可以处理的数据类型有哪些?如何定制支持 datetime 类型?
    52.json 序列化时,默认遇到中文会转换成 unicode,如果想要保留中文怎么办?
    53.有两个磁盘文件 A 和 B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件 C 中。
    54.如果当前的日期为 20190530,要求写一个函数输出 N 天后的日期,(比如 N 为 2,则输出 20190601)。
    55.写一个函数,接收整数参数 n,返回一个函数,函数的功能是把函数的参数和 n 相乘并把结果返回。
    56.下面代码会存在什么问题,如何改进?
    在这里插入图片描述
    57.一行代码输出 1-100 之间的所有偶数。
    58.with 语句的作用,写一段代码?
    59.python 字典和 json 字符串相互转化方法
    60.请写一个 Python 逻辑,计算一个文件中的大写字母数量
    61. 请写一段 Python连接 Mongo 数据库,然后的查询代码。
    62.说一说 Redis 的基本类型。
    63. 请写一段 Python连接 Redis 数据库的代码。
    64. 请写一段 Python 连接 MySQL 数据库的代码。
    65.了解 Redis 的事务么?
    66.了解数据库的三范式么?
    67.了解分布式锁么?
    68.用 Python 实现一个 Reids 的分布式锁的功能。
    69.写一段 Python 使用 Mongo 数据库创建索引的代码。
    高级特性

    70.函数装饰器有什么作用?请列举说明?
    71.Python 垃圾回收机制?
    72.魔法函数 __call__怎么使用?
    73.如何判断一个对象是函数还是方法?
    74.@classmethod 和@staticmethod 用法和区别
    75.Python 中的接口如何实现?
    76.Python 中的反射了解么?
    77.metaclass 作用?以及应用场景?
    78.hasattr() getattr() setattr()的用法
    79.请列举你知道的 Python 的魔法方法及用途。
    80.如何知道一个 Python 对象的类型?
    81.Python 的传参是传值还是传址?
    82.Python 中的元类(metaclass)使用举例
    83.简述 any()和 all()方法
    84.filter 方法求出列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    85.什么是猴子补丁?
    86.在 Python 中是如何管理内存的?
    87.当退出 Python 时是否释放所有内存分配?

    正则表达式

    88.使用正则表达式匹配出

    www.baidu.com

    中的地址
    a=“张明 98 分”,用 re.sub,将 98 替换为 100
    89.正则表达式匹配中(.)和(.?)匹配区别?
    90.写一段匹配邮箱的正则表达式
    其他内容

    91.解释一下 python 中 pass 语句的作用?
    92.简述你对 input()函数的理解
    93.python 中的 is 和==
    94.Python 中的作用域
    95.三元运算写法和应用场景?
    96.了解 enumerate 么?
    97.列举 5 个 Python 中的标准模块
    98.如何在函数中设置一个全局变量
    99.pathlib 的用法举例
    100.Python 中的异常处理,写一个简单的应用场景
    101.Python 中递归的最大次数,那如何突破呢?
    102.什么是面向对象的 mro
    103.isinstance 作用以及应用场景?
    104.什么是断言?应用场景?
    105.lambda 表达式格式以及应用场景?
    106.新式类和旧式类的区别
    107.dir()是干什么用的?
    108.一个包里有三个模块,demo1.py, demo2.py, demo3.py,但使用 from tools import 导入模块时,如何保证只有 demo1、demo3 被导入了。
    109.列举 5 个 Python 中的异常类型以及其含义
    110.copy 和 deepcopy 的区别是什么?
    111.代码中经常遇到的
    args, **kwargs 含义及用法。
    112.Python 中会有函数或成员变量包含单下划线前缀和结尾,和双下划线前缀结尾,区别是什么?
    113.w、a+、wb 文件写入模式的区别
    114.举例 sort 和 sorted 的区别
    115.什么是负索引?
    116.pprint 模块是干什么的?
    117.解释一下 Python 中的赋值运算符
    118.解释一下 Python 中的逻辑运算符
    119.讲讲 Python 中的位运算符
    120.在 Python 中如何使用多进制数字?
    121.怎样声明多个变量并赋值?
    算法和数据结构

    122.已知:

    AList = [1,2,3]
    BSet = {1,2,3}
    

    (1) 从 AList 和 BSet 中 查找 4,最坏时间复杂度那个大?
    (2) 从 AList 和 BSet 中 插入 4,最坏时间复杂度那个大?
    123.用 Python 实现一个二分查找的函数
    124.python 单例模式的实现方法
    125.使用 Python 实现一个斐波那契数列
    126.找出列表中的重复数字
    127.找出列表中的单个数字
    128.写一个冒泡排序
    129.写一个快速排序
    130.写一个拓扑排序
    131.python 实现一个二进制计算
    132.有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法。
    133.单链表反转
    134.交叉链表求交点
    135.用队列实现栈
    136.找出数据流的中位数
    137.二叉搜索树中第 K 小的元素

    爬虫相关

    138.在 requests 模块中,requests.content 和 requests.text 什么区别
    139.简要写一下 lxml 模块的使用方法框架
    140.说一说 scrapy 的工作流程
    141.scrapy 的去重原理
    142.scrapy 中间件有几种类,你用过哪些中间件
    143.你写爬虫的时候都遇到过什么?反爬虫措施,你是怎么解决的?
    144.为什么会用到代理?
    145.代理失效了怎么处理?
    146.列出你知道 header 的内容以及信息
    147.说一说打开浏览器访问 www.baidu.com 获取到结果,整个流程。
    148.爬取速度过快出现了验证码怎么处理
    149.scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?
    150.分布式爬虫主要解决什么问题
    151.写爬虫是用多进程好?还是多线程好? 为什么?
    152.解析网页的解析器使用最多的是哪几个
    153.需要登录的网页,如何解决同时限制 ip,cookie,session(其中有一些是动态生成的)在不使用动态爬取的情况下?
    154.验证码的解决(简单的:对图像做处理后可以得到的,困难的:验证码是点击,拖动等动态进行的?)
    155.使用最多的数据库(mysql,mongodb,redis 等),对他的理解?

    网络编程

    156.TCP 和 UDP 的区别?
    157.简要介绍三次握手和四次挥手
    158.什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
    并发

    159.举例说明 conccurent.future 的中线程池的用法
    160.说一说多线程,多进程和协程的区别。
    161.简述 GIL
    162.进程之间如何通信
    163.IO 多路复用的作用?
    164.select、poll、epoll 模型的区别?
    165.什么是并发和并行?
    166.一个线程 1 让线程 2 去调用一个函数怎么实现?
    167.解释什么是异步非阻塞?
    168.threading.local 的作用?

    Git 面试题

    169.说说你知道的 git 命令
    170.git 如何查看某次提交修改的内容

    展开全文
  • python面试题搜集

    万次阅读 2020-10-21 12:54:51
    1. Python面试题搜集(一) 2019 Python最新面试题及答案16道题吐血总结!50道Python面试题集锦(附答案) Python是目前编程领域最受欢迎的语言。在本文中,我将总结Python面试中最常见的50个问题。每道题都提供参考...

    1. Python面试题搜集(一)

    2019 Python最新面试题及答案16道题吐血总结!50道Python面试题集锦(附答案)

    Python是目前编程领域最受欢迎的语言。在本文中,我将总结Python面试中最常见的50个问题。每道题都提供参考答案,希望能够帮助你在2019年求职面试中脱颖而出,找到一份高薪工作。这些面试题涉及Python基础知识、Python编程、数据分析以及Python函数库等多个方面。

    Q1、Python中的列表和元组有什么区别?

    img

    Q2、Python的主要功能是什么?

    Python是一种解释型语言。与C语言等语言不同,Python不需要在运行之前进行编译。

    Python是动态语言,当您声明变量或类似变量时,您不需要声明变量的类型。

    Python适合面向对象的编程,因为它允许类的定义以及组合和继承。Python没有访问说明(如C ++的public,private)。

    在Python中,函数是第一类对象。它们可以分配给变量。类也是第一类对象

    编写Python代码很快,但运行比较慢。Python允许基于C的扩展,例如numpy函数库。

    Python可用于许多领域。Web应用程序开发,自动化,数学建模,大数据应用程序等等。它也经常被用作“胶水”代码。

    Q3、Python是通用编程语言吗?

    Python能够编写脚本,但从一般意义上讲,它被认为是一种通用编程语言。

    Q4、Python是如何解释语言的?

    Python在运行之前不需要对程序进行解释。因此,Python是一种解释型语言。

    Q5、什么是pep?

    PEP代表Python Enhancement Proposal。它是一组规则,指定如何格式化Python代码以获得最大可读性。

    Q6、如何在Python中管理内存?

    python中的内存管理由Python私有堆空间管理。所有Python对象和数据结构都位于私有堆中。程序员无权访问此私有堆。python解释器负责处理这个问题。

    Python对象的堆空间分配由Python的内存管理器完成。核心API提供了一些程序员编写代码的工具。

    Python还有一个内置的垃圾收集器,它可以回收所有未使用的内存,并使其可用于堆空间。

    Q7、Python中的命名空间是什么?

    命名空间是一个命名系统,用于确保名称是唯一性,以避免命名冲突。

    Q8、什么是PYTHONPATH?

    它是导入模块时使用的环境变量。每当导入模块时,也会查找PYTHONPATH以检查各个目录中是否存在导入的模块。解释器使用它来确定要加载的模块。

    Q9、什么是python模块?Python中有哪些常用的内置模块?

    Python模块是包含Python代码的.py文件。此代码可以是函数类或变量。一些常用的内置模块包括:sys、math、random、data time、JSON。

    Q10、Python中的局部变量和全局变量是什么?

    全局变量:在函数外或全局空间中声明的变量称为全局变量。这些变量可以由程序中的任何函数访问。

    局部变量:在函数内声明的任何变量都称为局部变量。此变量存在于局部空间中,而不是全局空间中。

    Q11、python是否区分大小写?

    是。Python是一种区分大小写的语言。

    Q12、什么是Python中的类型转换?

    类型转换是指将一种数据类型转换为另一种数据类型。

    int()  - 将任何数据类型转换为整数类型

    float()  - 将任何数据类型转换为float类型

    ord()  - 将字符转换为整数

    hex() – 将整数转换为十六进制

    oct()  - 将整数转换为八进制

    tuple() - 此函数用于转换为元组。

    set() - 此函数在转换为set后返回类型。

    list() - 此函数用于将任何数据类型转换为列表类型。

    dict() - 此函数用于将顺序元组(键,值)转换为字典。

    str() - 用于将整数转换为字符串。

    complex(real,imag)  – 此函数将实数转换为复数(实数,图像)数。

    Q13、如何在Windows上安装Python并设置路径变量?

    要在Windows上安装Python,请按照以下步骤操作:

    从以下链接安装python:https://http://www.python.org/downloads/

    下载之后,将其安装在您的PC上。在命令提示符下使用以下命令查找PC上安装PYTHON的位置:cmd python。

    然后转到高级系统设置并添加新变量并将其命名为PYTHON_NAME并粘贴复制的路径。

    查找路径变量,选择其值并选择“编辑”。

    如果值不存在,请在值的末尾添加分号,然后键入%PYTHON_HOME%

    Q14、python中是否需要缩进?

    缩进是Python必需的。它指定了一个代码块。循环,类,函数等中的所有代码都在缩进块中指定。通常使用四个空格字符来完成。如果您的代码没有必要缩进,它将无法准确执行并且也会抛出错误。

    Q15、Python数组和列表有什么区别?

    Python中的数组和列表具有相同的存储数据方式。但是,数组只能包含单个数据类型元素,而列表可以包含任何数据类型元素。

    Q16、Python中的函数是什么?

    函数是一个代码块,只有在被调用时才会执行。要在Python中定义函数,需要使用def关键字。

    Q17、什么是__init__?

    __init__是Python中的方法或者结构。在创建类的新对象/实例时,将自动调用此方法来分配内存。所有类都有__init__方法。

    Q18、什么是lambda函数?

    lambda函数也叫匿名函数,该函数可以包含任意数量的参数,但只能有一个执行操作的语句。

    Q19、Python中的self是什么?

    self是类的实例或对象。在Python中,self包含在第一个参数中。但是,Java中的情况并非如此,它是可选的。它有助于区分具有局部变量的类的方法和属性。init方法中的self变量引用新创建的对象,而在其他方法中,它引用其方法被调用的对象。

    Q20、区分break,continue和pass?

    img

    Q21、[:: – 1}表示什么?

    [:: – 1]用于反转数组或序列的顺序。

    Q22、如何在Python中随机化列表中的元素?

    可以使用shuffle函数进行随机列表元素。举例如下:

    img

    代码输出为:

    img

    Q23、什么是python迭代器?

    迭代器是可以遍历或迭代的对象。

    Q24、如何在Python中生成随机数?

    random模块是用于生成随机数的标准模块。该方法定义为:

    img

    作者:千锋教育

    链接:https://zhuanlan.zhihu.com/p/71913026

    来源:知乎

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    random.random()方法返回[0,1]范围内的浮点数。该函数生成随机浮点数。随机类使用的方法是隐藏实例的绑定方法。可以使用Random的实例来显示创建不同线程实例的多线程程序。其中使用的其他随机生成器是:

    randrange(a,b):它选择一个整数并定义[a,b]之间的范围。它通过从指定范围中随机选择元素来返回元素。它不构建范围对象。

    uniform(a,b):它选择一个在[a,b)范围内定义的浮点数

    normalvariate(mean,sdev):它用于正态分布,其中mean是平均值,sdev是用于标准偏差的sigma。

    使用和实例化的Random类创建一个独立的多个随机数生成器。

    Q25、range&xrange有什么区别?

    在大多数情况下,xrange和range在功能方面完全相同。它们都提供了一种生成整数列表的方法,唯一的区别是range返回一个Python列表对象,x range返回一个xrange对象。这就表示xrange实际上在运行时并不是生成静态列表。它使用称为yielding的特殊技术根据需要创建值。该技术与一种称为生成器的对象一起使用。因此如果你有一个非常巨大的列表,那么就要考虑xrange。

    Q26、如何在python中写注释?

    Python中的注释以#字符开头。也可以使用doc-strings(三重引号中包含的字符串)进行注释。

    Q27、什么是pickling和unpickling?

    Pickle模块接受任何Python对象并将其转换为字符串表示形式,并使用dump函数将其转储到文件中,此过程称为pickling。从存储的字符串中检索原始Python对象的过程称为unpickling。

    Q28、python中的生成器是什么?

    返回可迭代项集的函数称为生成器。

    Q29、你如何把字符串的第一个字母大写?

    在Python中,capitalize()函数可以将字符串的第一个字母大写。如果字符串在开头已经包含大写字母,那么它将返回原始字符串。

    Q30、如何将字符串转换为全小写?

    要将字符串转换为小写,可以使用lower()函数。

    Q31、如何在python中注释多行?

    注释多行代码时。所有要注释的行都要在开头前加#。还可以使用快捷方式来注释多行,就是按住Ctrl键并在每个想要包含#字符的地方左键单击并键入一次#。

    Q32、什么是Python中的文档Docstrings?

    Docstrings实际上不是注释,它们是文档字符串。这些文档字符串在三引号内。它们没有分配给任何变量,因此有时也用于注释。

    Q33、operators中的is、not和in各有什么功能?

    Operators是特殊函数,它们比较一个或多个值并产生相应的结果。其中is:当2个操作数为true时返回true(例如:“a”是’a’)

    not:返回布尔值的倒数

    in:检查某个元素是否存在于某个序列中

    Q34、Python中help()和dir()函数的用法是什么?

    Help()和dir()这两个函数都可以从Python解释器直接访问,并用于查看内置函数的合并转储。

    help()函数:help()函数用于显示文档字符串,还可以查看与模块,关键字,属性等相关的使用信息。

    dir()函数:dir()函数用于显示定义的符号。

    Q35、当Python退出时,为什么不清除所有分配的内存?

    当Python退出时,尤其是那些对其他对象具有循环引用的Python模块或者从全局名称空间引用的对象并没有被解除分配或释放。

    无法解除分配C库保留的那些内存部分。

    退出时,由于拥有自己的高效清理机制,Python会尝试取消分配/销毁其他所有对象。

    Q36、Python中的字典是什么?

    Python中的内置数据类型称为字典。它定义了键和值之间的一对一关系。字典包含一对键及其对应的值。字典由键索引。

    Q37、如何在python中使用三元运算符?

    三元运算符是用于显示条件语句的运算符。这包含true或false值,并且必须为其评估语句。其基本语法为:

    三元运算符是用于显示条件语句的运算符。这包含true或false值,并且必须为其评估语句。其基本语法为:

    [on_true] if [expression] else [on_false] x,y = 25,50big = x if x <y else y

    Q38、为什么使用* args,* kwargs?*

    当我们不确定将多少个参数传递给函数,或者我们想要将存储的列表或参数元组传递给函数时,我们使用* args。当我们不知道将多少关键字参数传递给函数时使用kwargs,或者它可以用于将字典的值作为关键字参数传递。标识符args和kwargs是一个约定,你也可以使用 bob和* billy。

    Q39、len()函数有什么作用?

    len()函数可用于确定字符串,列表,数组等的长度。

    Q40、在Python中split(),sub(),subn()功能。

    如果要修改字符串,Python的“re”模块提供了3种方法。他们是:

    split() – 使用正则表达式模式将给定字符串“拆分”到列表中。

    sub() – 查找正则表达式模式匹配的所有子字符串,然后用不同的字符串替换它们

    subn() – 它类似于sub(),并且还返回新字符串。

    Q41、什么是负指数,功能是什么?

    Python中的序列是索引的,它由正数和负数组成。积极的数字使用’0’作为第一个索引,’1’作为第二个索引,进程继续使用。

    负数的索引从’-1’开始,表示序列中的最后一个索引,’ – 2’作为倒数第二个索引,序列像正数一样前进。

    负索引用于从字符串中删除任何换行符,并允许该字符串除了作为S [: – 1]给出的最后一个字符。负索引还用于显示索引以正确的顺序表示字符串。

    Q42、什么是Python包?

    Python包是包含多个模块的命名空间。

    Q43、如何在Python中删除文件?

    要在Python中删除文件,您需要导入OS模块。之后,您需要使用os.remove()函数。

    Q44、什么是python的内置类型?

    Python中的内置类型如下:整型、浮点型、复数、字符串、布尔等。

    Q45、NumPy中有哪些操作Python列表的函数?

    Python的列表是高效的通用容器。它们支持(相当)有效的插入,删除,追加和连接,Python的列表推导使它们易于构造和操作。

    它们有一定的局限性:它们不支持像素化加法和乘法等“向量化”操作,并且它们可以包含不同类型的对象这一事实意味着Python必须存储每个元素的类型信息,并且必须执行类型调度代码在对每个元素进行操作时。

    NumPy不仅效率更高; 它也更方便。你可以免费获得大量的向量和矩阵运算,这有时可以避免不必要的工作。它们也得到有效实施。

    NumPy数组更快,你可以使用NumPy,FFT,卷积,快速搜索,基本统计,线性代数,直方图等内置。

    Q46、如何将值添加到python数组?

    可以使用append(),extend()和insert(i,x)函数将元素添加到数组中。

    Q47、如何删除python数组的值?

    可以使用pop()或remove()方法删除数组元素。这两个函数之间的区别在于前者返回已删除的值,而后者则不返回。

    Q48、Python有OOps概念吗?

    Python是一种面向对象的编程语言。这意味着可以通过创建对象模型在python中解决任何程序。同时Python可以被视为程序语言和结构语言。

    Q49、深拷贝和浅拷贝有什么区别?

    在创建新实例类型时使用浅拷贝,并保留在新实例中复制的值。浅拷贝用于复制引用指针,就像复制值一样。这些引用指向原始对象,并且在类的任何成员中所做的更改也将影响它的原始副本。浅拷贝允许更快地执行程序,它取决于所使用的数据的大小。

    深拷贝用于存储已复制的值。深拷贝不会将引用指针复制到对象。它引用一个对象,并存储一些其他对象指向的新对象。原始副本中所做的更改不会影响使用该对象的任何其他副本。由于为每个被调用的对象创建了某些副本,因此深拷贝会使程序的执行速度变慢。

    Q50、如何在Python中实现多线程?

    Python有一个多线程库,但是用多线程来加速代码的效果并不是那么的好,

    Python有一个名为Global Interpreter Lock(GIL)的结构。GIL确保每次只能执行一个“线程”。一个线程获取GIL执行相关操作,然后将GIL传递到下一个线程。

    虽然看起来程序被多线程并行执行,但它们实际上只是轮流使用相同的CPU核心。

    所有这些GIL传递都增加了执行的开销。这意味着多线程并不能让程序运行的更快。

    2.Python面试题搜集(二)

    2019 Python最新面试题及答案16道题

    这篇文章主要介绍了2019 Python最新面试题及答案16道题 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

    1.Python是如何进行内存管理的?

    答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制

    一、对象的引用计数机制

    Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。

    引用计数增加的情况:

    1,一个对象分配一个新名称

    2,将其放入一个容器中(如列表、元组或字典)

    引用计数减少的情况:

    1,使用del语句对对象别名显示的销毁

    2,引用超出作用域或被重新赋值

    sys.getrefcount( )函数可以获得对象的当前引用计数

    多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。

    二、垃圾回收

    1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

    2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

    三、内存池机制

    Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

    1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

    2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。

    3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

    2.什么是lambda函数?它有什么好处?

    答:lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数

    lambda函数:首要用途是指点短小的回调函数

    ?

    lambda` `[arguments]:expression``>>> a``=``lambdax,y:x``+``y``>>> a(``3``,``11``)
    

    3.Python里面如何实现tuple和list的转换?

    答:直接使用tuple和list函数就行了,type()可以判断对象的类型

    4.请写出一段Python代码实现删除一个list里面的重复元素

    答:

    1,使用set函数,set(list)

    2,使用字典函数,

    ?

    >>>a``=``[``1``,``2``,``4``,``2``,``4``,``5``,``6``,``5``,``7``,``8``,``9``,``0``]``>>> b``=``{}``>>>b``=``b.fromkeys(a)``>>>c``=``list``(b.keys())``>>> c
    

    5.编程用sort进行排序,然后从最后一个元素开始判断

    ?

    a``=``[``1``,``2``,``4``,``2``,``4``,``5``,``7``,``10``,``5``,``5``,``7``,``8``,``9``,``0``,``3``]``a.sort()``last``=``a[``-``1``]``for` `i inrange(``len``(a)``-``2``,``-``1``,``-``1``):``if` `last``=``=``a[i]:``del` `a[i]``else``:last``=``a[i]``print``(a)
    

    6.Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

    答:赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。

    浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}

    深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

    7.介绍一下except的用法和作用?

    答:try…except…except…[else…][finally…]

    执行try下的语句,如果引发异常,则执行过程会跳到except语句。对每个except分支顺序尝试执行,如果引发的异常与except中的异常组匹配,执行相应的语句。如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。

    try下的语句正常执行,则执行else块代码。如果发生异常,就不会执行

    如果存在finally语句,最后总是会执行。

    8.Python中pass语句的作用是什么?

    答:pass语句不会执行任何操作,一般作为占位符或者创建占位程序,whileFalse:pass

    9.介绍一下Python下range()函数的用法?

    答:列出一组数据,经常用在for in range()循环中

    10.如何用Python来进行查询和替换一个文本字符串?

    答:可以使用re模块中的sub()函数或者subn()函数来进行查询和替换,

    格式:sub(replacement, string[,count=0])(replacement是被替换成的文本,string是需要被替换的文本,count是一个可选参数,指最大被替换的数量)

    ?

    >>> ``import` `re``>>>p``=``re.``compile``(‘blue|white|red')``>>>``print``(p.sub(‘colour``','``blue socks ``and` `red shoes'))``colour socks ``and` `colourshoes``>>>``print``(p.sub(‘colour``','``blue socks ``and` `red shoes',count``=``1``))``colour socks ``and` `redshoes
    

    subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量

    11.Python里面match()和search()的区别?

    答:re模块中match(pattern,string[,flags]),检查string的开头是否与pattern匹配。

    re模块中research(pattern,string[,flags]),在string搜索pattern的第一个匹配值。

    ?

    >>>``print``(re.match(‘``super``', ‘superstition'``).span())``(``0``, ``5``)``>>>``print``(re.match(‘``super``', ‘insuperable'``))``None``>>>``print``(re.search(‘``super``', ‘superstition'``).span())``(``0``, ``5``)``>>>``print``(re.search(‘``super``', ‘insuperable'``).span())``(``2``, ``7``)
    

    12.用Python匹配HTML tag的时候,<.*>和<.*?>有什么区别?

    答:术语叫贪婪匹配( <.> )和非贪婪匹配(<.?> )

    例如:

    test

    <.*> :

    test

    <.*?> :

    13.Python里面如何生成随机数?

    答:random模块

    随机整数:random.randint(a,b):返回随机整数x,a<=x<=b

    random.randrange(start,stop,[,step]):返回一个范围在(start,stop,step)之间的随机整数,不包括结束值。

    随机实数:random.random( ):返回0到1之间的浮点数

    random.uniform(a,b):返回指定范围内的浮点数。

    14.有没有一个工具可以帮助查找python的bug和进行静态的代码分析?

    答:PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告

    Pylint是另外一个工具可以进行codingstandard检查

    15.如何在一个function里面设置一个全局的变量?

    答:解决方法是在function的开始插入一个global声明:

    def f()

    global x

    16.单引号,双引号,三引号的区别

    答:单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释

    如果要表示Let’s go 这个字符串

    单引号:s4 = ‘Let’s go’

    双引号:s5 = “Let’s go”

    s6 = ‘I realy like“python”!'
    

    这就是单引号和双引号都可以表示字符串的原因了

    总结

    以上所述是小编给大家介绍的2019 Python最新面试题及答案16道题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
    如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

    3.Python面试题搜集(三)

    Python 经典面试题(一)

    一、浮点数运算

    题目

    判断浮点数的运行结果是否相等:

     a = 0.1 b = 0.2 c = 0.3 assert a + b == c
    

    题目解析:

    本题考查的是计算机的浮点运算知识点。不仅是 python 语言,其他的编程语言也面临同样的问题:在进行浮点运算的时候,10 进制表示方式会丢掉它的精度,造成运算结果与实际结果不符合。

    这是由于底层 CPU 和运算标准通过自己的浮点单位去执行算术时的特征决定的。看似有穷的小数, 在计算机的二进制表示里却是无穷的。

    所以在进行高进度浮点运算的时候一定要注意,尤其是自动化测试过程中需要进行断言非常容易出错。

    题目答案:

    断言失败,抛出 AssertionError 错误。

    解决方案:

    使用 Decimal 模块:

     from decimal import Decimal  a = 0.1 b = 0.2 c = 0.3 assert Decimal(str(a)) + Decimal(str(b)) == Decimal(str(c))
    

    Decimal() 可以维持浮点数的精度,在金融领域和测试领域等精度要求高的行业有非常大的作用。 但是一定要注意: Decimal() 传的参数一定要是字符串类型,如果是数据类型会再次丢掉精度。

      Decimal(0.1) + Decimal(0.2) == Decimal(0.3)  # False   Decimal('0.1') + Decimal('0.2') == Decimal('0.3')  # True
    

    二、列表的扁平化和降维

    题目

    有一个二维列表,降成普通的一维的。比如说柠檬班都会有学员分组,我们想通过分组信息去获取所有的学员名称。

     groups = [['huahua', 'xiaojian'], ['musen', 'yuze'], ['keyou']] # 得到结果 ['huahua', 'xiaojian', 'musen', 'yuze', 'keyou']
    

    方法一

    最简单的方式可以通过 for 循环的方式一一提取:

     names = [] for group in groups:     for name in group:         names.append(name) print(names)
    

    方法二

    但是在面试的时候可能会加一些限制,比如让你用一行代码实现,这个时候就需要对 python 基础有进一步的理解了,比如说使用 sum 函数:

     names = sum(groups, [])
    

    非常简单就实现了同样的功能。 sum 函数为什么可以做到呢?先看一个简单的例子:

     a = sum([1,2,3])
    

    得到的结果是 6, 也就是说, sum 函数会把一个列表里面的每个元素相加。但是 sum 函数还可以有第二个参数:开始值,默认为 0 , 所以上述过程其实可以写成:

     a = sum([1,2,3], 0) # 0 + 1 + 2 + 3
    

    依据同样的道理,可以对列表进行降维操作:

    a = sum([['yuze'], ['is'], ['a']], [])
    # [] + ['yuze'] + ['is'] + ['a']
    # 列表拼接
    

    方法三

    通过列表推导式也可以方便的解决:

    a = [e for group in groups for e in group]
    

    三、多重继承

    class A:
        def run(self):
            print("a is running")
    
    class B:
        def run(self):
            print("b is running")
    
    class C(A, B):
        pass
    
    # 会打印什么???
    C().run()
    

    多重继承经常用来出面试题。在这个考题中,C 类的父类 A 和 B 都实现了 run 方法,那在 C 的对象里到底是优先调用哪一个呢?

    答案是: a running

    菱形问题

    class A:
        def run(self):
            print("a running")
    
    class B(A):
        pass
    
    class C(A):
        def run(self):
            print("C running")
    
    class D(B, C):
        pass
    
    # 会打印什么???
    D().run()
    

    他们的继承关系图可以简化如下,这个问题又称为菱形问题或者钻石问题:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMhnClAk-1603255929159)(data:image/png;base64,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8uTJeHp64unpyejRo5k/fz5ffPEFK1eu5JtvvmHr1q2cO3eO27dvc/v2bZKSksjOziY3Nxe1Wo3RaJQZAiGEEOWOBAQhRLlhMpnIycnhwIEDODs7889//pO33noLKysrFi1aRGxsrEWetD9tc3q62PjfXyaT6dnr/37taYtQabRJ/acapayVvIwAACAASURBVCVJCCFESZCAIISwOEVRKCgo4Pjx47i7u1OjRg2aN2/OvHnzuHz5MmlpaRQXF1e4Q87KUmpqKufPn+f27duWLkUIIUQFJwFBCGFRarWa0NBQPv/8c9q0aUOzZs3w9vbmxx9/JD09HZ1OJ0/Fn0NERASzZ8/mk08+4cGDB/I9E0II8dIkIAghLEJRFFQqFUeOHKF///40btyYHj16EBgYSGxsLBqNRga5LyA3N5etW7fi7u6On58f+fn5li5JCCFEBSUBQQhR5sxmM7GxsXz77bc4OzvTokULxo8fz8WLF59t7ylejMlkIioqivnz59OjRw9OnDghAUsIIcRLkYAghCgziqKg1Wo5f/48M2bMwNHRkV69erFixQru3LmDXq+3dIkVmlar5fjx4wwcOBBvb29SUlIsXZIQQogKSAKCEKJMKIpCdnY2hw8fZvjw4bi4uDBp0iQOHjxISkpKqZ1x8CpRFIXExET8/f358MMP2bx5s3xfhRBCvDAJCEKIUqcoChEREQQEBNCvXz/69OnDsmXLuHXrFiqVSlphSpBer+fy5ct4enrSr18/oqOjLV2SEEKICkYCghCi1CiKQlFREZcuXcLHxwcnJyeGDBnCzp07SU5Olm1LS0l2djabN2/G3t6eVatWyYJvIYQQL0QCghCiVJjNZnJzczly5Ah9+/alRYsWjB49mosXL1JUVCQD1lJkMpl4/PgxI0aMoEOHDty5cweDwWDpsoQQQlQQEhCEECXOaDSSlpbG7t27n+1SNGfOHO7du4dGo7F0ea+EvLw8tmzZQq1atfj888/JysqS3aGEEEI8FwkIQogSoygKarWayMhI1q5dS7t27WjdujXr16+XAWoZM5vNREdH0717d6ysrDhz5gxardbSZQkhhKgAJCAIIUqEoijk5+dz7tw5xo8fT926denevTsXL15Er9dLS5EF5Ofns3btWt58800mTpxIenq6/DsIIYT4TRIQhBC/m9lsJi8vj7179+Ls7MwH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)]

    答案是: c running

    如果我们不让 C 类继承 A 呢?

    class A:
        def run(self):
            print("a running")
    
    class B(A):
        pass
    
    class C:
        def run(self):
            print("C running")
    
    class D(B, C):
        pass
    
    # 会打印什么???
    D().run()
    

    他们的继承关系图可以简化如下,可以简称为 v 型问题:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OZbtHlGU-1603255929160)(data:image/png;base64,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)]

    答案会变成 a running

    题目解析

    具体原因是 python 的继承会遵循特定的顺序,优先级排在前面的,子类会优先使用。怎么快速查看这种继承顺序呢?通过D.__mro__去查看

    比如在 菱形问题上,d 的顺序是这样的:

    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    

    D 排在最前面,如果 D 定义了 run 方法,就会被优先使用,然后是 B, 然后是C, 然后是 A, 最后是 object 基类。

    而在 V 行问题上,d 的顺序又变成了这样:

    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)
    

    A 和 C 互换了顺序。造成 2 个题目的答案不一致。

    4.Python面试题搜集(四)

    最常见的 35 个 Python 面试题及答案(2018 版)

    \1. Python 面试问题及答案

    作为一个 Python 新手,你必须熟悉基础知识。在本文中我们将讨论一些 Python 面试的基础问题和高级问题以及答案,以帮助你完成面试。包括 Python 开发问题、编程问题、数据结构问题、和 Python 脚本问题。让我们来深入研究这些问题

    Python 面试问题

    Q.1. Python 的特点和优点是什么?

    Python 可以作为编程的入门语言,因为他具备以下特质:

    \1. 解释性

    \2. 动态特性

    \3. 面向对象

    \4. 语法简洁

    \5. 开源

    \6. 丰富的社区资源

    实际上 Python 的优点远不止这些,更详细的介绍可以阅读 Introduction to Python( https://data-flair.training/blogs/python-tutorial/)

    Q.2. 深拷贝和浅拷贝的区别是什么?

    深拷贝是将对象本身复制给另一个对象。这意味着如果对对象的副本进行更改时不会影响原对象。在 Python 中,我们使用 deepcopy()函数进行深拷贝,使用方法如下:

    深拷贝-Python 面试问题及答案

    浅拷贝是将对象的引用复制给另一个对象。因此,如果我们在副本中进行更改,则会影响原对象。使用 copy()函数进行浅拷贝,使用方法如下:

    浅拷贝—Python 面试问题及答案

    Q.3. 列表和元祖有什么不同?

    主要区别在于列表是可变的,元祖是不可变的。看下面的例子:

    img

    会出现以下错误提示:

    TypeError: ‘tuple’ object does not support item assignment

    关于列表和元祖的更多内容参考 Tuples vs Lists( https://data-flair.training/blogs/python-tuples-vs-lists/)

    \2. Python 面试基础题

    Q.4 到 Q.20 是新手经常会被问到的一些 Python 基础题,有经验的人也可以参考这些问题来复习这些概念。

    Q.4. 解释 Python 中的三元表达式

    与 C++不同, 在 Python 中我们不需要使用 ? 符号,而是使用如下语法:

    [on true] if [expression]else [on false]

    如果 [expression] 为真, 则 [on true] 部分被执行。如果表示为假则 [on false] 部分被执行

    下面是例子:

    2

    Hi

    Q.5. Python 中如何实现多线程?

    线程是轻量级的进程,多线程允许一次执行多个线程。众所周知,Python 是一种多线程语言,它有一个多线程包。

    GIL(全局解释器锁)确保一次执行单个线程。一个线程保存 GIL 并在将其传递给下一个线程之前执行一些操作,这就产生了并行执行的错觉。但实际上,只是线程轮流在 CPU 上。当然,所有传递都会增加执行的开销。

    Q.6. 解释继承

    一个类继承自另一个类,也可以说是一个孩子类/派生类/子类,继承自父类/基类/超类,同时获取所有的类成员(属性和方法)。

    继承使我们可以重用代码,并且还可以更方便地创建和维护代码。Python 支持以下类型的继承:

    \1. 单继承- 一个子类类继承自单个基类

    \2. 多重继承- 一个子类继承自多个基类

    \3. 多级继承- 一个子类继承自一个基类,而基类继承自另一个基类

    \4. 分层继承- 多个子类继承自同一个基类

    \5. 混合继承- 两种或两种以上继承类型的组合

    关于继承的更多内容参考 Python Inheritance( https://data-flair.training/blogs/python-inheritance/)

    Q.7. 什么是 Flask?

    Flask 是一个使用 Python 编写的轻量级 Web 应用框架,使用 BSD 授权。其 WSGI 工具箱采用 Werkzeug,模板引擎则使用 Jinja2。除了 Werkzeug 和 Jinja2 以外几乎不依赖任何外部库。因为 Flask 被称为轻量级框架。

    Flask 的会话会话使用签名 cookie 来允许用户查看和修改会话内容。它会记录从一个请求到另一个请求的信息。但如果要修改会话,则必须有密钥 Flask.secret_key。

    我们将在后续的课程中进一步讨论 Flask。

    Q.8. 如何在 Python 中管理内存?

    Python 用一个私有堆内存空间来放置所有对象和数据结构,我们无法访问它。由解释器来管理它。不过使用一些核心 API,我们可以访问一些 Python 内存管理工具控制内存分配。

    Q.9. 解释 Python 中的 help() 函数和 dir() 函数。

    help() 函数返回帮助文档和参数说明:

    运行结果如下:

    Help on function copy in module copy

    copy(x)

    Shallow copy operation on arbitrary Python objects.

    See the module』s doc string for more info.

    dir() 函数返回对象中的所有成员 (任何类型)

    img

    Q.10. 当退出 Python 时是否释放所有内存分配?

    答案是否定的。那些具有对象循环引用或者全局命名空间引用的变量,在 Python 退出是往往不会被释放

    另外不会释放 C 库保留的部分内容。

    Q.11. 什么是猴子补丁?

    在运行时动态修改类和模块

    img

    Hi, monkey

    Q.12. 什么是 Python 字典?

    字典是我在 C++和 Java 中没有见过的数据结构,它拥有键-值对

    3

    字典是可变的,我们也可以用推导式的方式创建它.

    {25: 5, 16: 4, 9: 3, 4: 2, 1: 1}

    要了解更多字典的内容请点击 Python Dictionaries( https://data-flair.training/blogs/python-dictionaries/)

    Q.13. 能否解释一下 *args 和 **kwargs?

    如果我们不知道将多少个参数传递给函数,比如当我们想传递一个列表或一个元组值时,就可以使用*args。

    3

    2

    1

    4

    7

    当我们不知道将会传入多少关键字参数时,使用**kwargs 会收集关键字参数。

    a.1

    b.2

    c.7

    使用 args 和 kwargs 作为参数名只是举例,可以任意替换。

    对于 Python 的基础题任何疑问,请在评论区提问。

    Q.14. 编程实现计算文件中的大写字母数

    img

    26

    Q.15. 什么是负索引?

    我们先创建如下列表:

    与正索引不同,负索引是从右边开始检索。

    6

    同样可以用于列表的切片:

    [3, 4, 5, 6, 7]

    Q.16. 如何随机打乱列表中元素,要求不引用额外的内存空间?

    我们用 random 包中的 shuffle() 函数来实现。

    [3, 4, 8, 0, 5, 7, 6, 2, 1]

    Q.17. 解释 Python 中的 join() 和 split() 函数

    join() 函数可以将指定的字符添加到字符串中。

    ‘1,2,3,4,5’

    split() 函数可以用指定的字符分割字符串

    [‘1’, ‘2’, ‘3’, ‘4’, ‘5’]

    Q.18. Python 区分大小写吗?

    验证 Python 是否区分大小写的方法是测试 myname 和 Myname 在程序中是不是算同一个标识符。观察以下代码的返回结果:

    Myname

    NameError: name ‘Myname’ is not defined

    如你所见,这里出现了 NameError,所以 Python 是区分大小的语言。

    Q.19. Python 中标识符的命名规则?

    Python 中的标识符可以是任意长度,但必须遵循以下命名规则:

    \1. 只能以下划线或者 A-Z/a-z 中的字母开头。

    \2. 其余部分只能使用 A-Z/a-z/0-9。

    \3. Python 标识符区分大小写。

    \4. 关键字不能作为标识符。Python 有以下这些关键字:

    img

    Q.20. 如何删除字符串中的前置空格

    前置空格是第一个非空格字符前的所有空格,使用 lstrip() 函数来删除.

    ‘Ayushi ‘

    如图这个字符串既包含前置空格也包含后置空格. 调用 lstrip() 函数去除了前置空格。如果想去除后置空格,使用 rstrip() 函数。

    ‘ Ayushi’

    以上是面向 Python 新手的基础题部分。

    \3. Python 面试进阶题

    Q. 21 至 Q. 35 是针对有经验者的一些 Python 面试问题及其答案和示例。

    Q.21. 如何将字符串转换为小写?

    使用 lower() 函数

    ‘ayushi’

    转换为大写用 upper() 函数

    ‘AYUSHI’

    要检查字符串是否为全大写或全小写,使用 isupper() 和 islower() 函数

    img

    像 @ 和$这样的字符即满足大写也满足小写。

    istitle() 可以检查字符串是否是标题格式。

    True

    Q.22. Python 中的 pass 语句有什么作用?

    我们在写代码时,有时可能只写了函数声明而没想好函数怎么写,但为了保证语法检查的正确必须输入一些东西。在这种情况下,我们使用 pass 语句。

    类似的 break 语句可以跳出循环。

    0

    1

    2

    continue 语句可以跳到下一轮循环。

    0

    1

    2

    4

    5

    6

    Q.23. 请解释 Python 中的闭包?

    如果在一个内部函数里。对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就是一个闭包。

    7

    闭包的详细解释请点击 Closures in Python。(https://data-flair.training/blogs/python-closure/)

    Q.24. 解释 Python 中的//,%和**运算符

    //运算符执行地板除法,返回结果的整数部分 (向下取整)。

    3

    用/符号除法结果为 3.5。

    符号表示取幂. ab 返回 a 的 b 次方

    1024

    % 是取模符号。返回除法后的余数。

    6

    0.5

    对于 Python 进阶面试问题和答案有任何疑问请在评论区提问。

    Q.24. Python 中有多少种运算符,解释算术运算符。

    这类面试问题可以判断你的 Python 功底,可以举一些实例来回答这类问题。

    在 Python 中我们有 7 中运算符:算术运算符、关系 (比较) 运算符、赋值运算符、逻辑运算符、位运算符、成员运算符、身份运算符。

    \1. 加号 (+) 将两个对象的值相加。

    15

    \2. 减号 (-) 将第一个对象的值减去第二个对象的值。

    -1

    \3. 乘号 (*) 将两个对象的值相乘。

    56

    \4. 除号 (/) 将第一个对象的值除以第二个对象的值。

    0.875

    1.0

    关于地板除法、取模和取幂,请参考上一个问题。

    Q.25. 解释 Python 中的关系运算符。

    关系运算符用来比较两个对象。

    \1. 判断小于 (<):如果符号左边的值比右边小则返回 True。

    False

    \2. 判断大于 (>):如果符号左边的值比右边大则返回 True。

    True

    出现上面的错误结果是因为 Python 的浮点运算存在一些 Bug。

    \3. 判断小于等于 (<=):如果符号左边的值小于或等于右边则返回 True。

    True

    \4. 大判断于等于 (>=):如果符号左边的值大于或等于右边则返回 True。

    True

    \5. 判断等于 (==) 如果符号两边的值相等则返回 True。

    True

    \6. 判断不等于 (!=) 如果符号两边的值不等则返回 True。

    True

    True

    Q.26. 解释 Python 中的赋值和算数运算符?

    这是面试中的常见题目。我们将算数运算符和赋值符号放在一起介绍。

    img

    Q.27. 解释 Python 中的逻辑运算符

    Python 中有三个逻辑运算符:and、or、not

    img

    Q.28. 解释 Python 中的成员运算符

    使用 in 和 not in 运算符我们可以判断某个值是否在成员中。

    img

    Q.29. 解释 Python 中的身份运算符

    这是非常常见的 Python 面试题,用下面的示例来回答.

    is 和 not is 运算符可以判断两个对象是否相同

    img

    Q.30. 解释 Python 中的位运算符

    此运算符按二进制位对值进行操作。

    \1. 与 (&) 返回按位与结果

    2

    \2. 或 (|) 返回按位或结果

    3

    \3. 异或 (^) 返回按位异或结果

    1

    \4. 取反 (~) 返回按位取反结果

    -3

    \5. 左移位 (<<) 将符号左边数的二进制左移右边数位

    4

    1 的二级制 001 左移 2 位变成 100 也即十进制的 4

    \6. 右移位 (>>)

    1

    想了解关于位运算符的更多内容请点击 Operators in Python(https://data-flair.training/blogs/python-operators/)

    Q.31. 如何在 Python 使用多进制数字?

    除十进制以外,在 Python 中还可以使用二进制、八进制、十六进制。

    \1. 二进制数有 0 和 1 组成,我们使用 0b 或 0B 前缀表示二进制数

    10

    使用 bin() 函数可以将数字转换为二进制

    ‘0b1111’

    \2. 八进制数由数字 0-7 组成,使用前缀 0o 或 0O 表示 8 进制数

    ‘0o10’

    \3. 十六进数由数字 0-15 组成,使用前缀 0x 或者 0X 表示 16 进制数

    ‘0x10’

    ‘0xf’

    Q.32. 如何获取字典中的所有键?

    使用 keys() 来获取字典中的所有键

    Q.33. 问什么标识符不建议使用下划线开头?

    因为在 Python 中以下划线开头的变量为私有变量,如果你不想让变量私有,就不要使用下划线开头。

    Q.34. 如何声明多个变量并赋值?

    有两种方式:

    Q.35. 什么是元组的解封装?

    首先我们来介绍元组封装:

    (3, 4, 5)

    将 3,4,5 封装到元组 mytuple 中。

    现在我们要将这些值解封装到变量 x,y,z 中

    12

    以上是 Python 高级面试问题和答案,新手也可以参考这些问题以获得进阶的 Python 知识。

    \4. 结束语

    本篇文章介绍了一些重要的 Python 面试问题和答案,后续我们还会增加。在你面试之前应该熟练掌握这些。如有想添加的问题欢迎随时评论。

    5.Python面试题搜集(五)

    整理的最全 python常见面试题(基本必考)

    1、大数据的文件读取

    ① 利用生成器generator

    ②迭代器进行迭代遍历:for line in file

    2、迭代器和生成器的区别

    1)迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身。对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数,iter()是python的内置函数。iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数。在没有后续元素时,next()会抛出一个StopIteration异常

    2)生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)

    区别:生成器能做到迭代器能做的所有事,而且因为自动创建了__iter__()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常

    3、装饰器的作用和功能:

    引入日志

    函数执行时间统计

    执行函数前预备处理

    执行函数后的清理功能

    权限校验等场景

    缓存

    4、简单谈下GIL:

    Global Interpreter Lock(全局解释器锁)

    Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。

    在多线程环境中,Python 虚拟机按以下方式执行:

    \1. 设置GIL
    \2. 切换到一个线程去运行
    \3. 运行:
    a. 指定数量的字节码指令,或者

    b. 线程主动让出控制(可以调用time.sleep(0))
    \4. 把线程设置为睡眠状态
    \5. 解锁GIL
    \6. 再次重复以上所有步骤

    在调用外部代码(如C/C++扩展函数)的时候,GIL 将会被锁定,直到这个函数结束为止(由于在这期间没有Python 的字节码被运行,所以不会做线程切换)。

    5、find和grep

    grep命令是一种强大的文本搜索工具,grep搜索内容串可以是正则表达式,允许对文本文件进行模式查找。如果找到匹配模式,grep打印包含模式的所有行。

    find通常用来再特定的目录下搜索符合条件的文件,也可以用来搜索特定用户属主的文件。

    6、线上服务可能因为种种原因导致挂掉怎么办?

    linux下的后台进程管理利器 supervisor

    每次文件修改后再linux执行 service supervisord restart

    7、如何提高python的运行效率

    使用生成器;关键代码使用外部功能包(Cython,pylnlne,pypy,pyrex);针对循环的优化–尽量避免在循环中访问变量的属性

    8、常用Linux命令:

    ls,help,cd,more,clear,mkdir,pwd,rm,grep,find,mv,su,date

    9、Python中的yield用法

    yield简单说来就是一个生成器,这样函数它记住上次返 回时在函数体中的位置。对生成器第 二次(或n 次)调用跳转至该函 次)调用跳转至该函 数。

    10、Python是如何进行内存管理的

    一、垃圾回收:python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。

    二、引用计数:Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。当变量被绑定在一个对象上的时候,该变量的引用计数就是1,(还有另外一些情况也会导致变量引用计数的增加),系统会自动维护这些标签,并定时扫描,当某标签的引用计数变为0的时候,该对就会被回收。

    三、内存池机制Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作,

    第0层是C中的malloc,free等内存分配和释放函数进行操作;

    第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;

    第3层是最上层,也就是我们对Python对象的直接操作;

    在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片. Python 在这里主要干的工作有:

    如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.

    这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.

    经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free 释放掉.以便下次使用.对于简单的Python对象,例如数值、字符串,元组(tuple不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同

    11、描述数组、链表、队列、堆栈的区别?

    数组与链表是数据存储方式的概念,数组在连续的空间中存储数据,而链表可以在非连续的空间中存储数据;

    队列和堆栈是描述数据存取方式的概念,队列是先进先出,而堆栈是后进先出;队列和堆栈可以用数组来实现,也可以用链表实现。

    12、你知道几种排序,讲一讲你最熟悉的一种?

    img

    你是最棒的!

    web框架部分

    1.django 中当一个用户登录 A 应用服务器(进入登录状态),然后下次请求被 nginx 代理到 B 应用服务器会出现什么影响?

    如果用户在A应用服务器登陆的session数据没有共享到B应用服务器,纳米之前的登录状态就没有了。

    2.跨域请求问题django怎么解决的(原理)

    启用中间件

    post请求

    验证码

    表单中添加{%csrf_token%}标签

    3.请解释或描述一下Django的架构

    对于Django框架遵循MVC设计,并且有一个专有名词:MVT

    M全拼为Model,与MVC中的M功能相同,负责数据处理,内嵌了ORM框架

    V全拼为View,与MVC中的C功能相同,接收HttpRequest,业务处理,返回HttpResponse

    T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html,内嵌了模板引擎

    4.django对数据查询结果排序怎么做,降序怎么做,查询大于某个字段怎么做

    排序使用order_by()

    降序需要在排序字段名前加-

    查询字段大于某个值:使用filter(字段名_gt=值)

    5.说一下Django,MIDDLEWARES中间件的作用?

    答:中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。

    6.你对Django的认识?

    Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

    Django内置的ORM跟框架内的其他模块耦合程度高。

    应用程序必须使用Django内置的ORM,否则就不能享受到框架内提供的种种基于其ORM的便利;理论上可以切换掉其ORM模块,但这就相当于要把装修完毕的房子拆除重新装修,倒不如一开始就去毛胚房做全新的装修。

    Django的卖点是超高的开发效率,其性能扩展有限;采用Django的项目,在流量达到一定规模后,都需要对其进行重构,才能满足性能的要求。

    Django适用的是中小型的网站,或者是作为大型网站快速实现产品雏形的工具。

    Django模板的设计哲学是彻底的将代码、样式分离; Django从根本上杜绝在模板中进行编码、处理数据的可能。

    \7. Django重定向你是如何实现的?用的什么状态码?

    使用HttpResponseRedirect

    redirect和reverse

    状态码:302,301

    8.ngnix的正向代理与反向代理?

    正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

    反向代理正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。

    \9. Tornado 的核是什么?

    Tornado 的核心是 ioloop 和 iostream 这两个模块,前者提供了一个高效的 I/O 事件循环,后者则封装了 一个无阻塞的 socket 。通过向 ioloop 中添加网络 I/O 事件,利用无阻塞的 socket ,再搭配相应的回调 函数,便可达到梦寐以求的高效异步执行。

    10.Django 本身提供了 runserver,为什么不能用来部署?

    runserver 方法是调试 Django 时经常用到的运行方式,它使用 Django 自带的

    WSGI Server 运行,主要在测试和开发中使用,并且 runserver 开启的方式也是单进程 。

    uWSGI 是一个 Web 服务器,它实现了 WSGI 协议、uwsgi、http 等协议。注意 uwsgi 是一种通信协议,而 uWSGI 是实现 uwsgi 协议和 WSGI 协议的 Web 服务器。uWSGI 具有超快的性能、低内存占用和多 app 管理等优点,并且搭配着 Nginx

    就是一个生产环境了,能够将用户访问请求与应用 app 隔离开,实现真正的部署 。相比来讲,支持的并发量更高,方便管理多进程,发挥多核的优势,提升性能。

    你是最棒的!

    网络编程和前端部分

    1.AJAX是什么,如何使用AJAX?

    ajax(异步的javascript 和xml) 能够刷新局部网页数据而不是重新加载整个网页。

    第一步,创建xmlhttprequest对象,var xmlhttp =new XMLHttpRequest();XMLHttpRequest对象用来和服务器交换数据。

    第二步,使用xmlhttprequest对象的open()和send()方法发送资源请求给服务器。

    第三步,使用xmlhttprequest对象的responseText或responseXML属性获得服务器的响应。

    第四步,onreadystatechange函数,当发送请求到服务器,我们想要服务器响应执行一些功能就需要使用onreadystatechange函数,每次xmlhttprequest对象的readyState发生改变都会触发onreadystatechange函数。

    \2. 常见的HTTP状态码有哪些?

    200 OK

    301 Moved Permanently

    302 Found

    304 Not Modified

    307 Temporary Redirect

    400 Bad Request

    401 Unauthorized

    403 Forbidden

    404 Not Found

    410 Gone

    500 Internal Server Error

    501 Not Implemented

    \3. Post和get区别?

    GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。

    POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。上面的item=bandsaw就是实际的传输数据。

    因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。

    2、传输数据的大小

    在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。

    对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

    3、安全性

    POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击。

    4.cookie 和session 的区别?

    1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

    2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。

    3、session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。

    4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

    5、建议:
    将登陆信息等重要信息存放为SESSION
    其他信息如果需要保留,可以放在COOKIE中

    5.创建一个简单tcp服务器需要的流程

    1.socket创建一个套接字

    2.bind绑定ip和port

    3.listen使套接字变为可以被动链接

    4.accept等待客户端的链接

    5.recv/send接收发送数据

    img

    你是最棒的!

    爬虫和数据库部分

    img

    1.scrapy和scrapy-redis有什么区别?为什么选择redis数据库?

    1. scrapy是一个Python爬虫框架,爬取效率极高,具有高度定制性,但是不支持分布式。而scrapy-redis一套基于redis数据库、运行在scrapy框架之上的组件,可以让scrapy支持分布式策略,Slaver端共享Master端redis数据库里的item队列、请求队列和请求指纹集合。

    2. 为什么选择redis数据库,因为redis支持主从同步,而且数据都是缓存在内存中的,所以基于redis的分布式爬虫,对请求和数据的高频读取效率非常高。

    \2. 你用过的爬虫框架或者模块有哪些?谈谈他们的区别或者优缺点?

    Python自带:urllib,urllib2

    第 三 方:requests

    框 架:Scrapy

    urllib和urllib2模块都做与请求URL相关的操作,但他们提供不同的功能。

    urllib2.:urllib2.urlopen可以接受一个Request对象或者url,(在接受Request对象时候,并以此可以来设置一个URL 的headers),urllib.urlopen只接收一个url

    urllib 有urlencode,urllib2没有,因此总是urllib,urllib2常会一起使用的原因

    scrapy是封装起来的框架,他包含了下载器,解析器,日志及异常处理,基于多线程, twisted的方式处理,对于固定单个网站的爬取开发,有优势,但是对于多网站爬取 100个网站,并发及分布式处理方面,不够灵活,不便调整与括展。

    request 是一个HTTP库, 它只是用来,进行请求,对于HTTP请求,他是一个强大的库,下载,解析全部自己处理,灵活性更高,高并发与分布式部署也非常灵活,对于功能可以更好实现.

    Scrapy优缺点:

    **优点:**scrapy 是异步的

    采取可读性更强的xpath代替正则

    强大的统计和log系统

    同时在不同的url上爬行

    支持shell方式,方便独立调试

    写middleware,方便写一些统一的过滤器

    通过管道的方式存入数据库

    **缺点:**基于python的爬虫框架,扩展性比较差

    基于twisted框架,运行中的exception是不会干掉reactor,并且异步框架出错后是不会停掉其他任务的,数据出错后难以察觉。

    3.你常用的mysql引擎有哪些?各引擎间有什么区别?

    主要 MyISAM 与 InnoDB 两个引擎,其主要区别如下:

    一、InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高

    级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM

    就不可以了;

    二、MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到

    安全性较高的应用;

    三、InnoDB 支持外键,MyISAM 不支持;

    四、MyISAM 是默认引擎,InnoDB 需要指定;

    五、InnoDB 不支持 FULLTEXT 类型的索引;

    六、InnoDB 中不保存表的行数,如 select count(*) from table 时,InnoDB;需要

    扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即

    可。注意的是,当 count(*)语句包含 where 条件时 MyISAM 也需要扫描整个表;

    七、对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM

    表中可以和其他字段一起建立联合索引;

    八、清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重

    建表;

    九、InnoDB 支持行锁(某些情况下还是锁整表,如 update table set a=1 where

    user like ‘%lee%’

    4.描述下scrapy框架运行的机制?

    从start_urls里获取第一批url并发送请求,请求由引擎交给调度器入请求队列,获取完毕后,调度器将请求队列里的请求交给下载器去获取请求对应的响应资源,并将响应交给自己编写的解析方法做提取处理:1. 如果提取出需要的数据,则交给管道文件处理;2. 如果提取出url,则继续执行之前的步骤(发送url请求,并由引擎将请求交给调度器入队列…),直到请求队列里没有请求,程序结束。

    5.什么是关联查询,有哪些?

    将多个表联合起来进行查询,主要有内连接、左连接、右连接、全连接(外连接)

    6.写爬虫是用多进程好?还是多线程好? 为什么?

    IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。在实际的数据采集过程中,既考虑网速和响应的问题,也需要考虑自身机器的硬件情况,来设置多进程或多线程

    7.数据库的优化?

    \1. 优化索引、SQL 语句、分析慢查询;

    \2. 设计表的时候严格根据数据库的设计范式来设计数据库;

    \3. 使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能

    节约磁盘IO;

    \4. 优化硬件;采用SSD,使用磁盘队列技术(RAID0,RAID1,RDID5)等;

    \5. 采用MySQL 内部自带的表分区技术,把数据分层不同的文件,能够提高磁

    盘的读取效率;

    \6. 垂直分表;把一些不经常读的数据放在一张表里,节约磁盘I/O;

    \7. 主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来;

    \8. 分库分表分机器(数据量特别大),主要的的原理就是数据路由;

    \9. 选择合适的表引擎,参数上的优化;

    \10. 进行架构级别的缓存,静态化和分布式;

    \11. 不采用全文索引;

    \12. 采用更快的存储方式,例如 NoSQL存储经常访问的数据

    8.常见的反爬虫和应对方法?

    1).通过Headers反爬虫

    从用户请求的Headers反爬虫是最常见的反爬虫策略。很多网站都会对Headers的User-Agent进行检测,还有一部分网站会对Referer进行检测(一些资源网站的防盗链就是检测Referer)。如果遇到了这类反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值修改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或者添加Headers就能很好的绕过。

    2).基于用户行为反爬虫

    还有一部分网站是通过检测用户行为,例如同一IP短时间内多次访问同一页面,或者同一账户短时间内多次进行相同操作。

    大多数网站都是前一种情况,对于这种情况,使用IP代理就可以解决。可以专门写一个爬虫,爬取网上公开的代理ip,检测后全部保存起来。这样的代理ip爬虫经常会用到,最好自己准备一个。有了大量代理ip后可以每请求几次更换一个ip,这在requests或者urllib2中很容易做到,这样就能很容易的绕过第一种反爬虫。

    对于第二种情况,可以在每次请求后随机间隔几秒再进行下一次请求。有些有逻辑漏洞的网站,可以通过请求几次,退出登录,重新登录,继续请求来绕过同一账号短时间内不能多次进行相同请求的限制。

    3).动态页面的反爬虫

    上述的几种情况大多都是出现在静态页面,还有一部分网站,我们需要爬取的数据是通过ajax请求得到,或者通过JavaScript生成的。首先用Fiddler对网络请求进行分析。如果能够找到ajax请求,也能分析出具体的参数和响应的具体含义,我们就能采用上面的方法,直接利用requests或者urllib2模拟ajax请求,对响应的json进行分析得到需要的数据。

    能够直接模拟ajax请求获取数据固然是极好的,但是有些网站把ajax请求的所有参数全部加密了。我们根本没办法构造自己所需要的数据的请求。这种情况下就用selenium+phantomJS,调用浏览器内核,并利用phantomJS执行js来模拟人为操作以及触发页面中的js脚本。从填写表单到点击按钮再到滚动页面,全部都可以模拟,不考虑具体的请求和响应过程,只是完完整整的把人浏览页面获取数据的过程模拟一遍。

    用这套框架几乎能绕过大多数的反爬虫,因为它不是在伪装成浏览器来获取数据(上述的通过添加 Headers一定程度上就是为了伪装成浏览器),它本身就是浏览器,phantomJS就是一个没有界面的浏览器,只是操控这个浏览器的不是人。利selenium+phantomJS能干很多事情,例如识别点触式(12306)或者滑动式的验证码,对页面表单进行暴力破解等。

    9.分布式爬虫主要解决什么问题?

    1)ip

    2)带宽

    3)cpu

    4)io

    10.爬虫过程中验证码怎么处理?

    1.scrapy自带

    2.付费接口

    6.Python面试题搜集(六)

    110道Python面试题(上)

    1、一行代码实现1–100之和

    利用sum()函数求和

    img

    2、如何在一个函数内部修改全局变量

    函数内部global声明 修改全局变量

    img

    3、列出5个python标准库

    os:提供了不少与操作系统相关联的函数

    sys: 通常用于命令行参数

    re: 正则匹配

    math: 数学运算

    datetime:处理日期时间

    4、字典如何删除键和合并两个字典

    del和update方法

    img

    5、谈下python的GIL

    GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。

    多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大

    6、python实现列表去重的方法

    先通过集合去重,在转列表

    img

    **7、fun(*args,*kwargs)中的*args,*kwargs什么意思?

    img

    img

    8、python2和python3的range(100)的区别

    python2返回列表,python3返回迭代器,节约内存.

    9、一句话解释什么样的语言能够用装饰器?

    函数可以作为参数传递的语言,可以使用装饰器。

    10、python内建数据类型有哪些

    整型–int

    布尔型–bool

    字符串–str

    列表–list

    元组–tuple

    字典–dict

    11、简述面向对象中__new__和__init__区别

    __init__是初始化方法,创建对象后,就立刻被默认调用了,可接收参数,如图

    img

    1、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别。

    2、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例。

    3、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。

    4、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。

    img

    12、简述with方法打开处理文件帮我我们做了什么?

    img

    打开文件在进行读写的时候可能会出现一些异常状况,如果按照常规的f.open写法,我们需要try,except,finally,做异常判断,并且文件最终不管遇到什么情况,都要执行finally f.close()关闭文件,with方法帮我们实现了finally中f.close(当然还有其他自定义功能,有兴趣可以研究with方法源码)。

    13、列表[1,2,3,4,5],请使用map()函数输出[1,4,9,16,25],并使用列表推导式提取出大于10的数,最终输出[16,25]?

    map()函数第一个参数是fun,第二个参数是一般是list,第三个参数可以写list,也可以不写,根据需求。

    img

    14、python中生成随机整数、随机小数、0–1之间小数方法

    随机整数:random.randint(a,b),生成区间内的整数。

    随机小数:习惯用numpy库,利用np.random.randn(5)生成5个随机小数。

    0-1随机小数:random.random(),括号中不传参。

    img

    15、避免转义给字符串加哪个字母表示原始字符串?

    r , 表示需要原始字符串,不转义特殊字符。

    16、中国,用正则匹配出标签里面的内容(“中国”),其中class的类名是不确定的。

    img

    17、python中断言方法举例

    assert()方法,断言成功,则程序继续执行,断言失败,则程序报错。

    img

    18、数据表student有id,name,score,city字段,其中name中的名字可有重复,需要消除重复行,请写sql语句

    select distinct name from student

    19、10个Linux常用命令

    ls pwd cd touch rm mkdir tree cp mv cat more grep echo

    20、python2和python3区别?列举5个

    1、Python3 使用 print 必须要以小括号包裹打印内容,比如 print(‘hi’)

    Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,比如 print ‘hi’

    2、python2 range(1,10)返回列表,python3中返回迭代器,节约内存

    3、python2中使用ascii编码,python中使用utf-8编码

    4、python2中unicode表示字符串序列,str表示字节序列

    python3中str表示字符串序列,byte表示字节序列

    5、python2中为正常显示中文,引入coding声明,python3中不需要

    6、python2中是raw_input()函数,python3中是input()函数

    21、列出python中可变数据类型和不可变数据类型,并简述原理

    不可变数据类型:数值型、字符串型string和元组tuple不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址),如下图用id()方法可以打印对象的id。

    img

    可变数据类型:列表list和字典dict;允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。

    img

    22、s = “ajldjlajfdljfddd”,去重并从小到大排序输出"adfjl"

    set去重,去重转成list,利用sort方法排序,reeverse=False是从小到大排

    list是不 变数据类型,s.sort时候没有返回值,所以注释的代码写法不正确。

    img

    23、用lambda函数实现两个数相乘

    img

    24、字典根据键从小到大排序

    dic={“name”:“zs”,“age”:18,“city”:“深圳”,“tel”:“1362626627”}

    img

    25、利用collections库的Counter方法统计字符串每个单词出现的次数"kjalfj;ldsjafl;hdsllfdhg;lahfbl;hl;ahlf;h"

    img

    26、字符串a = “not 404 found 张三 99 深圳”,每个词中间是空格,用正则过滤掉英文和数字,最终输出"张三 深圳"

    img

    顺便贴上匹配小数的代码,虽然能匹配,但是健壮性有待进一步确认。

    img

    27、filter方法求出列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表。

    img

    28、列表推导式求列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    img

    29、正则re.complie作用

    re.compile是将正则表达式编译成一个对象,加快速度,并重复使用。

    30、a=(1,)b=(1),c=(“1”) 分别是什么类型的数据?

    img

    31、两个列表[1,5,7,9]和[2,2,6,8]合并为[1,2,2,3,6,7,8,9]

    extend可以将另一个集合中的元素逐一添加到列表中,区别于append整体添加。

    img

    32、用python删除文件和用linux命令删除文件方法

    python:os.remove(文件名)

    linux: rm 文件名

    33、log日志中,我们需要用时间戳记录error,warning等的发生时间,请用datetime模块打印当前时间戳 “2018-04-01 11:38:54”,顺便把星期的代码也贴上。

    img

    34、数据库优化查询方法

    外键、索引、联合查询、选择特定字段等等

    35、请列出你会的任意一种统计图(条形图、折线图等)绘制的开源库,第三方也行

    pychart、matplotlib

    36、写一段自定义异常代码

    自定义异常用raise抛出异常。

    img

    37、正则表达式匹配中,(.*)和(.*?)匹配区别?

    (.*)是贪婪匹配,会把满足正则的尽可能多的往后匹配

    (.*?)是非贪婪匹配,会把满足正则的尽可能少匹配

    img

    38、简述Django的orm

    ORM,全拼Object-Relation Mapping,意为对象-关系映射。实现了数据模型与数据库的解耦,通过简单的配置就可以轻松更换数据库,而不需要修改代码只需要面向对象编程,orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句,所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite…,如果数据库迁移,只需要更换Django的数据库引擎即可。

    img

    39、[[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]

    列表推导式的骚操作

    运行过程:for i in a ,每个i是【1,2】,【3,4】,【5,6】,for j in i,每个j就是1,2,3,4,5,6,合并后就是结果。

    img

    还有更骚的方法,将列表转成numpy矩阵,通过numpy的flatten()方法,代码永远是只有更骚,没有最骚

    img

    40、x=“abc”,y=“def”,z=[“d”,“e”,“f”],分别求出x.join(y)和x.join(z)返回的结果

    join()括号里面的是可迭代对象,x插入可迭代对象中间,形成字符串,结果一致,有没有突然感觉字符串的常见操作都不会玩了

    顺便建议大家学下os.path.join()方法,拼接路径经常用到,也用到了join,和字符串操作中的join有什么区别,该问题大家可以查阅相关文档。

    img

    41、举例说明异常模块中try except else finally的相关意义

    try…except…else没有捕获到异常,执行else语句。

    try…except…finally不管是否捕获到异常,都执行finally语句。

    img

    42、python中交换两个数值

    img

    43、举例说明zip()函数用法

    zip()函数在运算时,会以一个或多个序列(可迭代对象)做为参数,返回一个元组的列表。同时将这些序列中并排的元素配对。

    zip()参数可以接受任何类型的序列,同时也可以有两个以上的参数;当传入参数的长度不同时,zip能自动以最短序列长度为准进行截取,获得元组。

    img

    44、a=“张明 98分”,用re.sub,将98替换为100

    img

    45、写5条常用sql语句

    show databases;

    show tables;

    desc 表名;

    select * from 表名;

    delete from 表名 where id=5;

    update students set gender=0,hometown=“北京” where id=5

    46、a="hello"和b="你好"编码成bytes类型

    img

    47、[1,2,3]+[4,5,6]的结果是多少?

    两个列表相加,等价于extend。

    img

    48、提高python运行效率的方法

    1、使用生成器,因为可以节约大量内存

    2、循环代码优化,避免过多重复代码的执行

    3、核心模块用Cython PyPy等,提高效率

    4、多进程、多线程、协程

    5、多个if elif条件判断,可以把最有可能先发生的条件放到前面写,这样可以减少程序判断的次数,提高效率

    49、简述mysql和redis区别

    redis: 内存型非关系数据库,数据保存在内存中,速度快

    mysql:关系型数据库,数据保存在磁盘中,检索的话,会有一定的Io操作,访问速度相对慢

    50、遇到bug如何处理

    1、细节上的错误,通过print()打印,能执行到print()说明一般上面的代码没有问题,分段检测程序是否有问题,如果是js的话可以alert或console.log。

    2、如果涉及一些第三方框架,会去查官方文档或者一些技术博客。

    3、对于bug的管理与归类总结,一般测试将测试出的bug用teambin等bug管理工具进行记录,然后我们会一条一条进行修改,修改的过程也是理解业务逻辑和提高自己编程逻辑缜密性的方法,我也都会收藏做一些笔记记录。

    4、导包问题、城市定位多音字造成的显示错误问题。

    51、正则匹配,匹配日期2018-03-20

    url=‘https://sycm.taobao.com/bda/tradinganaly/overview/get_summary.json?dateRange=2018-03-20%7C2018-03-20&dateType=recent1&device=1&token=ff25b109b&_=1521595613462’

    仍有同学问正则,其实匹配并不难,提取一段特征语句,用(.*?)匹配即可。

    img

    52、list=[2,3,5,4,9,6],从小到大排序,不许用sort,输出[2,3,4,5,6,9]

    利用min()方法求出最小值,原列表删除最小值,新列表加入最小值,递归调用获取最小值的函数,反复操作。

    img

    53、写一个单列模式

    因为创建对象时__new__方法执行,并且必须return 返回实例化出来的对象所cls.__instance是否存在,不存在的话就创建对象,存在的话就返回该对象,来保证只有一个实例对象存在(单列),打印ID,值一样,说明对象同一个。

    img

    54、保留两位小数

    题目本身只有a="%.03f"%1.3335,让计算a的结果,为了扩充保留小数的思路,提供round方法(数值,保留位数)。

    img

    55、求三个方法打印结果

    fn(“one”,1)直接将键值对传给字典;

    fn(“two”,2)因为字典在内存中是可变数据类型,所以指向同一个地址,传了新的额参数后,会相当于给字典增加键值对;

    fn(“three”,3,{})因为传了一个新字典,所以不再是原先默认参数的字典。

    img

    来源网络,侵权删除返回搜狐,查看更多

    7.Python面试题搜集(七)

    史上最全python面试题详解(一)

    python基础题(53道题详解)

    1、简述解释型和编译型编程语言?

    概念:

    • 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,可直接运行这个程序。
    • 解释型语言:把做好的源程序翻译一句,然后执行一句,直至结束!

    区别:

    • 编译型语言,执行速度快、效率高;依赖编译器、跨平台性差些。如C、C++、Delphi、Pascal,Fortran。
    • 解释型语言,执行速度慢、效率低;依赖解释器、跨平台性好。如Java、Basic.

    2、Python解释器种类以及特点

    • CPython
      • c语言开发的 使用最广的解释器
    • IPython
      • 基于cpython之上的一个交互式计时器 交互方式增强 功能和cpython一样
    • PyPy
      • 目标是执行效率 采用JIT技术 对python代码进行动态编译,提高执行效率
    • JPython
      • 运行在Java上的解释器 直接把python代码编译成Java字节码执行
    • IronPython
      • 运行在微软 .NET 平台上的解释器,把python编译成. NET 的字节码

    3、python常见的PEP8规范

    • 每级缩进用4个空格
    • Python 3中不允许混合使用Tab和空格缩进。
    • 限制所有行的最大行宽为79字符。
    • 在核心Python发布的代码应该总是使用UTF-8(ASCII在Python 2)。
    • 推荐绝对路径导入,因为它们通常更可读

    4、通过代码实现如下进制转换:

    [复制代码](javascript:void(0)😉

    1 hex()
    2 转换一个整数对象为十六进制的字符串
    3 
    4 >>> hex(16)
    5 '0x10'
    6 >>> hex(18)
    7 '0x12'
    8 >>> hex(32)
    9 '0x20'
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    1 oct()
    2 转换一个整数对象为八进制的字符串
    3 
    4 >>> oct(8)
    5 '0o10'
    6 >>> oct(166)
    7 '0o246'
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    1 bin()
    2 转换一个整数对象为二进制字符串
    3 
    4 >>> bin(10)
    5 '0b1010'
    6 >>> bin(255)
    7 '0b11111111'
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

     1 chr()
     2 转换一个[0, 255]之间的整数为对应的ASCII字符
     3 
     4 >>> chr(65)
     5 'A'
     6 >>> chr(67)
     7 'C'
     8 >>> chr(90)
     9 'Z'
    10 >>> chr(97)
    11 'a'
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    1 ord()
    2 将一个ASCII字符转换为对应整数
    3 
    4 >>> ord('A')
    5 65
    6 >>> ord('z')
    7 122
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

     1 16进制转10进制
     2 >>> int('10', 16)
     3 16
     4 >>> int('0x10', 16)
     5 16
     6 
     7 8进制转10进制
     8 >>> int('0o10', 8)
     9 8
    10 >>> int('10', 8)
    11 8
    12 
    13 2进制转10进制
    14 >>> int('0b1010', 2)
    15 10
    16 >>> int('1010', 2)
    17 10
    

    [复制代码](javascript:void(0)😉

    5、python递归的最大层数

    [复制代码](javascript:void(0)😉

     1 import sys
     2 sys.setrecursionlimit(100000)
     3 
     4 def foo(n):
     5     print(n)
     6     n += 1
     7     foo(n)
     8         
     9 if __name__ == '__main__':
    10     foo(1)
    

    [复制代码](javascript:void(0)😉

    得到的最大数字在3925-3929之间浮动,这个是和计算机有关系的,不然也不会是一个浮动的数字了(数学逻辑讲求严谨)

    6、三元运算规则以及应用场景

    • ​ 三元运算符就是在赋值变量的时候,可以直接加判断,然后赋值
    • ​ 三元运算符的功能与’if…else’流程语句一致,它在一行中书写,代码非常精炼,执行效率更高
    • ​ 格式:[on_true] if [expression] else [on_false]
    • ​ res = 值1 if 条件 else 值2

    7、列举 Python2和Python3的区别

    • print

    • input

    • [复制代码](javascript:void(0)😉

       1 问题:如何获取编码方式的信息?
       2 获取目标bytes的编码方式
       3 这一情况可以通过chardet模块的detect()函数来获取信息,chardet是第三方库,可以通过pip来安装
       4 
       5 b是待检测的bytes变量
       6 
       7 import chardet
       8 print(chardet.detect(b))
       9 ######output####
      10  {'confidence': 1.0, 'encoding': 'ascii'}
      11 1
      12 2
      13 3
      14 4
      15 5
      16 confidence是指匹配程度,encoding是指可能的编码方式
      17 
      18 获取当前环境的编码方式 
      19 这一情况可以使用sys模块下的getdefaultencoding()函数来获取信息
      20 
      21 import sys
      22 print(sys.getdefaultencoding())
      23 
      24 ######## output#####
      25 utf-8
      

      [复制代码](javascript:void(0)😉

    • 问题在控制台上看到的到底是什么

    [复制代码](javascript:void(0)😉

     1 写上面的东西的时候产生了一个疑问,现在已经知道Python内部存储str的方式是使用unicode字符集,但是我们在屏幕上看到的并不是unicode字符集
     3 s = "你好"
     4 print(s)
     6 #########output#############
     7 你好
    13 s的 unicode 是 \u4f60\u597d
    14 1
    15 那么,这中间应该是进行了某种转换 
    16 实际上,在执行print(str)的时候,python内部执行了encoding操作,控制台拿到的其实是一个bytes变量 
    17 之后,控制台又根据环境内部的编码方式,将所得到的bytes内容进行decoding的操作,就显示了原先str的内容
    

    [复制代码](javascript:void(0)😉

    • 打开文件不再支持 file 方法,只能用 open
    • range不再返回列表,而是一个可迭代的range对象
    • 除法 / 不再是整除,而是得到浮点数,整除需要用双斜杠 //
    • urllib和urllib2合并成了urllib,常用的urllib2.urlopen()变成了urllib.request.urlopen()
    • 字符串及编码相关有大变动,简单来说就是原来的str变成了新的bytes,原来的unicode变成了新的str。

    8、xrange和range的区别

    python2中 xrange 用法与 range 完全相同,所不同的是生成的不是一个list对象,而是一个生成器。

    9、python的read() 、readline()、readlines()、xreadlines()

    • read()会读取整个文件,将读取到底的文件内容放到一个字符串变量,返回str类型。
    • readline()读取一行内容,放到一个字符串变量,返回str类型。
    • readlines() 读取文件所有内容,按行为单位放到一个列表中,返回list类型。
    • xreadlines()返回一个生成器,来循环操作文件的每一行。

    10、列举布尔值为False的常见值

    None、""、0、[]、()、{}

    11、字符串、列表、元组、字典每个常用的5个方法(整型,浮点,字符串,布尔型,列表、元组、字典、集合、日期)

    字符串:

    [复制代码](javascript:void(0)😉

    # encoding:utf-8
    __author__ = 'Fioman'
    __date__ = '2018/11/19 15:10'
    
    # 1. 去掉空格和特殊符号
    name = " abcdefgeyameng  "
    name1 = name.strip()  # 并不会在原来的字符串上操作,返回一个去除了两边空白的字符串
    print(name1, len(name1), name, len(name))
    # abcdefgeyameng 14  abcdefgeyameng   17
    
    # 去掉左边的空格和换行符
    name2 = name.lstrip()
    print(name2, len(name2))# print(name2, len(name2))#
    
    # 去掉右边的空格和换行符
    name3 = name.rstrip()
    print(name3, len(name3)) # abcdefgeyameng 15
    
    
    # 2.字符串的搜索和替换
    name.count('e')  # 查找某个字符在字符串中出现的次数
    name.capitalize() # 首字母大写
    name.center(100,'-') # 把字符串方中间,两边用-补齐,100表示占位多少
    name.find('a') # 找到这个字符返回下标,多个时返回第一个,不存在时返回-1
    name.index('a') # 找到这个字符返回下标,多个时返回第一个,不存在时报错
    print(name.replace(name,'123')) # 字符串的替换
    name.replace('abc','123') # 注意字符串的替换的话,不是在原来的字符串上进行替换.而是返回一个替换后的字符串.
    
    # 3.字符串的测试和替换函数
    name.startswith("abc") # 是否以abc开头
    name.endswith("def") # 是否以def结尾
    name.isalnum() # 是否全是字母和数字,并且至少包含一个字符
    name.isalpha() # 是否全是字母,并至少包含一个字符
    name.isdigit() # 是否全是数字,并且至少包含一个字符
    name.isspace() # 是否全是空白字符,并且至少包含一个字符
    name.islower() # 是否全是小写
    name.isupper() # 是否全是大写
    name.istitle() # 是否是首字母大写
    
    # 4.字符串的分割
    name.split('') # 默认按照空格进行分隔,从前往后分隔
    name.rsplit() # 从后往前进行分隔
    
    # 5.连接字符串
    '.'.join(name) # 用.号将一个可迭代的序列拼接起来
    
    name = 'geyameng'
    # 6.截取字符串(切片)
    name1 = name[0:3] # 第一位到第三位的字符,和range一样不包含结尾索引
    name2 = name[:] # 截取全部的字符
    name3 = name[6:] # 截取第6个字符到结尾
    name4 = name[:-3] # 截取从开头到最后一个字符之前
    name5 = name[-1] # 截取最后一个字符
    name6 = name[::-1] # 创造一个与原字符串顺序相反的字符串
    name7 = name[:-5:-1] # 逆序截取
    

    [复制代码](javascript:void(0)😉

    列表:

    [复制代码](javascript:void(0)😉

    # encoding:utf-8
    __author__ = 'Fioman'
    __date__ = '2018/11/19 16:26'
    
    # 1.创建一个列表
    list1 = ['1', '2', '3', '4']
    list2 = list("1234")
    print(list1, list2)
    print(list1 == list2)
    # 以上创建的两个列表是等价的,都是['1', '2', '3', '4']
    
    # 2.添加新元素
    # 末尾追加
    a = [1, 2, 3, 4, 5]
    a.append(6)
    print(a)
    
    # 指定位置的前面插入一个元素
    a.insert(2, 100)  # 在下标为2的前面插入一个元素100
    print(a)
    
    # 扩展列表list.extend(iterable),在一个列表上追加一个列表
    a.extend([10, 11, 12])
    print(a)
    
    # 3.遍历列表
    # 直接遍历
    for i in a:
        print(i)
    
    # 带索引的遍历列表
    for index, i in enumerate(a):
        print(i, index)
    
    # 4.访问列表中的值,直接通过下标取值.list[index]
    print(a[2])
    
    # 从list删除元素
    # List.remove() 删除方式1:参数object 如果重复元素,只会删除最靠前的.
    a = [1,2,3]
    a.remove(2) # 返回值是None
    
    # List.pop()  删除方式2:pop 可选参数index,删除指定位置的元素 默认为最后一个元素
    a = [1,2,3,4,5]
    a.pop()
    print(a)
    
    a.pop(2)
    print(a)
    
    # 终极删除,可以删除列表或指定元素或者列表切片,list删除后无法访问
    a = [1,2,3,4,5,6]
    del  a[1]
    print(a) # 1, 3, 4, 5, 6]
    
    del a[1:]
    print(a) # 1
    
    del a
    # print(a) # 出错,name a is not defined
    
    
    # 排序和反转代码
    # reverse 反转列表
    a = [1,2,3,4,5]
    a.reverse()
    print(a)
    
    # sort 对列表进行排序,默认升序排列.有三个默认参数cmp = None,key = None,reverse = False
    
    # 7.Python的列表的截取与字符串操作类型相同,如下所示
    L = ['spam','Spam','SPAM!']
    print(L[-1]) # ['SPAM']
    
    # 8.Python列表操作的函数和方法
    len(a)  # 列表元素的个数
    max(a)  # 返回列表元素最大值
    min(a)  # 返回列表元素最小值
    list(tuple) #将一个可迭代对象转换为列表
    
    # 列表常用方法总结
    a.append(4)
    a.count(1)
    a.extend([4,5,6])
    a.index(3)
    a.insert(0,2)
    a.remove()
    a.pop()
    a.reverse()
    a.sort()
    

    [复制代码](javascript:void(0)😉

    元组:

    1.用一个可迭代对象生成元组
        T = tuple('abc')
    

    [复制代码](javascript:void(0)😉

    对元组进行排序
    注意
    当对元组进行排序的时候,通常先得将它转换为列表并使得它成为一个可变对象.或者使用sorted方法,它接收任何序列对象.
    
    T = ('c','a','d','b')
    tmp = list(T)
    tmp.sort()  ==> ['a','b','c','d']
    T = tunple(tmp)
    sorted(T)
    

    [复制代码](javascript:void(0)😉

    字典:

    [复制代码](javascript:void(0)😉

    以下实例展示了 fromkeys()函数的使用方法:
    
    实例(Python 2.0+)
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    seq = ('Google', 'Runoob', 'Taobao')
    dict = dict.fromkeys(seq)
    print "新字典为 : %s" % str(dict)
    dict = dict.fromkeys(seq, 10)
    print "新字典为 : %s" % str(dict)
    以上实例输出结果为:
    
    新字典为 : {'Google': None, 'Taobao': None, 'Runoob': None}
    新字典为 : {'Google': 10, 'Taobao': 10, 'Runoob': 10}
    

    [复制代码](javascript:void(0)😉

    通过zip函数构建字典
    D = dict(zip(keyslist,valueslist))
    通过赋值表达式元组构造字典(键必须是字符串,因为如果不是字符串,构造的时候也会当成是字符串处理)
    D = dict(name='Bob',age=42)  ==> {'name':'Bob,'age':42}
    列出所有的键,值.注意得到的是一个可迭代对象,而不是列表.用的时候需要转换
    D.keys()    
    D.values()  
    D.items()  --> 键 + 值
    删除字典(根据键)以及长度
    D.pop(key)    
    len(D) 
    del D[key]
    新增或者是修改键对应的值
    D[key] = value  # 如果key已经存在则修改,如果不存在就创建.
    字典推导式
    D = [x:x**2 for x in range(10) if x %2 == 0]
    

    12、lambda表达式格式以及应用场景

    1、lambda函数与list的结合使用

    [复制代码](javascript:void(0)😉

    list = lambda:x for x in range(10)
    print (list[0])
    >>>9
    
    list = lambda x:x for x in range(10)
    print (list[0])
    >>>0
    

    [复制代码](javascript:void(0)😉

    2、map,filter,reduce函数

    [复制代码](javascript:void(0)😉

    例子:
    a = [('a',1),('b',2),('c',3),('d',4)]
    a_1 = list(map(lambda x:x[0],a))
    如上例子,map函数第一个参数是一个lambda表达式,输入一个对象,返回该对象的第一个元素。第二个就是需要作用的对象,此处是一个列表。Python3中map返回一个map对象,我们需要人工转为list,得到的结果就是[‘a’,’b’,’c’,’d’] 
    例子:
    a = [1,2,3,4]
    b = [2,3,4,5]
    a_1 = list(map(lambda x,y:x+y,a,b))
    上边这个例子是为了说明,lambda表达式参数可以是多个。返回结果是[3,5,7,9]
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    例子:
    a = [1,2,3,4,5,6,7]
    a_1 = filter(lambda x:x<4,a)
    如上例子,定义lambda表达式,筛选a列表中小于4的元素,结果为[1,2,3]。filter函数直接返回一个列表,无需再进行转换,第三个是初始值,我们没给初始值,那么开始操作的两个元素就是序列的前两个。否则将使用我们给出的初始值和序列第一个元素操作,然后结果再与第三个元素操作,以此类推。上个例子结果是28
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    例子:
    from functools import reduce #python3需要导入此模块
    a = [1,2,3,4,5,6,7]
    a_1 = reduce(lambda x,y:x+y,a)
    reduce中使用的lambda表达式需要两个参数,reduce函数共三个参数,
    第一个是就是lambda表达式,第二个是要累计的序列,第三个是初始值,
    我们没给初始值,那么开始操作的两个元素就是序列的前两个。否则将使
    用我们给出的初始值和序列第一个元素操作,然后结果再与第三个元素操
    作,以此类推。上个例子结果是28
    

    [复制代码](javascript:void(0)😉

    3、字典多条件排序

    [复制代码](javascript:void(0)😉

    例子:
    dict = {'a':1,'b':2,'c':3,'d':4,'e':3,'f':1,'g':7}
    sorted_dict_asc = sorted(dict.items(),key=lambda item:item[0])
    sorted_dict_dsc = sorted(dict.items(),key=lambda item:item[0],reverse=True)
    
    输出(第一个升序,第二个降序):
    [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 3), ('f', 1), ('g', 7)]
    [('g', 7), ('f', 1), ('e', 3), ('d', 4), ('c', 3), ('b', 2), ('a', 1)]]
    

    [复制代码](javascript:void(0)😉

    13、pass的作用

    pass是空语句占位符,是为了保持程序结构的完整性。

    14、*arg和**kwarg作用

    [复制代码](javascript:void(0)😉

    定义函数时,使用*arg和**kwarg
    *arg和**kwarg 可以帮助我们处理上面这种情况,允许我们在调用函数的时候传入多个实参
    def exmaple2(required_arg, *arg, **kwarg):
        if arg:
            print "arg: ", arg
    
        if kwarg:
            print "kwarg: ", kwarg
    
    exmaple2("Hi", 1, 2, 3, keyword1 = "bar", keyword2 = "foo")
    >> arg:  (1, 2, 3)
    >> kwarg:  {'keyword2': 'foo', 'keyword1': 'bar'}
    从上面的例子可以看到,当我传入了更多实参的时候
    *arg会把多出来的位置参数转化为tuple
    **kwarg会把关键字参数转化为dict
    

    [复制代码](javascript:void(0)😉

    15、is和==的区别

    • Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。
    • ==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等
    • is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。

    只有数值型和字符串型的情况下,a is b才为True,当a和b是tuple,list,dict或set型时,a is b为False。

    16、简述Python的深浅拷贝以及应用场景

    深浅拷贝用法来自copy模块。

    导入模块:import copy

    浅拷贝:copy.copy

    深拷贝:copy.deepcopy

    对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。

    字面理解:浅拷贝指仅仅拷贝数据集合的第一层数据,深拷贝指拷贝数据集合的所有层。所以对于只有一层的数据集合来说深浅拷贝的意义是一样的,比如字符串,数字,还有仅仅一层的字典、列表、元祖等.

    字典(列表)的深浅拷贝

    赋值:

    import copy
    n1 = {'k1':'wu','k2':123,'k3':['alex',678]}
    n2 = n1
    

    img

    浅拷贝:

    import copy
    n1 = {'k1':'wu','k2':123,'k3':['alex',678]}
    n3 = copy.copy(n1)
    

    img

    深拷贝:

    import copy
    n1 = {'k1':'wu','k2':123,'k3':['alex',678]}
    n4 = copy.deepcopy(n1)
    

    img

    深拷贝的时候python将字典的所有数据在内存中新建了一份,所以如果你修改新的模版的时候老模版不会变。相反,在浅copy 的时候,python仅仅将最外层的内容在内存中新建了一份出来,字典第二层的列表并没有在内存中新建,所以你修改了新模版,默认模版也被修改了。

    17、Python是如何进行内存管理的

    答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制

    一、对象的引用计数机制

    Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。

    引用计数增加的情况:

    1,一个对象分配一个新名称

    2,将其放入一个容器中(如列表、元组或字典)

    引用计数减少的情况:

    1,使用del语句对对象别名显示的销毁

    2,引用超出作用域或被重新赋值

    Sys.getrefcount( )函数可以获得对象的当前引用计数

    多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。

    二、垃圾回收

    1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

    2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

    三、内存池机制

    Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

    1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

    2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。

    3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

    18、Python的可变类型和不可变类型

    • 数字、字符串、元组是不可变的,列表、字典是可变的。

    对象池:

    小整数对象池
    [-5, 256] 这些小整数被定义在了一个整数对象池里,当引用小整数时会自动引用整数对象池里的对象,所以这些小整数不会重复创建,当多个变量指向同一个小整数时,实质上它们指向的是同一个对象。

    字符串对象池
    字符串对象是不可变对象,python有个intern机制,简单说就是维护一个字典,这个字典维护已经创建字符串(key)和它的字符串对象的地址(value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了。intern机制处理字符串长度小于等于20且仅由数字字母下划线构成的,只创建一次。

    19、列举常见的内置函数

    数学相关

    • abs(a) : 求取绝对值。abs(-1)
    • max(list) : 求取list最大值。max([1,2,3])
    • min(list) : 求取list最小值。min([1,2,3])
    • sum(list) : 求取list元素的和。 sum([1,2,3]) >>> 6
    • sorted(list) : 排序,返回排序后的list。
    • len(list) : list长度,len([1,2,3])
    • divmod(a,b): 获取商和余数。 divmod(5,2) >>> (2,1)
    • pow(a,b) : 获取乘方数。pow(2,3) >>> 8
    • round(a,b) : 获取指定位数的小数。a代表浮点数,b代表要保留的位数。round(3.1415926,2) >>> 3.14
    • range(a[,b]) : 生成一个a到b的数组,左闭右开。 range(1,10) >>> [1,2,3,4,5,6,7,8,9]

    类型转换

    • int(str) : 转换为int型。int(‘1’) >>> 1
    • float(int/str) : 将int型或字符型转换为浮点型。float(‘1’) >>> 1.0
    • str(int) : 转换为字符型。str(1) >>> ‘1’
    • bool(int) : 转换为布尔类型。 str(0) >>> False str(None) >>> False
    • bytes(str,code) : 接收一个字符串,与所要编码的格式,返回一个字节流类型。bytes(‘abc’, ‘utf-8’) >>> b’abc’ bytes(u’爬虫’, ‘utf-8’) >>> b’\xe7\x88\xac\xe8\x99\xab’
    • list(iterable) : 转换为list。 list((1,2,3)) >>> [1,2,3]
    • iter(iterable): 返回一个可迭代的对象。 iter([1,2,3]) >>> <list_iterator object at 0x0000000003813B00>
    • dict(iterable) : 转换为dict。 dict([(‘a’, 1), (‘b’, 2), (‘c’, 3)]) >>> {‘a’:1, ‘b’:2, ‘c’:3}
    • enumerate(iterable) : 返回一个枚举对象。
    • tuple(iterable) : 转换为tuple。 tuple([1,2,3]) >>>(1,2,3)
    • set(iterable) : 转换为set。 set([1,4,2,4,3,5]) >>> {1,2,3,4,5} set({1:‘a’,2:‘b’,3:‘c’}) >>> {1,2,3}
    • hex(int) : 转换为16进制。hex(1024) >>> ‘0x400’
    • oct(int) : 转换为8进制。 oct(1024) >>> ‘0o2000’
    • bin(int) : 转换为2进制。 bin(1024) >>> ‘0b10000000000’
    • chr(int) : 转换数字为相应ASCI码字符。 chr(65) >>> ‘A’
    • ord(str) : 转换ASCI字符为相应的数字。 ord(‘A’) >>> 65

    相关操作

    • eval() : 执行一个表达式,或字符串作为运算。 eval(‘1+1’) >>> 2
    • exec() : 执行python语句。 exec(‘print(“Python”)’) >>> Python
    • filter(func, iterable) : 通过判断函数fun,筛选符合条件的元素。 filter(lambda x: x>3, [1,2,3,4,5,6]) >>> <filter object at 0x0000000003813828>
    • map(func, *iterable) : 将func用于每个iterable对象。 map(lambda a,b: a+b, [1,2,3,4], [5,6,7]) >>> [6,8,10]
    • zip(*iterable) : 将iterable分组合并。返回一个zip对象。 list(zip([1,2,3],[4,5,6])) >>> [(1, 4), (2, 5), (3, 6)]
    • type():返回一个对象的类型。
    • id(): 返回一个对象的唯一标识值。
    • hash(object):返回一个对象的hash值,具有相同值的object具有相同的hash值。 hash(‘python’) >>> 7070808359261009780
    • help():调用系统内置的帮助系统。
    • isinstance():判断一个对象是否为该类的一个实例。
    • issubclass():判断一个类是否为另一个类的子类。
    • globals() : 返回当前全局变量的字典。
    • next(iterator[, default]) : 接收一个迭代器,返回迭代器中的数值,如果设置了default,则当迭代器中的元素遍历后,输出default内容。
    • reversed(sequence) : 生成一个反转序列的迭代器。 reversed(‘abc’) >>> [‘c’,‘b’,‘a’]

    20、Python写9*9乘法表的两种简单方法

    1 for i in range(1,10):
    2     for j in range(1,i+1):
    3         print("%s * %s = %s" %(j,i,i*j),end="")
    4     print("")
    print "\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y in range(1, x+1)]) for x in range(1, 10))
    

    21、如何安装第三方模块?以及用过哪些第三方模块?

    pip install 模块名

    一、Python爬虫

    \1. 请求

    requests(第三方模块)

    \2. 解析:

    bs4(即beautifulsoup,第三方模块)

    \3. 储存:

    pymongo(第三方模块):[

    ](https://link.zhihu.com/?target=https%3A//api.mongodb.com/python/current/)

    把数据写入MongoDB

    MySQL-python(第三方模块):

    把数据写入MySQL里面。

    协程:gevent(第三方模块)

    二、Python数据分析&科学计算

    numpy(第三方模块,C拓展):[

    ](https://link.zhihu.com/?target=http%3A//www.numpy.org/)

    Copy了MATLAB的数据结构。很多数据分析和科学计算库的底层模块。提供了良好的数组数据结构和C拓展接口。

    pandas(第三方模块,C拓展):[

    ](https://link.zhihu.com/?target=http%3A//pandas.pydata.org/)

    Copy了R的data frame的数据结构。

    22、常用模块都有那些?

    [复制代码](javascript:void(0)😉

     1 import time
     2 import datetime
     3 
     4 print(time.asctime())      # 返回时间格式:Sun May  7 21:46:15 2017
     5 print(time.time())         # 返回时间戳 ‘1494164954.6677325’
     6 print(time.gmtime())       # 返回本地时间 的struct time对象格式,time.struct_time(tm_year=2017, tm_mon=5, tm_mday=7, tm_hour=22, tm_min=4, tm_sec=53, tm_wday=6, tm_yday=127, tm_isdst=0)
     7 print(time.localtime())    # 返回本地时间 的struct time对象格式,time.struct_time(tm_year=2017, tm_mon=5, tm_mday=7, tm_hour=22, tm_min=4, tm_sec=53, tm_wday=6, tm_yday=127, tm_isdst=0)
     8 print(time.gmtime(time.time()-800000))   # 返回utc时间的struc时间对象格式
     9 print(time.asctime(time.localtime()))    # 返回时间格式Sun May  7 22:15:09 2017
    10 print(time.ctime())                      # 返回时间格式Sun May  7 22:15:09 2017
    11 print(time.strftime('%Y-%m-%d'))         #默认当前时间 2017-05-07
    12 print(time.strftime('%Y-%m-%d',time.localtime())) #默认当前时间 2017-05-07
    13 
    14 string_struct = time.strptime("2016/05/22","%Y/%m/%d") # 将日期字符串 转成 struct时间对象格式
    15 print(string_struct)                     # 返回struct time对象格式 time.struct_time(tm_year=2016, tm_mon=5, tm_mday=22, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=143, tm_isdst=-1)
    16 
    17 # 将日期字符串转成时间戳
    18 struct_stamp = time.mktime(string_struct) # 将struct time时间对象转成时间戳
    19 print(struct_stamp)                         # 返回时间戳 ‘1463846400.0’
    20 
    21 # 将时间戳转为字符串格式
    22 print(time.gmtime(time.time()-86640))         # 将utc时间戳转换成struct_time格式
    23 print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) # 将utc struct_time格式转成指定的字符串格式
    24 
    25 
    26 # 时间加减
    27 print(datetime.datetime.now())           # 返回当前时间 2017-05-07 22:36:45.179732
    28 print(datetime.date.fromtimestamp(time.time()))  # 时间戳直接转换成日期格式 2017-05-07
    29 print(datetime.datetime.now() + datetime.timedelta(3))    # 返回时间在当前日期上 +3 天
    30 print(datetime.datetime.now() + datetime.timedelta(-3))    # 返回时间在当前日期上 -3 天
    31 print(datetime.datetime.now() + datetime.timedelta(hours= 3)) # 返回时间在当前时间上 +3 小时
    32 print(datetime.datetime.now() + datetime.timedelta(minutes= 30)) # 返回时间在当前时间上 +30 分钟
    33 
    34 c_time  = datetime.datetime.now()
    35 print(c_time)                          # 当前时间为 2017-05-07 22:52:44.016732
    36 print(c_time.replace(minute=3,hour=2)) # 时间替换 替换时间为‘2017-05-07 02:03:18.181732’
    37 
    38 print(datetime.timedelta)      # 表示时间间隔,即两个时间点之间的长度
    39 print (datetime.datetime.now() - datetime.timedelta(days=5))  # 返回时间在当前时间上 -5 天
    40 
    41 # python 日历模块
    42 import calendar
    43 
    44 print(calendar.calendar(theyear= 2017))     # 返回2017年整年日历
    45 print(calendar.month(2017,5))               # 返回某年某月的日历,返回类型为字符串类型
    46 
    47 calendar.setfirstweekday(calendar.WEDNESDAY) # 设置日历的第一天(第一天以星期三开始)
    48 cal = calendar.month(2017, 4)
    49 print (cal)
    50 
    51 print(calendar.monthrange(2017,5))        # 返回某个月的第一天和这个月的所有天数
    52 print(calendar.monthcalendar(2017,5))     # 返回某个月以每一周为元素的序列
    53 
    54 cal = calendar.HTMLCalendar(calendar.MONDAY)
    55 print(cal.formatmonth(2017, 5))           # 在html中打印某年某月的日历
    56 
    57 print(calendar.isleap(2017))             # 判断是否为闰年
    58 print(calendar.leapdays(2000,2017))       # 判断两个年份间闰年的个数
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

     1 import random
     2 
     3 # 随机数
     4 print(random.random())              # 返回一个随机小数'0.4800545746046827'
     5 print(random.randint(1,5))          # 返回(1-5)随机整型数据
     6 print(random.randrange(1,10))       # 返回(1-10)随机数据
     7 
     8 # 生成随机验证码
     9 code = ''
    10 for i in range(4):
    11     current = random.randrange(0,4)
    12     if current != i:
    13         temp = chr(random.randint(65,90))
    14     else:
    15         temp = random.randint(0,9)
    16     code += str(temp)
    17 
    18 print(code)
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    import os
    
    print(os.getcwd())        # 获得当前工作目录
    print(os.chdir("dirname")) # 改变当前脚本的工作路径,相当于shell下的cd
    print(os.curdir)            # 返回当前目录‘.'
    print(os.pardir)            # 获取当前目录的父目录字符串名‘..'
    print(os.makedirs('dirname1/dirname2'))     # 可生成多层递归目录
    print(os.removedirs('dirname1/dirname2'))      # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
    print(os.mkdir('test4'))         # 生成单级目录;相当于shell中mkdir dirname
    print(os.rmdir('test4'))        # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
    print(os.listdir('/pythonStudy/s12/test'))   # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
    print(os.remove('log.log'))            # 删除一个指定的文件
    print(os.rename("oldname","newname"))    # 重命名文件/目录)
    print(os.stat('/pythonStudy/s12/test'))     # 获取文件/目录信息
    print(os.pathsep)            # 输出用于分割文件路径的字符串';'
    print(os.name)               # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
    print(os.system(command='bash'))   # 运行shell命令,直接显示
    print(os.environ)                  # 获得系统的环境变量
    print(os.path.abspath('/pythonStudy/s12/test'))   # 返回path规范化的绝对路径
    print(os.path.split('/pythonStudy/s12/test'))     # 将path分割成目录和文件名二元组返回
    print(os.path.dirname('/pythonStudy/s12/test'))    # 返回path的目录。其实就是os.path.split(path)的第一个元素
    print(os.path.basename('/pythonStudy/s12/test'))   # 返回path最后的文件名。如果path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
    print(os.path.exists('test'))                 # 判断path是否存在
    print(os.path.isabs('/pythonStudy/s12/test'))    # 如果path是绝对路径,返回True
    print(os.path.isfile('test'))                   # 如果path是一个存在的文件,返回True。否则返回False
    print(os.path.isdir('/pythonStudy/s12/test'))    # 如果path是一个存在的目录,则返回True。否则返回False
    print(os.path.getatime('/pythonStudy/s12/test'))   # 返回path所指向的文件或者目录的最后存取时间
    print(os.path.getmtime('/pythonStudy/s12/test'))   # 返回path所指向的文件或者目录的最后修改时间
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    import sys
    
    print(sys.argv)          # 命令行参数List,第一个元素是程序本身路径
    print(sys.exit(n))     # 退出程序,正常退出时exit(0)
    print(sys.version)       # 获取python的版本信息
    print(sys.path)          # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
    print(sys.platform)      # 返回操作平台的名称
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    # xml的格式如下,就是通过<>节点来区别数据结构的:
    import xml.etree.ElementTree as ET
    
    tree = ET.parse("xmltest.xml")
    root = tree.getroot()
    print(root.tag)
    
    #遍历xml文档
    for child in root:
        print(child.tag, child.attrib)
        for i in child:
            print(i.tag,i.text)
    
    #只遍历year 节点
    for node in root.iter('year'):
        print(node.tag,node.text)
    
    # 修改和删除xml文档内容
    import xml.etree.ElementTree as ET
    tree = ET.parse("xmltest.xml")
    root = tree.getroot()
    
    #修改
    for node in root.iter('year'):
        new_year = int(node.text) + 1
        node.text = str(new_year)
        node.set("updated","yes")
    tree.write("xmltest.xml")
    
    #删除node
    for country in root.findall('country'):
       rank = int(country.find('rank').text)
       if rank > 50:
           root.remove(country)
    tree.write('output.xml')
    
    # 自己创建xml文档
    import xml.etree.ElementTree as ET
    
    new_xml = ET.Element("namelist")
    name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
    age = ET.SubElement(name, "age", attrib={"checked": "no"})
    age = ET.SubElement(name, "age")
    age.text = '33'
    name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
    age = ET.SubElement(name2, "age")
    age.text = '19'
    et = ET.ElementTree(new_xml)  # 生成文档对象
    et.write("test.xml", encoding="utf-8", xml_declaration=True)
    ET.dump(new_xml)  # 打印生成的格式
    

    [复制代码](javascript:void(0)😉

    python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug(), info(), warning(), error() and critical() 5个级别。

    [复制代码](javascript:void(0)😉

    import logging
    
    # %(message)s 日志信息
    # %(levelno)s 日志级别
    # datefmt  设置时间格式
    # filename  设置日志保存的路径
    # level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,
    # 在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
    logging.basicConfig(format='%(asctime)s %(message)s %(levelno)s', datefmt='%m/%d/%Y %I:%M:%S %p',filename='example.log',level=logging.INFO)
    logging.debug('This message should go to the log file')
    logging.info('So should this')
    

    [复制代码](javascript:void(0)😉

    python面试题搜集(八):史上最全python面试题详解 (二)(附带详细答案(关注、持续更新))

    23、re的match和search区别?

    re.match()从开头开始匹配string。
    re.search()从anywhere 来匹配string。

    # 多行模式>>> re.match('X', 'A\nB\nX', re.MULTILINE)  # No match
    >>> re.search('^X', 'A\nB\nX', re.MULTILINE)  # Match
    <_sre.SRE_Match object at ...>
    

    24、什么是正则的贪婪匹配

    1 如:String str="abcaxc";
    2   Patter p="ab.*c";
    3   贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab.*c)。
    4   非贪婪匹配:就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab.*c)。
    

    25、def func(a,b=[]) 这种写法有什么坑?

    [复制代码](javascript:void(0)😉

    def func(a,b=[]):
        b.append(a)
        print(b)
    func(1)
    func(1)
    func(1)
    func(1)
    

    [复制代码](javascript:void(0)😉

    看下结果

    [1]
      [1, 1]
      [1, 1, 1]
      [1, 1, 1, 1]

    函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] ,想每次执行只输出[1] ,默认参数应该设置为None。

    26、如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?

    1 # encoding: utf-8
    2 a = "1,2,3"
    3 b = a.split(",")
    4 print b
    

    27、如何实现[‘1’,’2’,’3’]变成[1,2,3]?

    1 >>>a = ['1', '2', '3']
    2 >>>b = [int(i) for i in a]
    3 >>>b
    

    28、a = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ]的区别?

    a里面的元素都是int类型,b中的元素都是元组。

    元组只有一个元素,必须要加逗号结尾

    29、一行代码选出列表里面的不重复元素

    1 b = [1,2,3,2,3,4,1,2]
    2 print [i  for i in b if b.count(i)==1]
    3 >>>4
    

    30、logging模块的作用?以及应用场景

    日志是一种可以追踪某些软件运行时所发生事件的方法。

    不同的应用程序所定义的日志等级可能会有所差别,分的详细点的会包含以下几个等级:

    • DEBUG
    • INFO
    • NOTICE
    • WARNING
    • ERROR
    • CRITICAL
    • ALERT
    • EMERGENCY
    • img

    img

    31、请用代码简答实现stack

    [复制代码](javascript:void(0)😉

     1 stack的实现代码(使用python内置的list),实现起来是非常的简单,就是list的一些常用操作
     2 
     3 class Stack(object):
     4     def __init__(self):
     5         self.stack = []
     6 
     7     def push(self, value):    # 进栈
     8         self.stack.append(value)
     9 
    10     def pop(self):  #出栈
    11         if self.stack:
    12             self.stack.pop()
    13         else:
    14             raise LookupError(‘stack is empty!‘)
    15 
    16     def is_empty(self): # 如果栈为空
    17         return bool(self.stack)
    18 
    19     def top(self): 
    20         #取出目前stack中最新的元素
    21         return self.stack[-1]
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

     1 定义一个头结点,左边指向队列的开头,右边指向队列的末尾,这样就可以保证我们插入一个元素和取出一个元素都是O(1)的操作,使用这种链表实现stack也是非常的方便。实现代码如下:
     2 
     3 class Head(object):
     4     def __init__(self):
     5         self.left = None
     6         self.right = None
     7 
     8 class Node(object):
     9     def __init__(self, value):
    10         self.value = value
    11         self.next = None
    12 
    13 class Queue(object):
    14     def __init__(self):
    15         #初始化节点
    16         self.head = Head()
    17 
    18     def enqueue(self, value):
    19         #插入一个元素
    20         newnode = Node(value)
    21         p = self.head
    22         if p.right:
    23             #如果head节点的右边不为None
    24             #说明队列中已经有元素了
    25             #就执行下列的操作
    26             temp = p.right
    27             p.right = newnode
    28             temp.next = newnode
    29         else:
    30             #这说明队列为空,插入第一个元素
    31             p.right = newnode
    32             p.left = newnode
    33 
    34     def dequeue(self):
    35         #取出一个元素
    36         p = self.head
    37         if p.left and (p.left == p.right):
    38             #说明队列中已经有元素
    39             #但是这是最后一个元素
    40             temp = p.left
    41             p.left = p.right = None
    42             return temp.value
    43         elif p.left and (p.left != p.right):
    44             #说明队列中有元素,而且不止一个
    45             temp = p.left
    46             p.left = temp.next
    47             return temp.value
    48 
    49         else:
    50             #说明队列为空
    51             #抛出查询错误
    52             raise LookupError(‘queue is empty!‘)
    53 
    54     def is_empty(self):
    55         if self.head.left:
    56             return False
    57         else:
    58             return True
    59 
    60     def top(self):
    61         #查询目前队列中最早入队的元素
    62         if self.head.left:
    63             return self.head.left.value
    64         else:
    65             raise LookupError(‘queue is empty!‘)
    

    [复制代码](javascript:void(0)😉

    32、常用字符串格式化哪几种?

    [复制代码](javascript:void(0)😉

     1 一、使用%
     2 %s     字符串
     3 %c     字符
     4 %d     十进制(整数)
     5 %i     整数
     6 %u    无符号整数
     7 %o     八进制整数
     8 %x    十六进制整数
     9 %X     十六进制整数大写
    10 %e     浮点数格式1 
    11 %E     浮点数格式2 
    12 %f     浮点数格式3 
    13 %g    浮点数格式4 
    14 %G    浮点数格式5 
    15 %%     文字% 
    16 >>> print("我叫%s,今年%d岁了" % ("小李", 20))
    17 我叫小李,今年20岁了
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    二、通过{}替代%
    1、正常使用
    >>> print("我叫{},今年{}岁了".format("小李", 20))
    我叫小李,今年20岁了
    2、还可以通过在括号里填写数字,修改格式化的顺序
    >>> print("我叫{1},今年{0}岁了".format("小李", 20))
    我叫20,今年小李岁了
    3、通过key取变量
    >>> print("我叫{name},今年{age}岁了".format(name="小李", age=20))
    我叫小李,今年20岁了
    4、传入对象
    >>> class Person:
    ...     def __init__(self,name,age):
    ...
    ...             self.name,self.age = name,age
    ...     def __str__(self):
    ...
    ...             return '我叫{self.name}, 今年{self.age}岁了'.format(self=self)
    >>> str(Person('小李',20))
    '我叫小李, 今年20岁了'
    5、通过下标
    >>> person=['小李',20]
    >>> '我叫{0[0]}, 今年{0[1]}岁了'.format(person)
    '我叫小李, 今年20岁了'
    

    [复制代码](javascript:void(0)😉

    33、简述 生成器、迭代器、可迭代对象 以及应用场景?

    Python可迭代对象(Iterable)
    Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,像常见的list,tuple都是。如果给一个准确的定义的话,就是只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法(这些双下划线方法会在其他章节中全面解释),那么它就是一个可迭代对象。

    Python迭代器(iterator)
    迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义了这个方法的都算是迭代器。可以用通过下面例子来体验一下迭代器:

    生成器(Generators)
    生成器是构造迭代器的最简单有力的工具,与普通函数不同的只有在返回一个值的时候使用yield来替代return,然后yield会自动构建好next()iter()

    因为迭代器如此普遍,python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。

    [复制代码](javascript:void(0)😉

     1 1.3 定义迭代器 
     2 下面一个例子——斐波那契数列
     3 # -*- coding: cp936 -*-
     4 class Fabs(object):
     5     def __init__(self,max):
     6         self.max = max
     7         self.n, self.a, self.b = 0, 0, 1  #特别指出:第0项是0,第1项是第一个1.整个数列从1开始
     8     def __iter__(self):
     9         return self
    10     def next(self):
    11         if self.n < self.max:
    12             r = self.b
    13             self.a, self.b = self.b, self.a + self.b
    14             self.n = self.n + 1
    15             return r
    16         raise StopIteration()
    17 
    18 print Fabs(5)
    19 for key in Fabs(5):
    20     print key
    21 
    22 结果
    23 <__main__.Fabs object at 0x01A63090>
    24 1
    25 1
    26 2
    27 3
    28 5
    

    [复制代码](javascript:void(0)😉

    34、用Python实现一个二分查找的函数

    [复制代码](javascript:void(0)😉

     1 #!usr/bin/env python  
     2 #encoding:utf-8  
     3 def binary_search(num_list, x):
     4     '''
     5     二分查找
     6     '''
     7     num_list=sorted(num_list)
     8     left, right = 0, len(num_list)
     9     while left < right:
    10         mid = (left + right) / 2
    11         if num_list[mid] > x:
    12             right = mid
    13         elif num_list[mid] < x:
    14             left = mid + 1
    15         else:
    16             return '待查元素{0}在列表中下标为:{1}'.format(x, mid)
    17     return  '待查找元素%s不存在指定列表中'%x
    18  
    19 if __name__ == '__main__':
    20     num_list = [34,6,78,9,23,56,177,33,2,6,30,99,83,21,17]
    21     print binary_search(num_list, 34)
    22     print binary_search(num_list, 177)
    23     print binary_search(num_list, 21)
    24     print binary_search(num_list, 211)
    25     print binary_search(num_list, 985)
    26 》》》
    27 待查元素34在列表中下标为:9
    28 待查元素177在列表中下标为:14
    29 待查元素21在列表中下标为:5
    30 待查找元素211不存在指定列表中
    31 待查找元素985不存在指定列表中
    

    [复制代码](javascript:void(0)😉

    35、谈谈你对闭包的理解。

    [复制代码](javascript:void(0)😉

     1 #闭包函数的实例
     2 # outer是外部函数 a和b都是外函数的临时变量
     3 def outer( a ):
     4     b = 10
     5     # inner是内函数
     6     def inner():
     7         #在内函数中 用到了外函数的临时变量
     8         print(a+b)
     9     # 外函数的返回值是内函数的引用
    10     return inner
    11 
    12 if __name__ == '__main__':
    13     # 在这里我们调用外函数传入参数5
    14     #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
    15     # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
    16     demo = outer(5)
    17     # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
    18     # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
    19     demo() # 15
    20 
    21     demo2 = outer(7)
    22     demo2()#17
    

    [复制代码](javascript:void(0)😉

    36、os和sys模块的作用

    os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;

    sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

    [复制代码](javascript:void(0)😉

     1 os 常用方法
     2 
     3 
     4 os.remove(‘path/filename’) 删除文件
     5 
     6 os.rename(oldname, newname) 重命名文件
     7 
     8 os.walk() 生成目录树下的所有文件名
     9 
    10 os.chdir('dirname') 改变目录
    11 
    12 os.mkdir/makedirs('dirname')创建目录/多层目录
    13 
    14 os.rmdir/removedirs('dirname') 删除目录/多层目录
    15 
    16 os.listdir('dirname') 列出指定目录的文件
    17 
    18 os.getcwd() 取得当前工作目录
    19 
    20 os.chmod() 改变目录权限
    21 
    22 os.path.basename(‘path/filename’) 去掉目录路径,返回文件名
    23 
    24 os.path.dirname(‘path/filename’) 去掉文件名,返回目录路径
    25 
    26 os.path.join(path1[,path2[,...]]) 将分离的各部分组合成一个路径名
    27 
    28 os.path.split('path') 返回( dirname(), basename())元组
    29 
    30 os.path.splitext() 返回 (filename, extension) 元组
    31 
    32 os.path.getatime\ctime\mtime 分别返回最近访问、创建、修改时间
    33 
    34 os.path.getsize() 返回文件大小
    35 
    36 os.path.exists() 是否存在
    37 
    38 os.path.isabs() 是否为绝对路径
    39 
    40 os.path.isdir() 是否为目录
    41 
    42 os.path.isfile() 是否为文件
    43 
    44 
    45 sys 常用方法
    46 
    47 
    48 sys.argv 命令行参数List,第一个元素是程序本身路径
    49 
    50 sys.modules.keys() 返回所有已经导入的模块列表
    51 
    52 sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
    53 
    54 sys.exit(n) 退出程序,正常退出时exit(0)
    55 
    56 sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0
    57 
    58 sys.version 获取Python解释程序的版本信息
    59 
    60 sys.maxint 最大的Int值
    61 
    62 sys.maxunicode 最大的Unicode值
    63 
    64 sys.modules 返回系统导入的模块字段,key是模块名,value是模块
    65 
    66 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
    67 
    68 sys.platform 返回操作系统平台名称
    69 
    70 sys.stdout 标准输出
    71 
    72 sys.stdin 标准输入
    73 
    74 sys.stderr 错误输出
    75 
    76 sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息
    77 
    78 sys.exec_prefix 返回平台独立的python文件安装的位置
    79 
    80 sys.byteorder 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'
    81 
    82 sys.copyright 记录python版权相关的东西
    83 
    84 sys.api_version 解释器的C的API版本
    

    [复制代码](javascript:void(0)😉

    37、谈谈你对面向对象的理解?

    [复制代码](javascript:void(0)😉

    在我理解,面向对象是向现实世界模型的自然延伸,这是一种“万物皆对象”的编程思想。在现实生活中的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。面向对象的编程是以对象为中心,以消息为驱动,所以程序=对象+消息。
    
    面向对象有三大特性,封装、继承和多态。
    
    封装就是将一类事物的属性和行为抽象成一个类,使其属性私有化,行为公开化,提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。
    
    继承则是进一步将一类事物共有的属性和行为抽象成一个父类,而每一个子类是一个特殊的父类--有父类的行为和属性,也有自己特有的行为和属性。这样做扩展了已存在的代码块,进一步提高了代码的复用性。
    
    如果说封装和继承是为了使代码重用,那么多态则是为了实现接口重用。多态的一大作用就是为了解耦--为了解除父子类继承的耦合度。如果说继承中父子类的关系式IS-A的关系,那么接口和实现类之之间的关系式HAS-A。简单来说,多态就是允许父类引用(或接口)指向子类(或实现类)对象。很多的设计模式都是基于面向对象的多态性设计的。
    
    总结一下,如果说封装和继承是面向对象的基础,那么多态则是面向对象最精髓的理论。掌握多态必先了解接口,只有充分理解接口才能更好的应用多态。
    

    [复制代码](javascript:void(0)😉

    38、面向对象深度优先和广度优先是什么?

    请关注,未完待续!

    python面试题搜集(九):史上最全python面试题详解(三)

    38、面向对象深度优先和广度优先是什么?

    img

    img

    img

    img

    39、面向对象中super的作用?

    img

    40、是否使用过functools中的函数?其作用是什么?

    [复制代码](javascript:void(0)😉

    1 Python自带的 functools 模块提供了一些常用的高阶函数,也就是用于处理其它函数的特殊函数。换言之,就是能使用该模块对可调用对象进行处理。
    2 
    3 functools模块函数概览
    4 functools.cmp_to_key(func)
    5 functools.total_ordering(cls)
    6 functools.reduce(function, iterable[, initializer])
    7 functools.partial(func[, args][, *keywords])
    8 functools.update_wrapper(wrapper, wrapped[, assigned][, updated])
    9 functools.wraps(wrapped[, assigned][, updated])
    

    [复制代码](javascript:void(0)😉

    41、列举面向对象中带双下划线的魔术方法?

    1. init()

    2. del()

    [复制代码](javascript:void(0)😉

    1 在调用del方法的时候,实际使用的是del()
    2 
    3 class Person(object):
    4     def __del__(self):
    5         print('我给干掉啦')
    6     
    7 bill = Person()
    8 del bill #我给干掉啦
    

    [复制代码](javascript:void(0)😉

    3. new()

    [复制代码](javascript:void(0)😉

     1 new()只有继承自objectd的类才有new()这方法是在init()之前调用的,用于生成实例对象。多用于设计模式中的单例模式。单例模式是为了确保类有且只有一个对象。多用于日志记录和数据库操作,打印机后台处理程序。这样子可以避免对统一资源产生相互冲突的请求
     2 new()负责创建一个类的对象,init()方法负责对创建后的类对象进行默认设置
     3 class Singleton(object):
     4     def __new__(cls):
     5         if not hasattr(cls, 'instance'):
     6             cls.instance = super(Singleton, cls).__new__(cls)
     7         return cls.instance
     8 
     9 s = Singleton()
    10 print('Object created', s)
    11 s1 = Singleton()
    12 print('Object created', s1)
    13 
    14 # output
    15 # Object created <__main__.Singleton object at 0x0000018EFF662DA0>
    16 # Object created <__main__.Singleton object at 0x0000018EFF662DA0>
    17 
    18 cls是当前类,new()返回的是一个实例,和init()中的self是同一个东西
    

    [复制代码](javascript:void(0)😉

    42、如何判断是函数还是方法?

    一般情况下,单独写一个def func():表示一个函数,如果写在类里面是一个方法。但是不完全准确。

    [复制代码](javascript:void(0)😉

    1 class Foo(object):
    2     def fetch(self):
    3         pass
    4 
    5 print(Foo.fetch)   # 打印结果<function Foo.fetch at 0x000001FF37B7CF28>表示函数
    6 # 如果没经实例化,直接调用Foo.fetch()括号里要self参数,并且self要提前定义
    7 obj = Foo()
    8 print(obj.fetch)  # 打印结果<bound method Foo.fetch of <__main__.Foo object at 0x000001FF37A0D208>>表示方法
    

    [复制代码](javascript:void(0)😉

    43、面向对象中的property属性、类方法、静态方法?

    property属性:

    img

    类方法:

    img

    静态方法:

    img

    44、列举面向对象中的特殊成员以及应用场景

    [复制代码](javascript:void(0)😉

     1 1. __doc__
     2     表示类的描述信息
     3 class Foo:
     4     """ 描述类信息,这是用于看片的神奇 """
     5     def func(self):
     6         pass
     7 print Foo.__doc__
     8  
     9 ==============
    10  描述类信息,这是用于看片的神奇
    

    [复制代码](javascript:void(0)😉

    1 2. __module__ 和  __class__ 
    2  __module__ 表示当前操作的对象在哪个模块
    3    __class__     表示当前操作的对象的类是什么
    1 3. __init__
    2 构造方法,通过类创建对象时,自动触发执行。
    1 4. __del__
    2 析构方法,当对象在内存中被释放时,自动触发执行。
    3 
    4 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
    5. __call__
      对象后面加括号,触发执行。
     
    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
    6. __dict__ 
      类或对象中的所有成员
    7. __str__
    如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
    

    8、eq

    img

    45、什么是反射?以及应用场景?

    img

    img

    img

    img

    img

    46、用尽量多的方法实现单例模式。

    一、模块单例

    Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

    [复制代码](javascript:void(0)😉

    1 #foo1.py
    2 class Singleton(object):
    3     def foo(self):
    4         pass
    5 singleton = Singleton()
    6 
    7 #foo.py
    8 from foo1 import singleton
    

    [复制代码](javascript:void(0)😉

    二、静态变量方法

    先执行了类的__new__方法(我们没写时,默认调用object.new),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式。

    [复制代码](javascript:void(0)😉

     1 class Singleton(object):
     2     def __new__(cls,a):
     3         if not hasattr(cls, '_instance'):
     4             cls._instance = object.__new__(cls)
     5         return cls._instance
     6     def __init__(self,a):
     7         self.a = a
     8     def aa(self):
     9         print(self.a)
    10 
    11 a = Singleton("a")
    

    [复制代码](javascript:void(0)😉

    47、装饰器的写法以及应用场景。

    img

    img

    48、异常处理写法以及如何主动跑出异常(应用场景)

    img

    img

    49、isinstance作用以及应用场景?

    img

    50、json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?

    [复制代码](javascript:void(0)😉

     1 官方文档中的一个Demo:
     2 >>> import json
     3  
     4 >>> class ComplexEncoder(json.JSONEncoder):
     5 ...     def default(self, obj):
     6 ...         if isinstance(obj, complex):
     7 ...             return [obj.real, obj.imag]
     8 ...         return json.JSONEncoder.default(self, obj)
     9 ...
    10 >>> dumps(2 + 1j, cls=ComplexEncoder)
    11 '[2.0, 1.0]'
    12 >>> ComplexEncoder().encode(2 + 1j)
    13 '[2.0, 1.0]'
    14 >>> list(ComplexEncoder().iterencode(2 + 1j))
    15 ['[', '2.0', ', ', '1.0', ']']
    16  
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

     1 然后简单扩展了一个JSONEncoder出来用来格式化时间
     2 class CJsonEncoder(json.JSONEncoder):
     3  
     4     def default(self, obj):
     5         if isinstance(obj, datetime):
     6             return obj.strftime('%Y-%m-%d %H:%M:%S')
     7         elif isinstance(obj, date):
     8             return obj.strftime('%Y-%m-%d')
     9         else:
    10             return json.JSONEncoder.default(self, obj)
    11  
    

    [复制代码](javascript:void(0)😉

    1 使用时候只要在json.dumps增加一个cls参数即可:
    2 
    3 json.dumps(datalist, cls=CJsonEncoder)
    

    51、json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

    img

    52、使用代码实现查看列举目录下的所有文件。

    [复制代码](javascript:void(0)😉

    1 import os
    2 
    3 if __name__ == '__main__':
    4     work_dir = 'C:\Program Files\MySQL\Connector ODBC 8.0'
    5     for parent, dirnames, filenames in os.walk(work_dir, followlinks=True):
    6         for filename in filenames:
    7             file_path = os.path.join(parent, filename)
    8             print('文件名:%s' % filename)
    9             print('文件完整路径:%s\n' % file_path)
    

    [复制代码](javascript:void(0)😉

    53、简述 yield和yield from关键字。

    1、可迭代对象与迭代器的区别

    可迭代对象:指的是具备可迭代的能力,即enumerable. 在Python中指的是可以通过for-in 语句去逐个访问元素的一些对象,比如元组tuple,列表list,字符串string,文件对象file 等。

    迭代器:指的是通过另一种方式去一个一个访问可迭代对象中的元素,即enumerator。在python中指的是给内置函数iter()传递一个可迭代对象作为参数,返回的那个对象就是迭代器,然后通过迭代器的next()方法逐个去访问。

    [复制代码](javascript:void(0)😉

    1 from collections import Iterable
    2 
    3 li=[1,4,2,3]
    4 iterator1 = iter(li)
    5 print(next(iterator1))
    6 print(next(iterator1))
    7 print(next(iterator1))
    8 print(isinstance(iterator1,Iterable)) # 判断是否是迭代器,导入collection模块
    

    [复制代码](javascript:void(0)😉

    >>>1
    4
    2
    True
    

    2、生成器

    生成器的本质就是一个逐个返回元素的函数,即“本质——函数”

    最大的好处在于它是“延迟加载”,即对于处理长序列问题,更加的节省存储空间。即生成器每次在内存中只存储一个值

    3、什么又是yield from呢?

    简单地说,yield from generator 。实际上就是返回另外一个生成器。如下所示:

    [复制代码](javascript:void(0)😉

     1 def generator1():
     2     item = range(10)
     3     for i in item:
     4         yield i
     5 
     6 def generator2():
     7     yield 'a'
     8     yield 'b'
     9     yield 'c'
    10     yield from generator1() #yield from iterable本质上等于 for item in iterable: yield item的缩写版
    11     yield from [11,22,33,44]
    12     yield from (12,23,34)
    13     yield from range(3)
    14 
    15 for i in generator2() :
    16     print(i)
    

    [复制代码](javascript:void(0)😉

    从上面的代码可以看出,yield from 后面可以跟的式子有“ 生成器 元组 列表等可迭代对象以及**range()**函数产生的序列”

    上面代码运行的结果为:

    a
    b
    c
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    11
    22
    33
    44
    12
    23
    34
    0
    1
    2

    请关注,未完待续!

    python面试题搜集(十):史上最全python面试题详解(四)

    8.Python高级进阶-网络编程和并发(?道题详解)

    1、简述 OSI 七层协议。

    OSI是Open System Interconnection的缩写,意为开放式系统互联。

    OSI七层协议模型主要是:应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。

    [复制代码](javascript:void(0)😉

    1、物理层
    主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。   
    
    2、数据链路层
    定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。   
    
    3、网络层
    在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。   
    
    4、运输层
    定义了一些传输数据的协议和端口号(WWW端口80等),如: 
    TCP(transmission control protocol –传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据) 
    UDP(user datagram protocol–用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。   
    
    5、会话层
    通过运输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)   
    
    6、表示层
    可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。   
    
    7、应用层
    是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
    

    [复制代码](javascript:void(0)😉

    2、什么是C/S和B/S架构?

    \1. C/S架构及其背景

    C/S架构是一种比较早的软件架构,主要应用于局域网内。在这之前经历了集中计算模式,随着计算机网络的进步与发展,尤其是可视化工具的应用,出现过两层C/S和三层C/S架构,不过一直很流行也比较经典的是我们所要研究的两层C/S架构。

    C/S架构软件(即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,这两个组成部分都承担着重要的角色。

    img

    [复制代码](javascript:void(0)😉

    2. C/S架构的优点
    a. 客户端和服务器直接相连。点对点的连接方式更安全,可以直接操作本地文本,比较方便。
    b. 客户端可以处理一些逻辑事务。可以进行数据处理和数据存储,提供一定的帮助。
    c. 客户端直接操作界面。
    
    3. C/S架构的缺点
    a> C/S架构适用于局域网,对网速的要求比较高。
    b> 客户端界面缺乏通用性,且当业务更改时就需要更改界面,重新编写。
    c> 随着用户数量的增多,会出现通信拥堵、服务器响应速度慢等情况。
    d> 系统的维护也比较麻烦。
    
    4. C/S架构的应用
    C/S架构的软件是在是数不胜数,从办公的OFFICE,WPS,WINRAR到杀毒软件如金山,瑞金再到我们的娱乐软件,如播放器,QQ,微信等,无处不见C/S架构。
    

    [复制代码](javascript:void(0)😉

    \1. B/S架构及其背景
    随着Internet和WWW的流行,以往的主机/终端和C/S都无法满足当前的全球网络开放、互连、信息随处可见和信息共享的新要求,于是就出现了B/S型模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构。主要是利用了不断成熟的WWW浏览器技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。
    img

    第一层是浏览器(即客户端)只有简单的输入输出功能,处理极少部分的事务逻辑。由于客户不需要安装客户端,只要有浏览器就能上网浏览,所以它面向的是大范围的用户,所以界面设计得比较简单,通用。
    第二层是WEB服务器,扮演着信息传送的角色。当用户想要访问数据库时,就会首先向WEB服务器发送请求,WEB服务器统一请求后会向数据库服务器发送访问数据库的请求,这个请求是以SQL语句实现的。
    第三层是数据库服务器,它存放着大量的数据。当数据库服务器收到了WEB服务器的请求后,会对SQL语句进行处理,并将返回的结果发送给WEB服务器,接下来,WEB服务器将收到的数据结果转换为HTML文本形式发送给浏览器。

    [复制代码](javascript:void(0)😉

    2. B/S架构的优点
    a> 浏览器和数据库服务器采用多对多的方式连接。因此适合在广域网里实现巨大的互联网,甚至是全球网,有着很强大的信息共享性。
    b> 浏览器只处理一些简单的逻辑事务,负担小。
    c> 数据都集中存放在数据库服务器,所以不存在数据不一致现象。
    d> 随着服务器负载的增加,可以平滑地增加服务器的个数并建立集群服务器系统,然后在各个服务器之间做负载均衡。
    e> B/S建立在广域网上,所以需要的网速要求不高。
    f> 不需要安装客户端,只要能连上网,就能随时随地的浏览页面。
    g> 能有效地保护数据平台和管理访问权限,确保服务器数据库的数据安全。
    
    3. B/S架构的缺点
    a> 服务器承担着重要的责任,数据负荷较重。一旦发生服务器“崩溃”等问题,后果不堪设想。
    b> 页面需要不断地动态刷新,当用户增多时,网速会变慢。
    
    4. B/S架构的应用
    比如WEBQQ,从WEBQQ名称中的WEB就不难看出它属于B/S架构,是一种浏览器服务器结构。事实上也是如此,因为WEBQQ根本不需要安装客户端,只需要有浏览器就可以进行聊天交互了。
    

    [复制代码](javascript:void(0)😉

    3、简述 三次握手、四次挥手的流程。

    三次握手:

    初始状态:客户端A和服务器B均处于CLOSED状态,然后服务器B创建socket,调用监听接口使得服务器处于LISTEN状态,等待客户端连接。(后续内容用A,B简称代替)

    1、A首先向B发起连接,这时TCP头部中的SYN标识位值为1,然后选定一个初始序号seq=x(一般是随机的),消息发送后,A进入SYN_SENT状态,SYN=1的报文段不能携带数据,但要消耗一个序号。

    2、B收到A的连接请求后,同意建立连接,向A发送确认数据,这时TCP头部中的SYN和ACK标识位值均为1,确认序号为ack=x+1,然后选定自己的初始序号seq=y(一般是随机的),确认消息发送后,B进入SYN_RCVD状态,与连接消息一样,这条消息也不能携带数据,同时消耗一个序号。

    3、A收到B的确认消息后,需要给B回复确认数据,这时TCP头部中的ACK标识位值为1,确认序号是ack=y+1,自己的序号在连接请求的序号上加1,也就是seq=x+1,此时A进入ESTABLISHED状态,当B收到A的确认回复后,B也进入ESTABLISHED状态,至此TCP成功建立连接,A和B之间就可以通过这个连接互相发送数据了。

    四次挥手:

    初始状态:客户端A和服务器B之间已经建立了TCP连接,并且数据发送完成,打算断开连接,此时客户端A和服务器B是等价的,双方都可以发送断开请求,下面以客户端A主动发起断开请求为例。(后续内容用A,B简称代替)

    1、A首先向B发送断开连接消息,这时TCP头部中的FIN标识位值为1,序号是seq=m,m为A前面正常发送数据最后一个字节序号加1得到的,消息发送后A进入FNI_WAIT_1状态,FIN=1的报文段不能携带数据,但要消耗一个序号。

    2、B收到A的断开连接请求需要发出确认消息,这时TCP头部中的ACK标识位值为1,确认号为ack=m+1,而自己的序号为seq=n,n为B前面正常发送数据最后一个字节序号加1得到的,然后B进入CLOSE_WAIT状态,此时就关闭了A到B的连接,A无法再给B发数据,但是B仍然可以给A发数据(此处存疑),同时B端通知上方应用层,处理完成后被动关闭连接。然后A收到B的确认信息后,就进入了FIN_WAIT_2状态。

    3、B端应用层处理完数据后,通知关闭连接,B向A发送关闭连接的消息,这时TCP头部中的FIN和ACK标识位值均为1,确认号ack=m+1,自己的序号为seq=k,(B发出确认消息后有发送了一段数据,此处存疑),消息发送后B进入LACK_ACK状态。

    4、A收到B的断开连接的消息后,需要发送确认消息,这是这时TCP头部中的ACK标识位值为1,确认号ack=k+1,序号为m+1(因为A向B发送断开连接的消息时消耗了一个消息号),然后A进入TIME_WAIT状态,若等待时间经过2MSL后,没有收到B的重传请求,则表明B收到了自己的确认,A进入CLOSED状态,B收到A的确认消息后则直接进入CLOSED状态。至此TCP成功断开连接。

    4、什么是arp协议?

    ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。

    详细见 https://www.cnblogs.com/csguo/p/7527303.html

    5、TCP和UDP的区别?

    [复制代码](javascript:void(0)😉

    TCP: 
    TCP编程的服务器端一般步骤是: 
      1、创建一个socket,用函数socket(); 
      2、设置socket属性,用函数setsockopt(); * 可选 
      3、绑定IP地址、端口等信息到socket上,用函数bind(); 
      4、开启监听,用函数listen(); 
      5、接收客户端上来的连接,用函数accept(); 
      6、收发数据,用函数send()和recv(),或者read()和write(); 
      7、关闭网络连接; 
      8、关闭监听; 
    

    [复制代码](javascript:void(0)😉

    [复制代码](javascript:void(0)😉

    UDP:
    与之对应的UDP编程步骤要简单许多,分别如下: 
      UDP编程的服务器端一般步骤是: 
      1、创建一个socket,用函数socket(); 
      2、设置socket属性,用函数setsockopt();* 可选 
      3、绑定IP地址、端口等信息到socket上,用函数bind(); 
      4、循环接收数据,用函数recvfrom(); 
      5、关闭网络连接; 
    

    [复制代码](javascript:void(0)😉

    TCP与UDP基本区别

    1. 基于连接与无连接
    2. TCP要求系统资源较多,UDP较少
    3. UDP程序结构较简单
    4. 字节流模式(TCP)与数据报模式(UDP);
    5. TCP保证数据正确性,UDP可能丢包
    6. TCP保证数据顺序,UDP不保证

    具体编程时的区别
    1.socket()的参数不同
       2.UDP Server不需要调用listen和accept
       3.UDP收发数据用sendto/recvfrom函数
       4.TCP:地址信息在connect/accept时确定
       5.UDP:在sendto/recvfrom函数中每次均 需指定地址信息
       6.UDP:shutdown函数无效

    6、什么是局域网和广域网?

    局域网:(Local Area Network,LAN), 局域网是一个局部范围的计算计组,比如家庭网络就是一个小型的局域网,里面包含电脑、手机和平板等,他们共同连接到你家的路由器上。又比如学校的机房就是一个局域网,里面有几百几千台电脑,当机房无法上外网时,但是电脑之间仍可以通信,你们可以通过这个局域网来打CS 、玩红警。理论上,局域网是封闭的,并不可以上外网,可以只有两台电脑,也可以有上万台。

    广域网:(WAN,Wide Area Network),广域网的范围就比较大了,可以把你家和别人家、各个省、各个国家连接起来相互通信。广域网和局域网都是从范围的角度来划分的,广域网也可以看成是很多个局域网通过路由器等相互连接起来。

    7、为何基于tcp协议的通信比基于udp协议的通信更可靠?

    TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。不过UDP的发送速度是TCP比不了的,而且UDP的反应速度更快。

    8、什么是socket?简述基于tcp协议的套接字通信流程。

    套接字,也称为BSD套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。

    1.服务器先用 socket 函数来建立一个套接字,用这个套接字完成通信的监听。
    2.用 bind 函数来绑定一个端口号和 IP 地址。因为本地计算机可能有多个网址和 IP,每一个 IP 和端口有多个端口。需要指定一个 IP 和端口进行监听。
    3.服务器调用 listen 函数,使服务器的这个端口和 IP 处于监听状态,等待客户机的连接。
    4.客户机用 socket 函数建立一个套接字,设定远程 IP 和端口。
    5.客户机调用 connect 函数连接远程计算机指定的端口。
    6.服务器用 accept 函数来接受远程计算机的连接,建立起与客户机之间的通信。
    7.建立连接以后,客户机用 write 函数向 socket 中写入数据。也可以用 read 函数读取服务器发送来的数据。
    8.服务器用 read 函数读取客户机发送来的数据,也可以用 write 函数来发送数据。
    9.完成通信以后,用 close 函数关闭 socket 连接。

    img

    9、什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

    img

    10、IO多路复用的作用?

    一、基本概念

    IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

    (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。

    (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。

    (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。

    (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。

    (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

    与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

    请关注,未完待续!

    B/S架构,是一种浏览器服务器结构。事实上也是如此,因为WEBQQ根本不需要安装客户端,只需要有浏览器就可以进行聊天交互了。

    
    [[外链图片转存中...(img-fac8gE4I-1603255929320)]](javascript:void(0);)
    
    ## 3、简述 三次握手、四次挥手的流程。
    
    #### 三次握手:
    
    初始状态:客户端A和服务器B均处于CLOSED状态,然后服务器B创建socket,调用监听接口使得服务器处于LISTEN状态,等待客户端连接。(后续内容用A,B简称代替)
    
    1、A首先向B发起连接,这时TCP头部中的SYN标识位值为1,然后选定一个初始序号seq=x(一般是随机的),消息发送后,A进入SYN_SENT状态,SYN=1的报文段不能携带数据,但要消耗一个序号。
    
    2、B收到A的连接请求后,同意建立连接,向A发送确认数据,这时TCP头部中的SYN和ACK标识位值均为1,确认序号为ack=x+1,然后选定自己的初始序号seq=y(一般是随机的),确认消息发送后,B进入SYN_RCVD状态,与连接消息一样,这条消息也不能携带数据,同时消耗一个序号。
    
    3、A收到B的确认消息后,需要给B回复确认数据,这时TCP头部中的ACK标识位值为1,确认序号是ack=y+1,自己的序号在连接请求的序号上加1,也就是seq=x+1,此时A进入ESTABLISHED状态,当B收到A的确认回复后,B也进入ESTABLISHED状态,至此TCP成功建立连接,A和B之间就可以通过这个连接互相发送数据了。
    
    #### 四次挥手:
    
    初始状态:客户端A和服务器B之间已经建立了TCP连接,并且数据发送完成,打算断开连接,此时客户端A和服务器B是等价的,双方都可以发送断开请求,下面以客户端A主动发起断开请求为例。(后续内容用A,B简称代替)
    
    1、A首先向B发送断开连接消息,这时TCP头部中的FIN标识位值为1,序号是seq=m,m为A前面正常发送数据最后一个字节序号加1得到的,消息发送后A进入FNI_WAIT_1状态,FIN=1的报文段不能携带数据,但要消耗一个序号。
    
    2、B收到A的断开连接请求需要发出确认消息,这时TCP头部中的ACK标识位值为1,确认号为ack=m+1,而自己的序号为seq=n,n为B前面正常发送数据最后一个字节序号加1得到的,然后B进入CLOSE_WAIT状态,此时就关闭了A到B的连接,A无法再给B发数据,但是B仍然可以给A发数据(此处存疑),同时B端通知上方应用层,处理完成后被动关闭连接。然后A收到B的确认信息后,就进入了FIN_WAIT_2状态。
    
    3、B端应用层处理完数据后,通知关闭连接,B向A发送关闭连接的消息,这时TCP头部中的FIN和ACK标识位值均为1,确认号ack=m+1,自己的序号为seq=k,(B发出确认消息后有发送了一段数据,此处存疑),消息发送后B进入LACK_ACK状态。
    
    4、A收到B的断开连接的消息后,需要发送确认消息,这是这时TCP头部中的ACK标识位值为1,确认号ack=k+1,序号为m+1(因为A向B发送断开连接的消息时消耗了一个消息号),然后A进入TIME_WAIT状态,若等待时间经过2MSL后,没有收到B的重传请求,则表明B收到了自己的确认,A进入CLOSED状态,B收到A的确认消息后则直接进入CLOSED状态。至此TCP成功断开连接。
    
    ##  4、什么是arp协议?
    
    ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。
    
    详细见 https://www.cnblogs.com/csguo/p/7527303.html
    
    ## 5、TCP和UDP的区别?
    
    [[外链图片转存中...(img-IkVNziti-1603255929321)]](javascript:void(0);)
    
    

    TCP:
    TCP编程的服务器端一般步骤是:
      1、创建一个socket,用函数socket();
      2、设置socket属性,用函数setsockopt(); * 可选
      3、绑定IP地址、端口等信息到socket上,用函数bind();
      4、开启监听,用函数listen();
      5、接收客户端上来的连接,用函数accept();
      6、收发数据,用函数send()和recv(),或者read()和write();
      7、关闭网络连接;
      8、关闭监听;

    
    [[外链图片转存中...(img-uB3MZRvg-1603255929322)]](javascript:void(0);)
    
    [[外链图片转存中...(img-bwpNmPLj-1603255929323)]](javascript:void(0);)
    
    

    UDP:
    与之对应的UDP编程步骤要简单许多,分别如下:
      UDP编程的服务器端一般步骤是:
      1、创建一个socket,用函数socket();
      2、设置socket属性,用函数setsockopt();* 可选
      3、绑定IP地址、端口等信息到socket上,用函数bind();
      4、循环接收数据,用函数recvfrom();
      5、关闭网络连接;

    
    [[外链图片转存中...(img-99GZnSSg-1603255929324)]](javascript:void(0);)
    
    TCP与UDP基本区别
    
    1. 基于连接与无连接
    2. TCP要求系统资源较多,UDP较少
    3. UDP程序结构较简单
    4. 字节流模式(TCP)与数据报模式(UDP);
    5. TCP保证数据正确性,UDP可能丢包
    6. TCP保证数据顺序,UDP不保证
    
    具体编程时的区别
        1.socket()的参数不同 
       2.UDP Server不需要调用listen和accept 
       3.UDP收发数据用sendto/recvfrom函数 
       4.TCP:地址信息在connect/accept时确定 
       5.UDP:在sendto/recvfrom函数中每次均 需指定地址信息 
       6.UDP:shutdown函数无效
    
    ## 6、什么是局域网和广域网?
    
    局域网:(Local Area Network,LAN),  局域网是一个局部范围的计算计组,比如家庭网络就是一个小型的局域网,里面包含电脑、手机和平板等,他们共同连接到你家的路由器上。又比如学校的机房就是一个局域网,里面有几百几千台电脑,当机房无法上外网时,但是电脑之间仍可以通信,你们可以通过这个局域网来打CS 、玩红警。理论上,局域网是封闭的,并不可以上外网,可以只有两台电脑,也可以有上万台。
    
    广域网:(WAN,Wide Area Network),广域网的范围就比较大了,可以把你家和别人家、各个省、各个国家连接起来相互通信。广域网和局域网都是从范围的角度来划分的,广域网也可以看成是很多个局域网通过路由器等相互连接起来。
    
    ## 7、为何基于tcp协议的通信比基于udp协议的通信更可靠?
    
    TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。不过UDP的发送速度是TCP比不了的,而且UDP的反应速度更快。
    
    ## 8、什么是socket?简述基于tcp协议的套接字通信流程。
    
    套接字,也称为BSD套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。
    
    1.服务器先用 socket 函数来建立一个套接字,用这个套接字完成通信的监听。 
    2.用 bind 函数来绑定一个端口号和 IP 地址。因为本地计算机可能有多个网址和 IP,每一个 IP 和端口有多个端口。需要指定一个 IP 和端口进行监听。 
    3.服务器调用 listen 函数,使服务器的这个端口和 IP 处于监听状态,等待客户机的连接。 
    4.客户机用 socket 函数建立一个套接字,设定远程 IP 和端口。 
    5.客户机调用 connect 函数连接远程计算机指定的端口。 
    6.服务器用 accept 函数来接受远程计算机的连接,建立起与客户机之间的通信。 
    7.建立连接以后,客户机用 write 函数向 socket 中写入数据。也可以用 read 函数读取服务器发送来的数据。 
    8.服务器用 read 函数读取客户机发送来的数据,也可以用 write 函数来发送数据。 
    9.完成通信以后,用 close 函数关闭 socket 连接。
    
    [外链图片转存中...(img-FmrgBRsI-1603255929325)]
    
    ## 9、什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
    
    [外链图片转存中...(img-Xi4kM45g-1603255929326)]
    
    ## 10、IO多路复用的作用?
    
    一、基本概念
    
      IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:
    
      (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
    
      (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
    
      (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
    
      (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
    
      (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
    
      与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。
    
    ## 请关注,未完待续!
    
     
    
    展开全文
  • Python 面试100讲(基于Python3.x)

    万人学习 2019-11-15 10:20:42
    本课程搜集了各大互联网公司的Python面试题以及类似的题目。课程体系包括Python语言本身的知识、Python SDK、Web、Python爬虫以及算法等内容。所以的源代码都使用Python3.x编写。Python相关知识包括基本语法、正则...
  • python面试题目

    2018-08-22 22:36:59
    python面试题,面试专用的好面试题目python面试题,面试专用的好面试题目
  • 全网极具参考价值的Python面试题,从创业公司到一线大厂的面经汇总整理。作者会持续维护更新!

    各位读者朋友们大家好!我是爬虫领域的职业段子手。这篇文章今天在CSDN首发,后续我会持续维护更新。希望能帮助每一位读者减少掉坑的机率,也祝愿每位读者都能拿到心仪的offer!

    由于时间原因还有很多实战资源题目及问题未能写完,后续会陆续更新上来

    另外,大家有任何在面试中遇到的有趣的问题及疑问都可以骚扰我!或者在下方评论区留言,之后也都会添加到本文章中分享给读者去参考

    这篇文章看完如果对你有所帮助的话,希望能给作者点个赞。感谢!

    我为何写这篇文章

      我为什么会写一篇这样的文章呢?我记得我以前刚开始面试的时候也会很好奇人家公司面试官会问一些什么样的问题?会出一些什么样的笔试题?而我个人的话又该准备哪些知识点呢?我也会在网上搜,一搜出来一大片,但是仔细翻阅发现大部分是一些比较基础的Python题目。每一个岗位面试的体验都是不一样的,所有公司的Feature也是不一样的,甚至是每一个面试官带给你的Freestyle也是不一样的!

    这些问题都来自哪

      以下所有涉及到的题目及问题大部分均来自第三方公司面经高频总结,其中包括不限于个人面经、朋友分享、热门话题。内容涉及创业公司到一线大厂均有!在这里为了保证第三方隐私性,就不按企业名称来划分问题了。但是我还是想跟大家说一句:

    看完这篇文章,掌握其中要领,一定会让你受益匪浅


    1. 笔试

      笔试在很多互联网公司中都会出现,尤其是一些较大的公司中。大家都能看到身边很多的小伙伴都在讨论刷一些算法题,为了下一次面试努力刷题。这些笔试的题目都是由谁出的呢?我可以很明确的告诉大家,大部分都是相关的开发人员所出。他们会在网上搜一搜相关题材、然后自己再改一改。很多都没有经过长期的信效度考验,缺少难度控制,笔试题目我个人觉得根本没法真实考核出面试者的个人能力。何况还有漏题的风险

      之所以会有笔试这个环节,真实目的就是能够快速把不合格的人和运气不够好的人快速过滤掉。从海量合格人选,注意!是合格人选中,相当粗糙但远优于随机地,挑选出一小批合格可能性非常非常高的p<0.01的面试集合,让面试官接触。这才是互联网企业的招聘核心成本:人力成本

    你没有听错!运气!所有的面试中成功与否不光取决于你的能力还有你的运气

    1.1 简答题

    高频题(面试常问)|Python 的 yield 关键字有什么作用?

    • 保存当前运行状态,然后暂停执行,即将函数挂起。yield关键字后面表达式的值作为返回值返回。当使用next()、send()函数从断点处继续执行

    Python中【args】【kwargs】 是什么?

    • 可变参数的处理
    • args 打包成 tuple
    • kwargs 被打包成 dict

    Python的列表和元组有什么区别?

    • 可变与不可变(列表是可变的而元组是不可变的)
    • 速度(元组比列表更快)

    并发与并行的区别?

    • 并发不是并行,但看起来像是同时运行的,单个cpu和多道技术就可以实现并发。并行也属于并发,指的是同时运行,只有具备多个cpu才能实现并行

    下面代码会输出什么?

    list = ['1','2','3','4','5']
    print(list[10:])
    '''
    这是一个坑!很e心的操作,代码将输出[],它并不会产生我们脑海中预期的IndexError错误'''
    

    处理一个大小为8G的文件,但是内存只有4G!如何实现以及需要考虑的问题?

    from mmap import mmap
    
    def get_lines(f_p):
        with open(f_p,"r+") as f:
            m = mmap(f.fileno(), 0)
            tmp = 0
            for i, char in enumerate(m):
                if char==b"\n":
                    yield m[tmp:i+1].decode()
                    tmp = i+1
    
    if __name__=="__main__":
        for i in get_lines("file/path"):
            print(i)
    

    内存只有4G无法一次性读入8G文件,需要分批读入数据且记录每次读入数据的位置。分批每次读取数据的大小,太小的话会在读取操作花费过多时间

    请按value值进行排序: d= {‘a’:30,‘g’:50,‘i’:12,‘k’:23}

    sorted(d.items(),key=lambda x:x[1])
    

    介绍一下进程同步锁的概念

    • 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件或者打印终端是可以的。共享带来了竞争,竞争的结果就是混乱。解决办法就是加锁处理。加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全

    python是如何进行内存管理的?

    • python采用的是基于值的内存管理方式,如果为不同变量赋值相同值,则在内存中只有一份该值,多个变量指向同一块内存地址

    高频题(面试常问)|Python中的深拷贝和浅拷贝有什么区别?

    • copy.copy(浅拷贝) 只拷贝父对象,不会拷贝对象的内部的子对象
    • copy.deepcopy( 深拷贝) 拷贝对象及其子对象
    • 【不懂的读者可以自行在ipython中验证一下查看效果】

    高频题(面试常问)|Python垃圾回收机制

    • PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。引用计数为0时,该对象生命就结束了
    • 优点:【简单、实时性
    • 缺点:【维护引用计数消耗资源、循环引用
    • 【标记-清除机制】基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放
    • 【分代技术】分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量

    Python支持多少种序列?

    • Python是支持7种序列类型的分别是:str,list,tuple,unicode,byte array,xrange和buffer。其中xrange在python 3.5.X中已被弃用

    当Python退出时,为什么不是所有的内存都被解除分配?

    • 当python退出时,尤其是那些对其他对象具有循环引用的Python模块或者从全局名称空间引用的对象并不总是被解除分配或释放。由于python拥有自己的高效清理机制,无法解除分配保留的那些内存部分会在退出时尝试取消分配/销毁其他所有对象

    Python2/3的差异点?

    • print 成为函数
    • 编码问题3不再有Unicode对象,默认str就是Unicode
    • Python3除法返回浮点数
    • 类型注解
    def Test(name: str) -> str:
    return 'Test' + name
    
    • 优化的super()方便调用父类函数
    • 高级解包操作: a, b, *res = range(10)
    • 限定关键词参数
    • Python3重新抛出异常不会丢失栈信息(raise from)
    • 一切返回迭代器:range, zip, map, dict.values
    • yield form 链接子生成器
    • asyncio内置库,asyn/await 原生协程支持异步编程

    Python中静态方法、类方法、成员函数作用是什么?

    • 静态方法是一种普通函数,就位于类定义的命名空间中,它不会对任何实例类型进行操作。使用装饰器@staticmethod定义静态方法。类对象和实例都可以调用静态方法
    • 类方法是将类本身作为对象进行操作的方法。类方法使用@classmethod装饰器定义,其第一个参数是类,约定写为cls

    类的图片

    生成器、迭代器的区别?

    • 生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration 异常

    什么是匿名函数,匿名函数有什么局限性

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

    高频题(面试常问)|函数装饰器有什么作用

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

    高频题(面试常问)|什么是协程?

    • 大家可以自行在网上搜索,属于一个高频题。

    简述一下僵尸进程和孤儿进程?

    • 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作
    • 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程

    SQL基础题|in与not in,exists与not exists的区别?

    • exist会针对子查询的表使用索引
    • not exist会对主子查询都会使用索引
    • in与子查询一起使用的时候,只针对主查询使用索引
    • not in则不会使用任何索引
    • 如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in,所以无论哪个表大,用not exists都比not in 要快

    SQL基础题|drop、delete 与 truncate 三者的区别?

    • delete 用来删除表的全部或者一部分数据行,执行delete 之后,用户需要提交 (commmit) 或者回滚(rollback) 来执行删除或者撤销删除, delete 命令会触发这个表上所有delete 触发器
    • truncate 删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,truncate 比 delete 更快,占用的空间更小
    • drop 命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的 DML 触发器也不会被触发,这个命令也不能回滚
    • 因此,在不再需要一张表的时候,用 drop。在想删除部分数据行时候,用 delete。在保留表而删除所有数据的时候用 truncate

    1.2 基础题

    基础爬虫题|使用多线程生产者消费者模式完成网站爬虫

    • 代码就不贴了,大家可以去了解一下。自己针对简单的网站写一个Demo,这个题目不光考察面试者的编码能力还有就是设计能力
    • 作者在面试爬虫岗遇到过好像有两次吧

    笔试高频题|使用python实现单例模式

    #__new__方法实现
    #实现方法比较多、大家可以自行看看其它实现方法
    class SingleTon(object):
        def __new__(cls,*args,**kwargs):
            #判断该类是否有实例化对象
            if not hasattr(cls,'_instance'):
                cls._instance = object.__new__(cls,*args,**kwargs)
            #将实例对象返回
            return cls._instance
    class HelloClass(SingleTon):
        a = 1
    
    A = HelloClass()
    B = HelloClass()
    print A.a,B.a
    
    A.a=2
    print A.a,B.a
    
    print id(A),id(B)
    

    实现一个简单的栈结构(stack)

    class Stack(object):
        def __init__(self):
            self.value = []
    
        def push(self,x):
            self.value.append(x)
    
        def pop(self):
            self.value.pop()
    
    stack = Stack()
    
    stack.push(1)
    stack.push(2)
    stack.push(3)
    print(stack.value)
    stack.pop()
    print(stack.value)
    

    Python反向迭代一个序列如何操作?

    • 假设是一个list,最快的方法使用reverse
    Test_List = [1,2,3...]
    Test_List.reverse()
    for i in Test_List:
        print i
    
    • 假设不是list,需要手动重排
    Test_List = (1,2,3...)
    for i in range(len(Test_List)-1,-1,-1):
        print Test_List[i]
    

    合并以下两个列表并去重

    A = ['a','b','c','d','e','f']
    B = ['e','a','x','c','z']
    
    def merge_list(*args):
        l = set()
        for i in args:
            l = l.union(i)
        print(l)
        return l
    
    merge_list(A,B)
    

    以下两段代码输出一样吗?占用系统资源一样吗?为什么要用xrange代替range?

    for i in range(1):
    	print(i)
    for i in xrange(1):
    	print(i)
    '''
    结果一样,但是占用系统资源不一样,range与xrange均属于可迭代对象,通过循环迭代可以取出其中的值,但是xrange属于惰性可迭代对象,虽然不是迭代器,没有next方法,但是有迭代器一样的性质,不会一次性将数据加载到内存,而是通过延迟加载的方式生成数据,取一个生成一个,节省内存资源,与python3中的range相同
    '''
    

    正则表达式操作

    '''其中2020-04-20和zhangsan为变量,使用正则表达式捕获这个url,要求尽量精准'''
    
    import re
    wiste_url = "csdnbot/detail/2020-04-20/zhangsan"
    r = re.compile('^footbar/homework/(?P<date>[0-9]{4}-[0-9]{2}-[0-9]{2})/(?P<name>w+)$')
    url = r.findall()
    

    1.3 算法题

      各位读者记得有事没事都可以多刷刷LeetCode上面的题或者看看剑指Offer。我身边的大佬跟我自己所遇到过的面试题基本上99%的公司算法题真的都在这两大神器上出现过,不看你不知道看了是真香啊!

    栈在O(1)时间内求min

    • 这道题有两个朋友碰到过,大家可以在网上围观一下这道经典的题目

    二叉搜索树中第 K 小的元素

    • 这道题目某大厂常考!大家可以自行网上搜索围观

    按照题目指引给的输入和输出实现一个程序

    • 一般就包括排序、树、图等相关题

    链表算法

    • 输出/删除 单链表倒数第 K 个节点
    class Solution:
        def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
            second = fist = head
            for i in range(n):  # 第一个指针先走 n 步
                fist = fist.next
     
            if fist == None:  # 如果现在第一个指针已经到头了,那么第一个结点就是要删除的结点。
                return second.next
     
            while fist.next:  # 然后同时走,直到第一个指针走到头
                fist = fist.next
                second = second.next
            second.next = second.next.next  # 删除相应的结点
            return head
    
    • 删除链表中节点,要求时间复杂度为O(1)
    class Solution:
        def deleteNode(self, node):
            next_node=node.next
            next_nextnode=next_node.next
            node.val=next_node.val
            node.next=next_nextnode
    
    • 反转链表
    class Solution:
        def reverseList(self, head: ListNode) -> ListNode:
            pre=None
            # 不断取出和向后移动头节点,并将头节点连接到新头节点后面
            while head:
                next_node=head.next
                head.next=pre
                pre=head
                head=next_node
            return pre
    

    二叉树的层次遍历

    class Node(object):
        def __init__(self, data, left=None, right=None):
            self.data = data
            self.left = left
            self.right = right
     
    tree = Node(1, Node(3, Node(7, Node(0)), Node(6)), Node(2, Node(5), Node(4)))
     
    def lookup(root):
        stack = [root]
        while stack:
            current = stack.pop(0)
            print current.data
            if current.left:
                stack.append(current.left)
            if current.right:
                stack.append(current.right)
    def deep(root):
        if not root:
            return
        print root.data
        deep(root.left)
        deep(root.right)
     
    if __name__ == '__main__':
        lookup(tree)
    

    判断一棵二叉树是否为另一棵二叉树的子树

    class Solution(object):
        def isSubtree(self, s, t):  #用于判断的主函数,递归得遍历s的每一个结点,并将其作为新的根节点,再与t进行比较
            if not s:
                return False
                
            return self.isEqual(s,t) or self.isSubtree(s.left,t) or self.isSubtree(s.right,t)
            #使用or相连,即其中只要有一个s的子树与t相同,则返回True
            
            
        def isEqual(self,S,T):  #以S为根节点,判断S和T是否相等
            if not S and not T:
                return True
            if S and T:
                if S.val!=T.val:
                    return False
                return self.isEqual(S.left,T.left) and self.isEqual(S.right,T.right)
            else:
                return False
    

    高频算法题|实现一个二分查找的函数

    二分查找是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半

    在这里插入图片描述

    # 返回 x 在 arr 中的索引,如果不存在返回 -1
    def binarySearch (arr, l, r, x): 
      
        # 基本判断
        if r >= l: 
      
            mid = int(l + (r - l)/2)
      
            # 元素整好的中间位置
            if arr[mid] == x: 
                return mid 
              
            # 元素小于中间位置的元素,只需要再比较左边的元素
            elif arr[mid] > x: 
                return binarySearch(arr, l, mid-1, x) 
      
            # 元素大于中间位置的元素,只需要再比较右边的元素
            else: 
                return binarySearch(arr, mid+1, r, x) 
      
        else: 
            # 不存在
            return -1
      
    # 测试数组
    arr = [ 2, 3, 4, 10, 40 ] 
    x = 10
      
    # 函数调用
    result = binarySearch(arr, 0, len(arr)-1, x) 
      
    if result != -1: 
        print ("元素在数组中的索引为 %d" % result )
    else: 
        print ("元素不在数组中")
    

    高频手撕|手写冒泡排序

    冒泡排序是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素如果它们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到最后没有再需要交换也就是说该数列已经排序完成

    在这里插入图片描述

    # -*- coding:utf-8 -*-
    
    import random
    
    def bubbleSort(arr):
        n = len(arr)
     
        for i in range(n):
     
            for j in range(0, n-i-1):
     
                if arr[j] > arr[j+1] :
                    arr[j], arr[j+1] = arr[j+1], arr[j]
     
    arr=[random.randint(1,100) for _ in range(10)]
    print ("排序前:")
    print(arr)
    bubbleSort(arr)
     
    print ("排序后:")
    for i in range(len(arr)):
        print ("%d" %arr[i])
    
    

    高频手撕|手写选择排序

    选择排序是一种简单直观的排序算法。它的工作原理是我们依次拿数组里的元素和它后面的元素进行比较大小,找到最小的元素并和该元素交换位置。然后继续拿第二、第三…第N个元素,这样小的数字最终就会排在前面

    在这里插入图片描述

    # -*- coding:utf-8 -*-
    
    import random
    
    def selectSort(lists):
        lengh = len(lists)
        for i in range(0, lengh-1):
            key = i
            for j in range(i+1, lengh):
                if lists[key] > lists[j]:
                    lists[key], lists[j] = lists[j], lists[key]
     
     
    alist = [random.randint(1,100) for _ in range(10)]
    print("排序前:")
    print(alist)
    selectSort(alist)
    print("排序后:")
    print(alist)
    

    高频手撕|手写快排

    先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1,处理结束

    在这里插入图片描述

    def partition(arr,low,high): 
        i = ( low-1 )# 最小元素索引
        pivot = arr[high]     
      
        for j in range(low , high): 
      
            # 当前元素小于或等于 pivot 
            if   arr[j] <= pivot: 
              
                i = i+1 
                arr[i],arr[j] = arr[j],arr[i] 
      
        arr[i+1],arr[high] = arr[high],arr[i+1] 
        return ( i+1 ) 
      
    def quickSort(arr,low,high): 
        if low < high: 
      
            pi = partition(arr,low,high) 
      
            quickSort(arr, low, pi-1) 
            quickSort(arr, pi+1, high) 
      
    alist = [random.randint(1,100) for _ in range(10)] 
    n = len(alist) 
    quickSort(alist,0,n-1) 
    print ("排序后的数组:") 
    for i in range(n): 
        print ("%d" %alist[i]),
    

    高频手撕|使用Python实现一个斐波那契数列

    nterms = 10
     
    n1 = 0
    n2 = 1
    count = 2
    
    while count < nterms:
       nth = n1 + n2
       print(nth,end=" , ")
       # 更新值
       n1 = n2
       n2 = nth
       count += 1
    

    2. 面试技巧(必看)

      这个环节主要通过包含电话、视频、面对面等交流的方式去考察应试者的技术能力、技术深度、表达能力、解决问题的能力等等。有时候看到很多同学说紧张。在这里我想告诉大家的是这个表现很正常,我们保持平常心就好。面试就是交流并没有多么恐怖!我第一次面试的时候也是慌得一皮。完全丝毫不夸张的说在面试官问的问题内我都知道,但是由于过度紧张甚至连说话都带着那么一丝丝颤音。这种表现最终是非常糟糕的可能会导致你错失offer

      当你觉得自己充分的准备好了面试之后,你应该先找几个感觉对自己会有一定技术挑战的公司,但是并不是强制要求自己特别意向想要去的公司去投递简历面试一下,这个阶段一般会暴露出来很多问题。只要面试官的技术实力比你强,那么在面试的过程中,一定会问到你一些问题,是你之前没注意以及没准备好的。此时你很可能会发现,刚开始面试的头三四家公司,每家公司聊的都不太顺畅,每家公司总有那么几个问题没回答好,最后可能都没拿到offer。但是这个阶段的好处是,你在这个过程中发现了自己很多技术薄弱点,这个时候应该尽快通过上网查资料的方式填补好自己对一些薄弱问题的弱项,迅速总结、消化。

      经过了之前多次被虐以后,个人的面试能力慢慢变强起来,而且你会发现自己找到了一些面试的感觉,总结过自己的一套经验,对面试的节奏、交流都有了很好的把控。这个时候就可以尝试去冲刺一下心仪的大厂了,在这个阶段里,需要全力以赴

    来吧! 不断总结、不断归纳!让我们不断学习更多的知识、技术变得自信起来,让我们拥有跟面试官战一百个回合而不落下风的能力

    2.1 网络相关(小问题大奥妙)

    网络编程的问题基本每一场面试中较为正规的流程都会出现!

    • 说说TCP 和 UDP 的区别?
    • 什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
    • 创建一个TCP服务器的流程?
    • GET 和 POST 请求有什么区别?
    • HTTP 和 HTTPS 的区别?

    经典高频发问:

    • 向浏览器发送一个请求到返回中间经历了什么?
    • 说说三次握手和四次挥手
    • HTTPS 是如何实现安全数据传输的?

    2.2 数据库(经典高频)

      数据库知识很重要!即使你投递的是开发不是DBA,一般的公司基本都会有关于数据库相关知识的面试问题,不是在笔试环节就是在后续跟面试官切磋的环节。你可以不了解数据库底层的基本原理,但是至少要知道索引原理、MySQL的数据引擎、你所经常使用的数据库优缺点等相关知识

    了解数据库索引吗?描述一下它优缺点?

    • 优点:
        (1)大大加快数据的检索速度,这也是创建索引的最主要的原因
        (2)加速表和表之间的连接
        (3)在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
        (4)通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
    • 缺点
        (1)时间方面:创建索引和维护索引要耗费时间,具体地对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度
        (2)空间方面:索引需要占物理空间

    MongoDB做爬虫的话应该经常使用吧?你能说说它的优缺点吗?

    • 优点:性能优越、快速!它将热数据存储在物理内存中,使得热数据的读写变得十分快速。第三方支持丰富,自身的 Failover 机制!弱一致性(最终一致),更能保证用户的访问速度。支持多种编程语言。文档结构的存储方式,能够更便捷的获取数据— json 的存储格式。支持大容量的存储,内置 GridFS
    • 缺点:主要是无事物机制!MongoDB 不支持事务操作(最主要的缺点)。MongoDB 占用空间过大!MongoDB 没有如 MySQL 那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方

    Redis数据类型有哪些?

    • string、hash、List、Set、Sorted Set

    说说Redis的应用场景?

    • 访问热点数据,减少响应时间,提升吞吐量
        (1)会话缓存(最常用)
        (2)消息队列,比如支付
        (3)活动排行榜或计数
        (4)发布,订阅消息(消息通知)
        (5)商品列表,评论列表等

    高并发场景下数据重复插入如何解决?

    • 使用关系型数据库的唯一约束
    • Redis 实现分布式锁

    如果Redis中的某个列表中的数据量非常大,如何实现循环显示每一个值?

    #写个生成器实现
    def list_iter(key, count=3):
                start = 0
                while True:
                    result = conn.lrange(key, start, start+count-1)
                    start += count
                    if not result:
                        break
                    for item in result:
                        yield item
    
            for val in list_iter('num_list'):
                print(val)
    

    简述Redis有哪几种持久化策略及比较?

    RDB:每隔一段时间对Redis进行一次持久化
          - 缺点:数据不完整
          - 优点:速度快
    
    AOF:把所有命令保存起来,如果想到重新生成到Redis,那么就要把命令重新执行一次
          - 缺点:速度慢,文件比较大
          - 优点:数据完整
    

    缓存失效的解决办法?

    • 可以搜索缓存重建,Redis高频题!

    如何基于Redis实现消息队列?

    • Redis并不适合用来做消息队列,业务上避免过度复用一个Redis。选择用它做缓存、做计算比较香。消息队列kafka、MQ它们不香吗?但是代码还是要贴出来的
    
    # 发布者:
    import redis
    conn = redis.Redis(host='192.168.33.16', port=6379)
    conn.publish('a', "点赞关注不迷路!")
    
    # 订阅者:
    import redis
    conn = redis.Redis(host='192.168.33.16', port=6379)
    pub = conn.pubsub()
    pub.subscribe('a')
    while True:
        msg= pub.parse_response()
        print(msg)
    

    基于redis如何实现商城商品数量计数器?

    • 做过电商系统跟抢票系统的同学对库存这块经验想必是很丰富的
    import redis
    
    conn = redis.Redis(host='192.168.33.16', port=6379)
    conn.set('count',10000)
    with conn.pipeline(transaction=True) as pipe:
    
        # 先监视,自己的值没有被修改过
        conn.watch('count')
    
        # 事务开始
        pipe.multi()
        old_count = conn.get('count')
        count = int(old_count)
        if count > 0:    # 有库存
        	#库存递减
            pipe.set('count', count - 1)
    
        # 执行,把所有命令一次性推送过去
        pipe.execute()
    

    MySQL常见数据库引擎及比较

    InnoDB 
    支持事务
    支持外键
    支持表锁、行锁(for update)
    表锁:select * from tb for update
    行锁:select id,name from tb where id=2 for update
    
    myisam
    查询速度快
    全文索引
    支持表锁
    表锁:select * from tb for update
    

    2.3 反爬虫(高能硬核)

      爬虫这个领域的反爬虫问题就比较多了,而且很深。但是!任何网站的任何反爬虫机制所保护的数据最终都是要需要呈现给用户去欣赏的,我们反推复现一下它是怎么显示到页面的就能找到解决思路,数据它无非会出现在JS内或者HTML内又或者是JSON文件内的其中之一!只不过中间实现的过程增加了不同的反爬Feature这个是需要爬虫工程师去分析的

    IP封禁、验证码、US检测、蜜罐数据、JS加密、签名验证、Cookie反爬...
    
    • 网站请求参数加密如何处理?

    反向分析JS加载,首先使用搜索大法,找到关键参数加密部分的JS代码,再用断点调试大法最后重写解密。如果发现搜索大法跟断点都无法命中入口的话,很有可能JS部分加密部分的关键代码被删除可以重写HOOK函数配合断点调试拦截加密参数

    • 爬虫职业生涯中遇到过最棘手的反爬机制是什么?最后如何解决的?

    哈哈!这个问题当初我也是随便说了那么一两个。主要是棘手的套路都差不多,比如ZF相关类型的网站,基本上就是针对IP下手。棘手吗?肯定很棘手!在之前的文章中我说过任何反爬机制都能破解跟绕过,它的实现只不过是时间的问题!但是网站做反爬虫需要做的并不是完全去阻止你的爬虫去爬取数据,而是限制爬虫的很多功能增加爬虫的时间成本、资金成本就够了。某网的反爬机制上午一个Feature,下午一个Feature。这样的谁能受得了吗?当你好不容易分析了一上午的Feature最终完美破解,准备将爬虫投入生产的时候发现新的Feature已经到来

    -说说APP爬虫流程?如果抓包抓不到数据如何处理?

    这个问题吧!正常的(容易的)网站它基本流程就是使用抓包工具。保证APP走代理以及证书被信任,然后打开目标app查看是否能抓到包。如果抓不到数据,这个原因就多了。SSLPinning证书问题、代码混淆加密、反抓包SDK…

    APP抓取没有通用的方法,具体问题还需要具体分析,反抓包的话你可以反编译看看反抓包的实现。因为每种类型的APP的反抓包处理方式都会有差别。有一些APP加密的参数在不能逆向或者能力未达到的情况下也是可以使用自动化测试工具。实在不行的话试试web端或者小程序,功能都一样

    点选验证码识别做过吗?成功率高的算法有多高?

    • 点选验证码大家可以围观一下GitHub上开源的深度学习算法
    • 爬虫往深度学习、神经网络发展的趋势已经不远了
    • 随着智能文本抽取(基于符号密度、未来基于视觉提取还会远吗?)

    JavaScript 逆向你一般怎么做的?

    • 高级爬虫不了解逆向?那肯定不行!现在的招聘职位要求多少都带着点逆向的知识,包括面试也是。JS加密作为爬虫一个绕不过的关卡
    • 通过断点调试,虽然可行!但是你会发现,想一步一步深入地搞清楚这整个程序的逻辑,是十分困难的,因为大部分函数之间都是相互调用的关系。可以直接从系统函数入手调试
    • 搜索大法、常规断点Debug大法、XHR Debug、行为Debug、各种钩子函数的使用、堆栈Debug

    JS逆向主要涉及:JS 基本语法、浏览器渲染知识、代码混淆原理、加密算法理论、开发者工具的使用、代码逆向思路、Hook 和对应的脚本

    2.4 爬虫相关(爬虫必会)

    你爬过某某站和某某站,期间有没有遇到什么困难,你是如何完成的?

    • 该问题一般出现在简历项目内,根据实际情况回答即可

    Scrapy框架运行机制?

    • 这个大家可以自行在网上搜索,资源太多。

    如何提升scrapy的爬取效率?

    • 增加并发、降低日志级别、禁止cookie、禁止重试、减少下载超时
    • 五大功法,具体配置跟操作大家可以看看官方文档

    scrapy及scrapy-redis区别?

    scrapy及scrapy-redis去重原理?

    scrapy如何自定义DownloaderMiddleware

    需要编写一个下载器中间件类。继承scrapy.downloadermiddlewares.DownloaderMiddleware。然后重写process_request方法,就可以定义一个Downloader Middleware
    Reuqest在被Scrapy引擎调度给Downloader之前,process_request方法在这个时候会被调用
    

    简单介绍下 scrapy 的异步处理

    • scrapy 框架的异步机制是基于 twisted 异步网络框架处理的,在 settings.py 文件里可以自行设置具体的并发量数值(默认是并发量 16)

    写爬虫是用多进程好?还是多线程好? 为什么?

    • IO密集型情况使用多线程;

    • 计算密集型情况下使用多进程;

    • IO 密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有 IO 操作会进行 IO 等待,造成不必要的时间浪费,而开启多线程能在线程 A 等待时,自动切换到线程 B,可以不浪费 CPU 的资源,从而能提升程序执行效率)。在实际的数据采集过程中,既考虑网速和响应的问题,也需要考虑自身 机器的硬件情况,来设置多进程或多线程

    如何监控一个爬虫的状态?

    • 使用Python 的 STMP 包将爬虫的状态信息发送到指定的邮箱
    • 虽然Python通过 smtplib 库使得发送email变得很简单,Scrapy仍然提供了自己的实现。 该功能十分易用,同时由于采用了 Twisted非阻塞式(non-blocking)IO ,其避免了对爬虫的非阻塞式IO的影响。 另外,其也提供了简单的API来发送附件。 通过一些 settings 设置,您可以很简单的进行配置
     def __init__(self):
      """ 监听信号量 """
      super(YoutubeapiSpider, self).__init__()# 当收到spider_closed信号的时候,调用下面的close方法来发送通知邮件
      dispatcher.connect(self.spider_closed, signals.spider_closed)
    def spider_closed(self, spider, reason):
          # 上方的信号量触发这个方法
          stats_info = self.crawler.stats._stats  # 爬虫结束时控制台信息
          body = "爬虫[%s]已经关闭,原因是: %s.\n以下为运行信息:\n %s" % (spider.name, reason, stats_info)
          subject = "[%s]爬虫关闭提醒" % spider.name
          mailers.send(to={"513720453@qq.com"},
                       subject=subject,
                       body=body)
    '''
    只要满足触发条件,就可以发送指定内容的邮件
    '''
    

    分布式爬虫主要解决哪些问题?

    • ip、带宽、cpu、io

    3. 项目问题(高能场景复现)

      任何一个公司的面试,都一定会涉及到作为一个工程师最核心的价值——解决问题的能力,具体来说就是你做过的项目,这块是面试准备时的重中之重,应该作为最高优先级来对待。面试官反复的追问项目的各个地方的技术实现细节,就想看看有没有哪个地方是有一定的技术难度的,可以体现出这个候选人的一些项目上的亮点
    在这里插入图片描述

    在这个环节的话面试官大部分是左手拿着你的简历,右手揣兜,目光时不时望向你

    本导演开始现场复现:来!灯光、灯光打过来。再过来些!好!action

    面试官:我看你简历上写的这个项目,我很感兴趣,你能详细说一下吗?
    你:开始你的表演(别跟我说你自己写得简历却不知从何说起…)

    面试官:你们这个项目中主要涉及了哪些技术/框架?
    你:可以按照项目的基础架构、各个功能模块细分技术栈做一些描述

    面试官:在这个项目中你遇到过哪些技术难点和问题是如何解决的呢?

    作者插嘴:这个问题不太好回答,能得到解决的问题也可以说不叫问题。就好比问你觉得哪家的撸串最好吃!如果你能一下子说出来,那么证明你就撸过那几家的!但是呢?如果你说没遇到过什么问题会显得你的经历不够多,说实在的回头想想看,感觉也没遇到过啥了不起的难题。

    作者插嘴:一个优秀的面试官,看到你简历上的XX项目以及用到的技术的时候,他其实大概知道做这个项目会遇到些什么比较难的技术问题,然后直接问你是怎么解决的。

    你:所以还是得如实根据自身的实际情况去回答吧!没有最优解!记得不要吹NB,不然一问破绽多了就很尴尬了!你也同样不能反问面试官说:那您觉得您撸过最好吃的串是哪一家呢?哈哈…你是魔鬼吗?

    面试官:你在这个项目中承担的角跟主要负责?
    你:根据个人实际情况展开回答

    面试官:你在这个项目中学到了什么?
    你:可以说说项目中的令人眼前一亮的技术

    在这个环节经常也会引出连环炮!面试官比如会常问:
      为什么要用这个不用那个?
      这个你了解吗?好的!你了解,那么你能说说它的原理吗?底层怎么实现的?

    所以说重要的事情说三遍:基础!基础!基础!如果你能把连环炮抗下来基本证明你的基础能力是很强的,会用跟产生自己的想法跟理解是个分水岭

      说到这里我跟大家说个有趣的事,之前有一次电话面试中一个面试官一上来叭叭问了我一堆分布式、反爬虫、爬虫框架相关的问题。我也叭叭回答了他一堆,他的回答基本就是:嗯,好之类的回应。问题问了很多但是都不做评价跟追问。最后说了一句让我彻底懵逼的话:那个我对爬虫也不是很了解。搞得我一脸的黑人问号脸!我在哪?我是谁?

    4. Freestyle题

      这个环节看这标题能感受到这个语义吗?Do you have a Freestyle?

    Oh,Yeah。我为什么取名Freestyle?因为它来自面试官的即兴发挥!

    面试官:我看了你的博客,很不错,小伙子。
    我:感谢老铁支持 您的夸奖
    面试官:最近有学习新技术吗?
    我:当然,叭拉叭拉…
    面试官:你对自己的未来的规划是什么?
    我:叭拉叭拉…
    面试官:写文章带给你最大的收获是什么?
    我:快乐!您现在正在看的这篇文章此时已经凌晨3点!还有一个小时我又能跟凌晨四点的北京同在

    有在项目中用过消息中间件吗,例如 Kafka、MQ 之类的

    • 用过!好的。连环炮…
    • 没用过?显得太LOW?

    说说你擅长哪些方面?

    • Freestyle就是Freestyle,问题都是这么的优雅。这个根据自身领域回答即可

    你现在技术方面有哪些瓶颈或者觉得可以提升的地方?

    • 可以根据自身实际情况述说

    这道题为什么这么做,有什么好处?

    • 此时此刻面试官正拿着你的笔试题

    爬虫究竟是合法还是违法的?你如何看待?

    • 爬虫技术本身不违法,关键是看你爬取到的数据用来做什么。所以事情违法,要看如何定性

    5. 场景实战题

      这个环节我碰到过两次!期间聊得很开心,最后说我这里有一个网站的反爬,你能看看怎么解决吗?其实这种情况很多人会觉得面试公司在套思路套方案之类的。嗯~说实话,世界之大无奇不有。这种公司存在吗?当前存在!但是我还是现场操练起来,一个JS加密比较简单反推一下通过断点找到了加密那块JS,作了一下解密基本就过了。还有一个是一个境外网站要求只能通过Request请求拿到数据,有一个鼠标监测反爬,每一次请求需要提交鼠标坐标参数,问题也不大

      像一些后端开发的同学面一些大公司的时候会碰到一些现场设计系统的题。比如电商的秒杀系统、抢红包系统等等。爬虫面试的时候一样会涉及到让你现场设计一个分布式爬虫系统

    如何监控网站更新情况?

    • Distill Web Monitor等Chrome插件现在能实现这个需求
    • 静态网页的话可以拿文件修改时间通过发送 If-Modified-Since请求来比对
    • 动态网页的话通过将网页转化成MD5或哈希持久化比对
    • 难点其实是主体内容有无更新,很多网站其实是主体内容没更新,但会随机来个列表更新之类的,保持它网页的更新性

    通用爬虫可行吗?主要适用于哪些类型的网站?

    • 可行!主要可以用于文章类型的网站数据爬取,比如新闻资讯类网站等。通过输入域名,提取字段等参数设置,然后程序会自动一层一层爬取该站点下的全部数据

    看你简历做过舆情系统爬虫?如何保证系统数据的实时性?

    • 一个优秀的舆情系统都是有实时采集功能的。像新闻、社交类网站,通常是按照最新发布的时间顺序向下展示数据的,较少有时间打乱的展示方式。所以每次对网站检索都可以查看到最新的发布信息。

    • 那么对于舆情系统来说,在对社交媒体、新闻网站等进行舆情监控时,可设置定时采集功能。对目标网站进行最短1分钟每次的实时访问,即当第一次数据采集结束,1分钟后可再次访问该网站,获取到最新发布的信息。

    6. 致谢

      好了,到这里又到了跟大家说再见的时候了。感谢抽出宝贵时间阅读的各位小读者们。创作不易,如果感觉有点东西的话,帮忙点个赞再走吧。你的支持是我创作的动力,希望能带给大家更多优质的文章

    如果你想跟作者有点故事,可以通过下方传送门找到我哟!里面有作者收藏的独家学习秘籍及优质大佬群。跟各领域优秀的顶级大佬在一起聊聊技术、学学投资理财…不说了~我要回家吃饭了~~记得来找我哟、风里雨里我会一直在这等你
    在这里插入图片描述

    展开全文
  • 整理的python面试宝典,100题,包你面试无忧,遇见python面试题,遇神杀神、遇佛杀佛,欢迎大家下载评价,谢谢。
  • python面试

    2018-06-17 13:48:54
    自己从网络整理的python面试常见题,作为准备python面试的一个材料
  • python 面试宝典

    2018-09-20 11:28:12
    该书为python面试宝典,用于对python知识点巩固,应对面试
  • Python面试

    2020-07-12 21:31:26
    Python面试Python面试Python面试
  • python面试宝典pdf版

    2018-10-18 15:38:11
    python面试宝典,分为python进阶, python经典面试题, python面试100例, python面试总结,一共130页, 页面清晰。
  • Python面试宝典

    2019-03-15 17:00:06
    Python面试宝典Version8.1 感恩于心,回报于行 原文地址:http://bbs.itheima.com/thread-402667-1-1.html
  • python面试宝典

    2018-06-14 21:45:08
    python面试宝典,该宝典是一份知识点全面又能不断更新,与时俱进的学习手册,不仅收录了作者亲身面试遇到的问题,还收录了近上万名黑马学子面试时遇到的问题。
  • 链表 python 面试题by Anthony Sistilli 安东尼... Python面试问题指南:如何编写链表 (Python interview question guide: how to code a linked list) I always understood the core concept of Linked Lists, but...
  • Python面试题汇总

    2019-02-13 19:15:39
    某培训机构总结的面试题结合 Python面试题汇总 其中包含python基础、高级企业面试题
  • Python面试提高自己

    2017-12-14 09:55:42
    Python面试须知,掌握提高自己面试通过率 本资料共包含以下附件: Python面试须知,掌握提高自己面试通过率.pdf
  • 110道Python面试

    2018-11-23 19:20:50
    110道Python面试题,python面试经验技巧 。
  • Python 爬虫面试题,Python面试必看

    千次阅读 2019-06-28 10:49:52
    先来一份完整的Python爬虫工程师关于Python面试的考点: 搞定这套 Python 爬虫面试题,Python面试 so easy 一、 Python 基本功 1、简述Python 的特点和优点 Python 是一门开源的解释性语言,相比 Java C++ 等语言,...
  • 经典python面试

    2018-09-15 10:40:01
    经典Python面试题之Python基础篇,最基本的面试题,十分适合新手
  • 梦想橡皮擦写的 Python 面试系列文章清单

    万次阅读 多人点赞 2019-04-17 16:08:00
    互联网很多python面试分享的资料,但是都是对题目进行了非常简单的解读,我想针对每个面试题都深入并且细致的解释清楚,从这个出发点去帮助你建立python体系,所以有了这个系列的文章 Python基础面试,看这篇文章画...
  • python面试题汇总

    2019-12-11 13:37:03
    Python常见面试题汇总,里面收集了经常被问到的Python面试题,需要面试的朋友可以看看,非常的使用
  • 主要介绍了python面试题Python2.x和Python3.x的区别 ,在面试中也经常会问到,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • python面试经典题

    2018-09-10 14:59:22
    python面试经典考题2018,提高对知识点的复习。上传的版本为最新版,整理过的。
  • python面试题,,,python面试题,,,python面试题,,,
  • 2019最新BAT python面试

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,543
精华内容 10,617
关键字:

python面试

python 订阅