面谈Python基础

面谈Python基础一

文章目录

1.什么是Python?

1)Python是一种解释型的语言

2)Python是动态类型语言

3)Python一切皆是对象

4)Python代码编写快,但是运行速度比编译语言要慢,我们可以优化代码,因为Python允许加入的C语言进行扩展

5)Python让困难的事情变的简单,使程序员更加专注与算法和数据结构的设计,不用注意底层的细节

2.解释解释型和编译型的区别

​ 计算机不能直接理解高级语言,所以必须要将高级语言翻译成机器语言,翻译的方式有两种一个是解释,一个是编译,两种方式只是编译的时间不同。

​ 用编译型的语言写的程序执行之前,需要一个准们编译过程,通过编译系统把高级语言翻译成机器语言,把源高级程序编译成为机器语言文件,比如windows下的exe文件,以后就可以直接运行而不需要编译了,因为翻译只做了一次,所以编译型语言的程序执行效率高,但是部分解释型语言的解释器通过在运行时动态优化代码,甚至能够使解释型语言的性能超过编译型语言

注 意 : 光 理 论 是 不 够 的 , 在 此 送 大 家 一 套 2020 最 新 P y t h o n 全 栈 实 战 视 频 教 程 , \color{#FF0000}{注意:光理论是不够的,在此送大家一套2020最新Python全栈实战视频教程,} ,2020Python 点击此处 免 费 获 取 一 起 进 步 哦 ! \color{#FF0000}{免费获取一起进步哦!}

img

​ 解释型,解释型写的程序不需要编译。解释型语言在运行的时候才翻译,比如VB语言,在执行的时候,专门有一个解释器能将VB语言翻译成机器语言。

​ 编译型与解释型,两者各有利弊。前者由于程序执行速度快,同等条件下对系统要求较低,因此像开发操作系统、大型应用程序、数据库系统等时都采用它,像C/C++、Pascal/Object Pascal(Delphi)等都是编译语言,而一些网页脚本、服务器脚本及辅助开发接口这样的对速度要求不高、对不同系统平台间的兼容性有一定要求的程序则通常使用解释性语言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。

3.Python解释器的种类以及特点?

CPython

  • c语言开发的 使用最广的解释器

IPython

  • 基于CPython之上的一个交互式计时器 交互方式增强 功能和CPython一样

PyPy

  • 目标时执行效率 采用JIT技术 对Python代码进行动态编译,提高执行效率

JPython

  • 运行在java上的解释器 直接把Python的代码编译成java字节码执行

IronPython

  • 运行在微软 .NET平台上的解释器 把Python编译成.NET的字节码

4.位和字节的关系?

1)位(bit):一个二进制数据0和1,是计算机传输的最小单位,8位组成一个字节

2)字节(byte):存储空间的计量单元,1个字节有8个Bit,而1024个字节又代表1k

3)一个英文占用一个字节

4)一个汉字占用两个字节

5)标点符号:中文占用两个字节,英文占用一个字节

5.请至少列举5个 PEP8 规范(越多越好)

PEP8就是写Python代码要遵循的一些规范

完整规范

1)变量命名规则:不能与关键字重名,必须以数字字母下划线组成,且不能以数字开头

2)导包的规则:推荐 import os import sys 不推荐一行写

3)缩进:每一级使用四个空格缩进,要么都是空格,要么都是TAB

4)注释:如果可能注释独占一行,避免逐行添加注释,避免没有一个注释

5)最大行度,所有行限制的最大字符数为79(文档注释限制在72)

6)字符串引号:在Python中,单引号和双引号字符串是相同的。PEP不会为这个给出建议。选择一条规则并坚持使用下去。当一个字符串中包含单引号或者双引号字符的时候,使用和最外层不同的符号来避免使用反斜杠,从而提高可读性。

6.通过代码实现进制的转换

二进制 bin() ob 八进制 oct() 0o 十六进制 hex() 0x

二进制转换成十进制:v = “0b1111011”

int(v,2)

十进制转换成二进制:v = 18

bin(v)

八进制转换成十进制:v = “0o11”

int(v,8)

十进制转换成八进制:v = 30

oct(v)

十六进制转换成十进制:v = “0x12”

int(v,16)

十进制转换成十六进制:v = 87

hex(v)

7.请编写一个函数实现将IP地址转换成一个整数。

如 10.3.9.12 转换规则为:

10 00001010

3 00000011

9 00001001

12 00001100

再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?

def Change(addr):
    str = ''
    addr = addr.split(".")
    for i in addr:
        a = bin(int(i))
        b = a[2:]
        l = 8 - len(b)
        c = l * '0'
        new = c + b
        str += new
    return int(str,2)

num = Change("10.2.1.2")
print(num)

8.python递归的最大层数?

# encoding:utf-8
__author__ = 'Fioman'
__date__ = '2018/11/19 11:23'

import sys

sys.setrecursionlimit(3000)


def foo(n):
    print(n)
    n += 1
    foo(n)


if __name__ == '__main__':
    foo(1)  # 打印到998,所以Python的默认递归层数是998
    # 但是可以通过设置,来改变递归层数的上限,但是也是上限也是有限制的.
    # 可以看到打印到2998

9.逻辑运算符题目

1  v1 = 1 or 3  
3  v2 = 1 and 3
0  v3 = 0 and 2 and 1
1  v4 = 0 and 2 or 1
1  v5 = 0 and 2 or 1 or 4
False v6 = 0 or Flase and 1

1)布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。(如果都为True则返回第二个,是False则返回False) 找False返回

2)布尔"或" - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。(返回不是0的数,如果都为True 则返回第一个,都为False返回第二个) 找True返回

3)布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。not x

都要先转换成bool进行运算

10.ascii、unicode、utf-8、gbk 区别?

1)ascii:是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646

8位一个字节,一个字节表示一个字符,最多只能表示256个字符

2)unicode:因为世界国家很多,每个国家都定义一套自己的编码标准,结果相互之间谁也不懂谁的编码,就无法进行很好的沟通交流,所以及时的出现了一个组织ISO(国际标准化组织)决定定义一套编码方案来解决所有国家的编码问题,这个新的编码方案就叫做Unicode。

unicode一般使用两个字节表示一个字符,特别生僻的字用四个字节表示

3)utf8:由于Unicode比较浪费网络带宽和硬盘,因此为了解决这个问题,就在Unicode的基础上,定义了一套编码规则(将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)),这个新的编码规则就是UTF-8,采用1-4个字符进行传输和存储数据。

可变长的编码方式,常用汉字占3个字节,生僻4-6个

4)gbk:由于ASCII编码不支持中文,因此,当中国人用到计算机时,就需要寻求一种编码方式来支持中文。
于是,国人就定义了一套编码规则:当字符小于127位时,与ASCII的字符相同,但当两个大于127的字符连接在一起时,就代表一个汉字,第一个字节称为高字节(从0xA1-0xF7),第二个字节为低字节(从0xA1-0xFE),这样大约可以组合7000多个简体汉字。这个规则叫做GB2312。

国内版本,一个中文字符 == 两个字节 英文是一个字节

10.字节码和机器码的区别?

字节码

  • 字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码

机器码

  • 机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到

11.三元运算规则以及应用场景?

格式:[on_true] if [expression] else [on_false]

通过一行书写让代码变得精炼,执行效率更高

12.列举 Python2和Python3的区别?

  1. Python3 对 Unicode 字符的原生支持。
    Python2 中使用 ASCII 码作为默认编码方式导致 string 有两种类型 str 和 unicode,Python3 只支持 unicode 的 string。Python2 和 Python3 字节和字符对应关系为:
  2. Python3 采用的是绝对路径的方式进行 import
    Python2 中相对路径的 import 会导致标准库导入变得困难(想象一下,同一目录下有 file.py,如
    何同时导入这个文件和标准库 file)。Python3 中这一点将被修改,如果还需要导入同一目录的文件必
    须使用绝对路径,否则只能使用相关导入的方式来进行导入。
  3. Python2 中存在老式类和新式类的区别,Python3 统一采用新式类。新式类声明要求继承 object,必须用新式类应用多重继承。
  4. Python3 使用更加严格的缩进。Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所
    以在缩进中可以同时允许 tab 和 space 在代码中共存。这种等价机制会导致部分 IDE 使用存在问题。
    Python3 中 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错:TabError:
    inconsistent use of tabs and spaces in indentation.

13.用一行代码实现数值交换:


a = 1

b = 2
a,b = b,a

14.Python3和Python2中 int 和 long的区别?

int(符号整数):通常被称为是整数或整数,没有小数点的正或负整数;

long(长整数):无限大小的整数,这样写整数和一个大写或小写的L

python2中有long类型
python3中没有long类型,只有int类型

15.xrange和range的区别?

1).range和xrange都是在循环中使用,输出结果一样。
2).range返回的是一个list对象,而xrange返回的是一个生成器对象(xrange object)。
3).xrange则不会直接生成一个list,而是每次调用返回其中的一个值,内存空间使用极少,因而性能非常好。

注意:Python 3.x已经去掉xrange,全部用range代替。

16.文件操作时:xreadlines和readlines的区别?

xreadlines返回的是一个生成器类型,python3已经没有改方法.

readlines返回的是一个列表: [‘hi\n’, ‘hi\n’, ‘hi’]

17.列举布尔值为False的常见值?

0 , [ ] , " , ( ) , { } ,None,False

18.字符串、列表、元组、字典每个常用的5个方法?

字符串

  • v = " abc" v = v.strip() 返回去除两变空白的字符串
  • v = “aeaeeea” v.count(‘e’) 返回字符串中出现e的次数
  • v = “10.2.1.2” v = v.split(".") 将字符串以 . 分割成数组
  • str.replace(old, new[, max]) v = “我是adc” a = v.replace(‘adc’,‘666’)
  • v.index(‘e’) 找到这个字符串的下标,多个时返回第一个
  • max(v) min(v)
  • v.startswith(‘a’) 是否以a开头
  • v.endswith(‘b’) 是否以b结尾
  • v.islower() 是否全是小写
  • v.isupper() 是否全是大写
  • v.istitle() 是否时首字母大写
  • v.rsplit() 从后往前进行分割
  • ’ . '.join(v) 用. 将一个可迭代的序列拼接起来

列表

列表是一个有序的可以通过索引修改读取数据的支持嵌套的可变的一个数据集合

  • a = []
  • a.append(4) 只能添加一个
  • a.count(1) 列表中 为1的数
  • a.extend([4,5,6])
  • a.index(3) 找到列表中数的索引
  • a.insert(0,2)
  • a.remove(3)
  • a.pop()
  • a.reverse()
  • a.sort()

元组

Python的元组与列表类似,不同之处在于元组的元素不能修改。

  • 创建元祖 tup = ()
  • 访问元组 tup[1:5]
  • 修改元组元素值不允许修改,但是可以对元组进行连接组合 tup = tup1 + tup2
tup1 = (1,2)
tup2 = ('1','2')
tup = tup1 + tup2 
(1,2,'1','2')
  • 删除元组 del tup
  • tuple(seq) 将列表转换成元组

字典

  • d = {‘name’:‘fuxi’,‘age’:18}
  • d.keys()
  • d.items()
  • d.values()
  • d.get(‘name’)
  • d.pop(‘age’)

19.lambda表达式格式以及应用场景?

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

add = lambda x,y : x+y

20.pass的作用?

  1. 空语句 do nothing
  2. 保证格式完整
  3. 保证语义完整

在编写一个程序时,暂时还没有想好思路就可以使用pass语句来站位,也可以当做是个标记

21.*arg和**kwarg作用

*arg会把多出来的位置参数转化为tuple

**kwarg会把关键字参数转化为dict

22.is和==的区别

Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)value(值)

is :Python身份运算符  a is b  id(a) = id(b)  判断id是否相等

==:Python比较运算符  比较对象是否相等,值类型都要相等  判断值是否相等

只有数值型和字符串型的情况下,a is b才为True,当a和b是tuple,list,dict或set型时,a is b为False。

23.简述Python的深浅拷贝以及应用场景?

  1. 浅拷贝指仅仅拷贝数据集合的第一层数据;深拷贝指拷贝数据集合的所有层。
    所以对于只有一层的数据集合来说深浅拷贝的意义是一样的,比如字符串,数字,还有仅仅一层的字典、列表、元祖等。

  2. 应用

    (1)对于 数字 和 字符串 而言:
    赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
    (2)对于 字典、列表、元组 而言:
    赋值时,内存地址不会变化;
    浅拷贝时,内存地址不会变化。因为python仅仅将第一层的内容在内存中新建了一份出来,字典第二层的列表并没有在内存中新建,所以你修改了新模版,默认模版也被修改了;
    深拷贝时,内存地址会变化。因为字典里面的第一层和里面嵌套的地址都已经变了,python将字典的所有数据在内存中新建了一份,所以如果你修改新的模版的时候老模版不会变;它里面嵌套多少层,就会拷贝多少层出来,但是最底层的数字和字符串地址不变

24.Python垃圾回收机制?

1)引用计数器为主

​ 环状双向链表 refchain

​ 在Python中创建的任何对象都会放在refchain链表中

name = 'bob' 内部存储[上一个对象、下一个对象、类型、引用的个数]
age = 18 内部存储[上一个对象、下一个对象、类型、引用的个数、value]
hobby = ['soccker'] 内部存储[上一个对象、下一个对象、类型、引用的个数、item=元素、元素的个数]
在C源码中如何体现每个对象中都有相同约值 PyObject结构体(4个值)
有多个元素组成的对象:PyObject结构体(4个值) + ob_size

​ 类型封装结构体

data = 3.14
内部创建
_ob_next  refchain的上一个对象
_ob_prev  refchain的下一个对象
ob_refcnt = 1
ob_type = float 
ob_fval = 3.14
v1 = 3.14
v2 = 999
v3 = (1,2,3)
当Python程序运行时,会根据数据类型不同找到其对应的结构体,根据结构体中的字段来进行创建相关的数据,然后将对象添加到refchain双线链表中
在C源码中有两个关键的结构体 PyObject PyVarObject
每个对象都有OB_refcnt就是引用计数器,值默认为1,当有其他变量引用,引用计数器就会发生变化

引用
a = 999
b = a

删除引用
a = 9999
b = a
del b  #b变量删除;b对应对象引用计数器-1
del a  #a变量删除;a对应对象引用计数器-1

#当一个对象的引用计数器为0时,意味着没有人在使用这个对象了,这个对象就是垃圾,垃圾回收
#回收:1.对象从refchain链表移除  2.将对象销毁,内存归还

2)标记清除 辅

循环引用&交叉感染
v1 = [1,2,3] ob_refcnt = 1
v2 = [3,4,5] ob_refcnt = 1
v1.append(v2)  ob_refcnt = 2
v2.append(v1)  ob_refcnt = 2

del v1 ob_refcnt = 1
del v2 ob_refcnt = 1
列表就不会被销毁,内存中一直有,内存不会回收 爆栈,循环引用导致内存泄漏

基于这个问题,标记清除就是为了解决引用计数其循环引用的不足
实现:在Python的底层再去维护一个链表,这个链表中专门放可能存在循环引用的对象(list、tuple、dict、set)
两个链表进行存储

在Python内部 某种情况下触发会去扫描存在循环引用链表中的每个元素,检查是否有循环引用,如果有则让双方引用计数其-1,如果时0则是垃圾回收

问题
什么时候扫描
可能存在循环引用的链表扫描代价大,每次扫描耗时久

3)分代回收 辅

将可能存在循环引用的对象维护成3个链表
0代:0代中的对象达到700个扫描一次
1代:0代扫描10次,则1代扫描一次
2代:1代扫描10次,则2代扫描一次

总结

在Python中维护了一个refchain的双向环状链表,这个链表中存储程序创建的所有对象,每种类型的对象中都有一个ob_refcnt引用计数器的值,引用个数+1、-1;最后当引用计数器变为0时会进行垃圾回收,对象销毁,refchain中移除)
但是,在Python中对于那些可以有多个元素组成的对象,可能还会存在循环引用的问题,为了解决这个问题,Python又引入了标记清除和分代回收,在其内部维护了4个链表
refchain
2代
1代
0代
在源码内部当达到各自的阈值时,就会触发扫描链表进行标记清除的动作(有循环则各自-1)

缓存机制

提出了优化机制,让Python的性能更高
缓存:池 (int str)
为了避免重复创建个销毁一些常见对象,维护一个池
启动解释器时,Python内部帮我们创建 -5 -4 .。。。。 257
v1 = 7 内部不会开辟内存 直接去池中获取
v2 = 9 

free_list(flaot/list/tuple/dict)
当一个对象的引用计数器为0时,按理说应该回收,内部不会直接会后,而是将对象添加到free_list链表中当缓存,以后在去创建对象时,不在重复开辟内存,而是直接使用free_list

v1 = 3.14 开辟内存,内部存储结构体中定义几个值,并存到reflchain中
del v1    reflchain中移除,将对象添加到free_list中
v9 = 999.99  不会重新开辟内存,去free_list中获取对象,对象内部数据初始化,在放到refchain中

Python的C源码

25.Python的可变类型和不可变类型?

可变类型:list/dict/set

不可变类型:数字/字符串/元祖

可变类型:
  • 可以修改对象的的值,修改后对象的内存地址不变(变量与内存地址链接:常量、变量、内存
  • 可变类型包括:列表、字典、可变集合
不可变类型
  • 值变了,内存地址就变了,等于重新定义
  • 在尝试修改对象元素时,实际上是重新开辟了内存空间来存储的
  • 不可变类型有:数值、元组、字符串、不可变集合
  • 对于不可变类型的对象,他们都没有涉及到修改的方法,尝试使用就会报错

26.求结果

v = dict.fromkeys(['k1','k2'],[])
v[‘k1’].append(666)
print(v)  #{'k1': [666], 'k2': [666]}
v[‘k1’] = 777
print(v)  #{'k1': 777, 'k2': [666]}

27.列举常见的内置函数?

1)abs()函数返回数字的绝对值。

2) all() 函数用于判断给定的参数中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False 外都算 True;空元组、空列表返回值为True。

3)callable()函数用于检查一个对象是否可调用的。对于函数、方法、lambda函式、类以及实现了 call 方法的类实例, 它都返回 True。(可以加括号的都可以调用)

4)dir()函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。

5)divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(商x,余数y)。

6)enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中

7)eval() 函数用来执行一个字符串表达式,并返回表达式的值。

8)exec() 执行储存在字符串或文件中的Python语句,相比于eval,exec可以执行更复杂的Python代码。

9) frozenset() 返回一个冻结的集合(一个无序的不重复元素序列),冻结后集合不能再添加或删除任何元素。

10).globals() 函数会以字典格式返回当前位置的全部全局变量。

  1. hash() 用于获取一个对象(数字或者字符串等)的哈希值。不能直接应用于 list、set、dictionary。

12) isinstance() 函数来判断一个对象是否是一个已知的类型,返回布尔值。类似 type()

13)import() 函数用于动态加载类和函数。如果一个模块经常变化就可以使用 import() 来动态载入。

28.filter、map、reduce的作用?

filter:筛选器,过滤满足条件的参数

>>> list(filter(lambda x:x>3,[3,24,1]))
[24]

map:将数据进行一一映射

>>> list(map(lambda x:x*2, [1,2,3,4]))
[2, 4, 6, 8]

reduce:一次将所有数据放进去进行求和

>>> reduce(lambda x,y:x+y,[0,1,2,3,4,5,6])
21

29.一行代码实现9*9乘法表

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)))

30.至少列举8个常用模块都有那些?

os

json

sys

random

time

requests

re

Django

pymysql

31.re的match和search区别?

>>> print(re.match('hello','worldhello'))
None

>>> print(re.search('hello','worldhello'))
<re.Match object; span=(5, 10), match='hello'>

>>> print(re.search('hello','worldhello').span())
(5, 10)
span()函数返回 (start(group), end(group))

match只会在0位置上进行匹配

search会扫描整个字符串并返回第一个成功的匹配

32.什么是正则的贪婪匹配?

贪婪匹配:尝试匹配尽可能多的字符

非贪婪匹配:尝试匹配尽可能少的字符

.* 和 .*?

33.def func(a,b=[]) 这种写法有什么坑?

​ 函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] ,想每次执行只输出[1] ,默认参数应该设置为None。

34.如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?

>>> a = "1,2,3"
>>> a.split(',')
['1', '2', '3']

35.如何实现[‘1’,’2’,’3’]变成[1,2,3] ?

>>> list(map(int,['1','2','3']))
[1, 2, 3]

36.比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?

a = [1,2,3]  #列表形式 元素是Int类型
b = [(1),(2),(3) ] #列表中 元素也是Int类型
b = [(1,),(2,),(3,) ] #列表中的元素是tuple类型

37.如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?

>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

38.一行代码实现删除列表中重复的值 ?

>>> a = [1,2,1,4,5]
>>> set(a)
{1, 2, 4, 5}

39.如何在函数中设置一个全局变量 ?

在函数的内部,通过global声明,使在函数内部中设置一个全局变量,这个全局变量可以在任意的函数中进行调用!

40.logging模块的作用?以及应用场景?

日志模块: 用来记录用户的行为 或者 代码执行的过程

作用:可以了解程序的运行情况是否正常,在程序出现故障快速定位出错地方以及故障分析.

使用

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='/tmp/test.log',
                    filemode='w')
logging.debug('debug message') # 低级别的,调试信息
logging.info('info message') # 正常信息
logging.warning('warning message') # 警告信息
logging.error('error message') # 错误信息
logging.critical('critical message') # 高级别的 # 严重错误信息

# 配置相关
# basicconfig 简单 能做的事情少

# 配置log对象,稍微有点复杂 能做的事情相对多

配置

logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。
若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

logger对象配置

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8') 

# 再创建一个handler,用于输出到控制台 
ch = logging.StreamHandler() 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)

fh.setFormatter(formatter) 
ch.setFormatter(formatter) 
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 
logger.addHandler(ch) 

logger.debug('logger debug message') 
logger.info('logger info message') 
logger.warning('logger warning message') 
logger.error('logger error message') 
logger.critical('logger critical message')

41.请用代码简答实现stack 。

栈和队列是两种基本的数据结构,同为容器类型

class Stack(object):
    def __init__(self):
        self.stack = []

    def push(self, value):    # 进栈
        self.stack.append(value)

    def pop(self):  #出栈
        if self.stack:
            self.stack.pop()
        else:
            raise LookupError('stack is empty!')

    def is_empty(self): # 如果栈为空
        return bool(self.stack)

    def top(self): 
        #取出目前stack中最新的元素
        return self.stack[-1]

42.常用字符串格式化哪几种?

1.最方便的 %s

print('hello %s'%('bob'))

2.最好用的 以字典的方式,缩短时间

print('hello %(name)s'%{'name':'bob'})

3.最先进的 可读性强

print('hello {}'.format('bob'))

43.简述 生成器、迭代器、可迭代对象 以及应用场景?

迭代器协议:对象需要提供next方法,一直迭代下一项知道出现StopIteration异常,终止迭代

可迭代对象:可以直接作用于for循环的叫可迭代对象,在一个对象的方法中必须有 iter()

迭代器:在对象中有 iter() 和 next() 这两个方法的对象就是迭代器

优点:迭代器可以很好的减少内存在Python内部的机制就是当你取到一个值的时候,Python才会在内存中去创建空间

生成器:在函数的内部如果有yield的关键字,那么我们就说这个函数是个是个生成器函数,调用这个函数的方法返回的就是,生成器(生成器本本身也是一个迭代器)

44.用Python实现一个二分查找的函数。

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
def binary_search(dataset,find_num):
    if len(dataset) > 1:
        mid = int(len(dataset) / 2)
        if dataset[mid] == find_num:
            print("找到数字", dataset[mid])
        elif dataset[mid] > find_num:
            return binary_search(dataset[0:mid], find_num)
        else: 
            return binary_search(dataset[mid + 1:], find_num)
    else:
        if dataset[0] == find_num:  
            print("找到数字啦", dataset[0])
        else:
            print("没的分了,要找的数字[%s]不在列表里" % find_num)

binary_search(data,20)

45.谈谈你对闭包的理解?

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的医用,这样就构成了一个闭包

def outer():
	a = 1
	def inner():  #inner是一个闭包
		print(a)  #不用a就是一个嵌套函数 
    print(inner.__closure__)  #出现cell就是一个闭包
    return inner
inn = outer()
inn()

可以节省资源
    

46.os和sys模块的作用?

os:这个模块提供给了一种方便使用操作系统函数的方法

sys:这个模块可提供由解释器使用或维护变量和解释器进行交互的函数

47.如何生成一个随机数?

使用random模块

random.random():生成一个0-1之间的随机浮点数
random.uniform(a,b):生成[a,b]之间的浮点数
random.randint(a,b):生成[a,b]之间的整数
random.randrange(a,b,step):在指定集合[a,b)中,以step为基数随机生成一个数
random.choice(seq):从指定序列中随机取一个元素,这里的序列可以是字符串、列表、元组等

48.如何使用python删除一个文件?

使用os模块

import os
os.remove(path) :删除单个文件

os.removedirs(path) :递归删除目录下的文件

49.谈谈你对面向对象的理解?

​ 面向对象就是将现实世界中的所有事物进行抽象出来,所以在Python中一切皆是对象,在现实中每一类物品都可以给它做一个划分,每一个个体则是这一类事物的实例。面向对象以对象为核心,以消息作为驱动,所以程序=对象+消息

​ 其中面向对象有三大特性,封装、继承和多态

​ 封装就是将一类事物的属性和行为抽象为一个类,使其属性私有化,行为公开化,提高了数据的隐秘性的同时,也大大减少了开发过程中出现代码冗余的问题

​ 继承则是进一步将一类事物共有的属性和行为抽象成一个父类,而每一个子类是一个特殊的父类,有父类的行为和属性,也有自己的行为和属性,这样可以扩展已存在的代码块,进一步提高代码的复用

​ 多态是指一类事物有多种形态,比如动物类,可以有猫,狗,猪等等。(一个抽象类有多个子类,因而多态的概念依赖于继承)

多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。多态性就是一个接口多个实现

​ 多态性的好处:

  • 增加了程序的灵活性,以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(obj)
  • 增加了程序额可扩展性,通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(obj)去调用

50.Python面向对象中的继承有什么特点?

继承的优点

  • 建造系统中的类,避免重复操作
  • 新类经常是基于已经存在的类,这样就可以提升代码的复用程度

继承的特点

  • 在继承中基类的构造(init()方法) 不会被自动调用,它需要在其派生类的构造中亲自专门调用
  • 在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
  • Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找
  • 减少代码和灵活制定新类
  • 子类具有父类的属性和方法
  • 子类可以添加新的方法
  • 子类可以修改父类的方法

51.面向对象深度优先和广度优先是什么?

​ Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种: 当类是经典类时,多继承情况下,会按照深度优先方式查找 py3 ;当类是新式类时,多继承情况下,会按照广度优先方式查找 py2

简单点说就是:经典类是纵向查找,新式类是横向查找

经典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。

在python3中默认全是新式类

52.面向对象中super的作用?

super()函数时用于调用父类(超类)的一个方法

super是用来解决多重继承问题,在多继承中涉及查找顺序(MRO)、重复调用(钻石调用)等种种问题

MRO就是类的方法解析顺序表,其实也就是继承父类方法时的顺序表

class Parent:
	def __init(self,node):
		self.node = node
		self.next = None

class Son(Parent):
	def __init__(self):
		super().__init__() #这样子类就继承了父类的初始化方法

53.是否使用过functools中的函数?其作用是什么?

​ functools用于高阶函数:指那些作用于函数或者返回其他函数的函数。通常情况下,只要是可以被当做函数调用的对象就是这个模块的目标

1)partial:它可以重新绑定函数的可选参数,生成一个callable的partial对象
>>> from functools import partial
>>> a = partial(int,base=2)
>>> a
functools.partial(<class 'int'>, base=2)
>>> a('10')
2
>>> a('1')
1
其效果和 int('10') int('10',2) 是相同的

54.列举面向对象中带爽下划线的特殊方法,如:newinit

new:生成实列,为对象分配空间

init:初始化实例的属性

call:实例对象加()会执行def call:方法中的内容

55.如何判断是函数还是方法?

可以用内置的isinstance 来判断

isinstance(对象名,FunctionType)
isinstance(对象名,MethodType)

函数:封装了一些独立的功能,可以直接调用,python内置了许多函数,同时可以自建函数来使用

方法:同样封装了独立的功能,但是方法是需要通过对象来调用,表示针对这个对象要做的操作,使用时采用点方法

56.静态方法和类方法区别?

逻辑区别:类方法是只能由类名调用;静态方法可以由类名或对象名进行调用

57.列举面向对象中的特殊成员以及应用场景

1.__doc__:描述类的信息
2.__call__:对象后面加括号,触发执行
3.__dict__:查看类或对象中的所有成员
4.__str__:如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
5.__getitem__、__setitem__、__delitem__用于索引操作,分别表示获取、设置、删除数据
6.__new__:为对象分配空间,返回对象的引用

58.1、2、3、4、5 能组成多少个互不相同且无重复的三位数

59.什么是反射?以及应用场景?

​ Python面向对象中的反射: 通过字符串的形式操作对象相关的属性,python中的一切事物都是对象(都可以使用反射),利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员(自省),一种基于字符串的事件驱动。通俗来讲就是反射就像我们日常照镜子一样,通过镜子的反射,我们可以进行整理衣服,或者将原来的衣服去除。这个过程就称之为反射。

60.metaclass作用?以及应用场景?

61.用尽量多的方法实现单例模式。

1)模块单列:Python的模块就是天然的单例模式,因为模块在第一次导入时就会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码

#foo1.py
class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()


#foo.py
from foo1 import singleton

2)静态变量方法:先执行类的__new__方法(我们没写时,默认调用 object.__new_),实例化对象;然后在执行类的 __init__方法,对这个对象进行初始化,所有我们可基于这个,实现单例模式

class Singleton(object):
    def __new__(cls,a):
        if not hasattr(cls, '_instance'):
            cls._instance = object.__new__(cls)
        return cls._instance
    def __init__(self,a):
        self.a = a
    def aa(self):
        print(self.a)


a = Singleton("a")
复制代码

变种:利用类的静态方法,实现对函数初始化的控制。该方法需要手动调用静态方法实现实例。本质上是手动版的__new__方法

3)元类方法:此方法是在__new__方法的更上层对实例化过程进行控制。

原理:执行元类的 元类的__new__方法和__init__方法用来实例化类对象,call 方法用来对实例化的对象的实例即类的对象进行控制。__call__方法会调用实例类的 __new__方法,用于创建对象。返回对象给__call__方法,然后调用类对象的 __init__方法,用于对对象初始化。

class Singleton1(type):
    def __init__(self, *args, **kwargs):
        self.__instance = None
        super(Singleton1,self).__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton1,self).__call__(*args, **kwargs)
        return self.__instance

class Singleton2(type):
    _inst = {}
    def __call__(cls, *args, **kwargs):
        print(cls)
        if cls not in cls._inst:
            cls._inst[cls] = super(Singleton2, cls).__call__(*args)
        return cls._inst[cls]

class C(metaclass=Singleton1):
    pass

4)装饰器:装饰器用来控制类调用 __call__方法

def singleton(cls, *args, **kw):
    instance = {}
    def _singleton(args):
        if cls not in instance:
            instance[cls] = cls(*args, **kw)
        return instance[cls]
    return _singleton

@singleton
class A:
    pass

62.装饰器的写法以及应用场景。

装饰器的原则:传入的对象作为参数,其实传递的就是那个对象的内存地址

def func():     #被装饰的函数
	time.sleep(10)
	print()
	
def timer(f):   #wrapper装饰
	def inner(*args,**kwargs):
		start = time.time()
		ret = f(*args,**kwargs)  #别装饰的函数  可以包括整个世界
		end = time.time()
		return ret
	return inner #如果在这里执行将会出现 None 将会报错
	
func = timer(func)  #加上 @timer
ret = func()   #这个执行的就相当于执行Inner()
print(ret)


#带参数函数的装饰器
@timer    func = timer(func)
def func(a):     #被装饰的函数
	time.sleep(10)
	print()
ret = func(a)  #此时的func已经是内部的对象了,称为了inner对象

应用场景:http://c.biancheng.net/view/5410.html

  • 装饰器用于身份认证
  • 装饰器用于日志记录
  • 装饰器用于输入合理性检查
  • 缓存装饰器

63.异常处理写法以及如何主动跑出异常(应用场景)

# 触发异常
def temp_convert(var):
    try:
        return int(var)
    except ValueError as Argument:
        print ("参数没有包含数字%s"%Argument)

# 调用函数
temp_convert("xyz")
# 以10为基数的int()的无效文字:“xyz”
----------------------------------------------------------------------------
# raise语法
#raise [Exception [, args [, traceback]]]
# 语句中 Exception 是异常的类型,args 是自已提供的异常参数。

class Networkerror(RuntimeError):
    def __init__(self, arg):
        self.args = arg
try:
    raise Networkerror("Bad hostname")
except Networkerror as e:
    print(e.args)

通过raise 异常对象主动抛出异常

64.什么是面向对象的mro

Method Realtion Order 用来制作一个继承关系的列表

MRO列表的制作原则:
1.子类永远在父类的前面
2.如果继承了多个父类,那么按照()中的顺序在列表中摆放
3.如果多个类同时继承了一个父类,孙子类中只会选取第一个父类中的父类的该方法

65.isinstance作用以及应用场景?

isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。

语法:isinstance(object, classinfo)
object:实例对象
classinfo:可以是直接或间接类名、基本类型或者由他们组成的元组

>>>a = 2
>>> isinstance (a,int)
True
>>> isinstance (a,str)
False
>>> isinstance (a,(str,int,list))    # 是元组中的一个返回 True
True

isinstance(对象名,FunctionType)
isinstance(对象名,MethodType)

66.json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?

#自定义时间序列化转换器
import json
from json import JSONEncoder
from datetime import datetime
class ComplexEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        else:
            return super(ComplexEncoder,self).default(obj)
d = { 'name':'alex','data':datetime.now()}
print(json.dumps(d,cls=ComplexEncoder))
# {"name": "alex", "data": "2018-05-18 19:52:05"}

67.json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

json.dumps({},ensure_ascii=False)

68.什么是断言?应用场景?

Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。例如:

>>> x = -1
>>> assert x > 0 ,"x is noe"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: x is noe

并不是任何错误都要使用assert进行报错

断言应该用于

  • 防御型编程
  • 运行时检查程序逻辑
  • 检查约定
  • 程序常量
  • 检查文档

69.有用过with statement吗?它的好处是什么?

with语句使用所谓的上下文管理器对代码块进行包装,允许上下文管理器实现一些设置和清理操作。

例如:文件可以作为上下文管理器使用,它们可以关闭自身作为清理的一部分。

70.使用代码实现查看列举目录下的所有文件。

a = os.path.abspath('.') #返回当前的绝对路径
b = os.listdir(a) #查看该目录下的所有文件
for i in b:
	c = os.path.join(a,i) #拼接成新路径
	os.path.isfile(c) #判断是否为文件 

71.简述 yield和yield from关键字。

yield:每次迭代时值加载这一个元素,而且替换掉之前的那一个元素,这样就大大节省了内存。而且程序在遇见yield语句时会停下来,这是后面使用yield阻断原理进行多线程编程的一个启发

yield from iterable本质上等于 for item in iterable: yield item的缩写版
ncoder
from datetime import datetime
class ComplexEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        else:
            return super(ComplexEncoder,self).default(obj)
d = { 'name':'alex','data':datetime.now()}
print(json.dumps(d,cls=ComplexEncoder))
# {"name": "alex", "data": "2018-05-18 19:52:05"}

67.json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

json.dumps({},ensure_ascii=False)

68.什么是断言?应用场景?

Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。例如:

>>> x = -1
>>> assert x > 0 ,"x is noe"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: x is noe

并不是任何错误都要使用assert进行报错

断言应该用于

  • 防御型编程
  • 运行时检查程序逻辑
  • 检查约定
  • 程序常量
  • 检查文档

69.有用过with statement吗?它的好处是什么?

with语句使用所谓的上下文管理器对代码块进行包装,允许上下文管理器实现一些设置和清理操作。

例如:文件可以作为上下文管理器使用,它们可以关闭自身作为清理的一部分。

70.使用代码实现查看列举目录下的所有文件。

a = os.path.abspath('.') #返回当前的绝对路径
b = os.listdir(a) #查看该目录下的所有文件
for i in b:
	c = os.path.join(a,i) #拼接成新路径
	os.path.isfile(c) #判断是否为文件 

71.简述 yield和yield from关键字。

yield:每次迭代时值加载这一个元素,而且替换掉之前的那一个元素,这样就大大节省了内存。而且程序在遇见yield语句时会停下来,这是后面使用yield阻断原理进行多线程编程的一个启发

yield from iterable本质上等于 for item in iterable: yield item的缩写版

细品,相信你会收获一些知识,上面并没有太深入,如果感兴趣可以进行查询,继续学习。

注 意 : 最 后 送 大 家 一 套 2020 最 新 企 业 P y h o n 项 目 实 战 视 频 教 程 , \color{#FF0000}{注意:最后送大家一套2020最新企业Pyhon项目实战视频教程,} 2020Pyhon 点击此处 免 费 获 取 一 起 进 步 哦 ! \color{#FF0000}{免费获取一起进步哦!}

在这里插入图片描述

  • 9
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值