python-开发面试题(持续更新..)

python基础相关

 

python面向对象相关

 

网络编程相关

前端相关

 

数据库相关

 

Django相关

 

Linux相关

 

 

1. Python中__new__与__init__方法的区别

__new__: 构造方法

触发时机: 在实例化对时触发

参数:至少一个cls 接收当前类

返回值:必须返回一个对象实例

作用:实例化对象

注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。

__init__: 初始化方法

触发时机:初始化对象时触发(不是实例化触发,但是和实例化在一个操作中)

参数:至少有一个self,接收对象

返回值:无

作用:初始化对象的成员

注意:使用该方式初始化的成员都是直接写入对象当中,类中无法具有。

 

 

3.简要概述一下python中生成器和迭代器?

(1)迭代器:

迭代器协议:对象需要提供next()方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。

可迭代对象:实现了迭代器协议对象。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。但可以使用内建函数iter(),把这些都变成Iterable(可迭代器对象)。

for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,遇到StopIteration的异常后循环结束。

(2)生成器:

将列表生成式中[]改变为()数据结构会改变,从列表变为生成器;

列表受内存限制,所以没有必要创建完整的列表(节省大量内存空间),在python中我们可以采用生成器:边循环边计算的机制;

生成器是只能遍历一次的。生成器是一类特殊的迭代器。还能使用 def 定义函数,但是,使用yield而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

4.Python的垃圾回收机制(garbage collection)

(1)当gc模块的计数器达到阈值,垃圾自动回收

(2)当调用gc.collect(),垃圾收到回收

(3)程序退出的时候,python解释器来回收垃圾

5.函数装饰器的作用?

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

6.进程、线程的区别?

(1)定义的不同

进程是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

(2)区别

一个程序至少有一个进程,一个进程至少有一个线程。

线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线线程不能够独立执行,必须依存在进程中。

(3)优缺点

线程和进程在使用上各有优缺点:

线程执行开销小,但不利于资源的管理和保护;而进程正相反。

7.函数的闭包

闭包就是函数式编程的重要语法结构,提高了代码可重复实用性。使用特定或特殊的方式,将局部变量(内部函数)引入到全局环境中使用,这就是闭包操作。

8.Python里的拷贝

Copy浅拷贝,只拷贝父元素,deepcopy深拷贝,递归拷贝可变对象的所有元素

9.apache和nginx的区别

(1)nginx 相对 apache 的优点:

轻量级,同样起web 服务,比apache 占用更少的内存及资源

抗并发,nginx 处理请求是异步非阻塞的,支持更多的并发连接,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能

配置简洁

高度模块化的设计,编写模块相对简单

社区活跃

(2)apache 相对nginx 的优点:

rewrite ,比nginx 的rewrite 强大;

模块超多,基本想到的都可以找到;

少bug ,nginx 的bug 相对较多;

超稳定。

10.什么是事务?

事务(Transaction)是并发控制的基本单位。所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转帐工作:

从一个帐号扣款并使另一个帐号增款,这两个操作要么都执行,要么都不执行。所以,应该把他们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

事务四大特性:

原子性:事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行;

一致性:几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致;

隔离性:事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的;

持久性:对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

11. 主键和外键的区别?

主键在本表中是唯一的、不可唯空的,外键可以重复可以唯空;外键和另一张表的主键关联,不能创建对应表中不存在的外键。

12. 在数据库中查询语句速度很慢,如何优化?

(1)建索引 ;

(2)减少表之间的关联 ;

(3)优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据 量大的表排在前面 ;

(4)简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据 ;

(5)数据库做好读写分离。

 

14.tcp和udp的区别?

tcp是一种面向连接的、可靠的、基于字节流的传输层通信协议。是专门为了在不可靠的互联网络上提供一个可靠的端到端字节流而设计的,面向字节流。

udp(用户数据报协议)是iso参考模型中一种无连接的传输层协议,提供面向操作的简单不可靠的非连接传输层服务,面向报文。

它们之间的区别:

1、tcp是基于连接的,安全性高;udp是基于无连接的,安全性较低;

2、由于tcp是连接的通信,需要有三次握手、重新确认等连接过程,会有延时,实时性差;同时过程复杂,也使其易于被攻击;而udp无连接,无建立连接的过程,因而实时性较强,也稍安全;

3、tcp连接是点到点的电话接通通信;udp支持一对一、一对多、多对一、多对多的广播通信。

15.对if __name__ == 'main'的理解?

“ if __name__ == '__main__':”

在Python中分为两类:一种是直接执行,另外一种是作为模块时才被调用。

__name__ 作为模块的内置属性,即".py"文件的调用方式。如果等于“__main__"就直接执行本文件,如果是别的就是作为模块被调用。

16. http协议与https协议的区别?

http是超文本传输协议在互联网上应用最为广泛的一种网络协议,所有www文件都必须遵守这个标准,基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)连接。

https是超文本传输安全协议,是一种网络安全传输协议。http协议传输的数据都没有加密,一些私密的信息不安全,https经由超文本传输协议(http)进行通信,利用SSL/TLS来加密数据包,https开发的主要目的就是为了保护数据传输的安全性。

HTTPS和HTTP的区别:

1) https协议要申请证书到ca,需要一定经济成本

2) http是明文传输,https是加密的安全传输

3) 连接的端口不一样,http是80,https是443

4)http连接很简单,没有状态;https是ssl加密的传输,身份认证的网络协议,相对http传输比较安全。

17. Python解释器

当我们编写好了的Python代码的时,一.py为扩展名的文件,运行代码的时候,需要python解释器。解释器在执行的程序时,一条一条的解释成机器语言给计算机来执行。因为计算机只能识别机器语言(以二进制的形式)

18. 字典推导式和列表推导式

列表推导式:

格式:[变量 for 变量 in 列表]

普通的字典内涵

变量= {key:value for key,value in 字典.items()}

19.Python2和python3在使用super时区别:

20.python 列表去重(数组)的几种方法

方法1:用if语句判断,用append函数追加

输出结果:

方法二:

用set集合:

输出的结果:

21. 列举您使用过的python网络爬虫所用到的解析数据包

BeautifulSoup、pyquery、Xpath、lxml

22.python常用内置函数:

dir(对象名):返回一个列表,列出该对象所有的属性和方法;

help(函数名、方法名或对象):查看函数、方法或对象的帮助文档;

type(对象名):查看该对象的类型;

isinstance(对象, 类型):判断该对象是否是该类型,返回True或False;

range、input、print就不用多说了。

以上几个使用频率应当是最高的。更多函数,请导入模块”import builtins”,dir(builtins)查看。

23. python中的and、or、not逻辑运算符:

and、or、not两边的值会被放到布尔环境下,作比较

and运算如x and y:

x和y都为True时,那么返回最后一个值y

否则返回两个值中的第一个布尔值为假的值,从左往右运算

or运算如x or y:

只要有一个为真值,就返回第一个布尔值为真的值

如果都为假,返回最后一个布尔值为假的值,从左往右运算

not运算如not x:

当x的布尔值为True,返回False

当x的布尔值为False,返回True

24.参数按值传递和引用传递是怎样实现的?

Python中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法被改变。但是如果一个对象是可以被修改的,你可以改动对象。

25. python内置的数据类型有哪些?

list: 链表, 有序的项目, 通过索引进行查找, 使用方括号"[]"

dict: 字典, 字典是一组键(key)和值(value)的组合, 通过键(key)进行查找, 没有顺序, 使用大括号"{}"

str:字符串,用单或双引号括起来表示字符串

tuple: 元组, 元组将多样的对象集合到一起, 不能修改, 通过索引进行查找, 使用括号"()"

set: 集合,无序, 元素只出现一次, 使用"set([])",可实现列表快速去重,不过注意返回的是一个集合

int: 整数,如3

float:浮点数,如2.3

complex:复数,如complex(1,2) => 1+2j

可迭代(遍历)对象:list、dict、tuple、set、str

可变类型:list、dict、set,其余为不可变类型

list、tuple、str可通过索引获取当中的元素

set不支持索引查找,因为数据只出现一次, 它只关心数据是否出现, 不关心其位置。

26.python中search()和match()的区别

match从起始位置开始往后查找,返回第一个符合规则的

search任何位置开始往后查找,返回第一个符合规则的

27.redis中常用的5种数据类型?

Redis支持5种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

28.请描述一下try……except……else……finally执行的顺序?

try:

#尝试实现某个操作,

#如果没出现异常,任务就可以完成

#如果出现异常,将异常从当前代码块扔出去尝试解决异常

except 异常类型1:

#解决方案1:用于尝试在此处处理异常解决问题

except 异常类型2:

#解决方案2:用于尝试在此处处理异常解决问题

else:

#如果没有出现任何异常,将会执行此处代码

finally:

#管你有没有异常都要执行的代码

29.什么样的字段适合建立索引?

唯一、不为空、经常被查询的字段。

30. Xrange和range的区别是什么?

xrange用法与 range 完全相同。不同的是,xrange生成的不是一个list对象,而是一个生成器。

1.django和flash有什么区别?

2.开发过程中遇到的技术问题?

3.文档分布式存储熟悉吗?

4.关于docker熟悉吗?

5.斐波那契数列,使用python写出来?

6.实现服务器与业务直接的关系表 用ORm
7.如果实在高并发
8.介绍Restframwork及其中组件?
9.vue 使用
10.写冒泡排序
11.谈谈并发编程与网络编程
12.什么是消息队列和缓存机制
13.分库分表怎么操作 ,介绍下
14.前后端分离会有什么问题 我说的是跨域问题

15.装饰器在cbv和fbv中怎么使用?

16.具体的认证组件怎么写?

17.解释器怎么用?有什么类型?

18.Restframwork的序列化组件怎么用,具体实现方式,及用途?

19. django 的orm是怎么使用的?怎么用?有什么缺点?

你在项目中遇到最难的部分是什么,你是怎么解决的; 
你看过django的admin源码么;看过flask的源码么;你如何理解开源; 
MVC / MTV; 
缓存怎么用; 
中间件是干嘛的; 
CSRF是什么,django是如何避免的;XSS呢; 
如果你来设计login,简单的说一下思路; 
session和cookie的联系与区别;session为什么说是安全的; 
uWSGI和Nginx的作用; 

 

 

1.深拷贝和浅拷贝之间的区别是什么?

答:深拷贝就是将一个对象拷贝到另一个对象中,这意味着如果你对一个对象的拷贝做出改变时,不会影响原对象。在Python中,我们使用函数deepcopy()执行深拷贝,导入模块copy,如下所示:

import copy

b=copy.deepcopy(a)

而浅拷贝则是将一个对象的引用拷贝到另一个对象上,所以如果我们在拷贝中改动,会影响到原对象。我们使用函数function()执行浅拷贝,使用如下所示:

b=copy.copy(a)

2.Python基础数据类型(别看这个题目看起来简单,你未必能完全答对)

答:Python3 中有六个标准的数据类型:

1) Number(数字)2) String (字符串) 3)元组 4) 列表 5) 字典 6) set(集合)

3.列表和元组之间的区别是?

答:列表是可变的,而元组是不可变的

4.在Python中如何实现多线程?

答:一个线程就是一个轻量级进程,多线程能让我们一次执行多个线程。我们都知道,Python是多线程语言,其内置有多线程工具包。

几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程。
所有运行中的任务通常都会对应一个进程(Process)。当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配调度的一个独立单位。
一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。
线程在程序中是独立的,并发的执行流,而且线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高程序的运行效率。

5.解释一下Python中的继承

答:当一个类继承自另一个类,它就被称为一个子类/派生类,继承自父类/基类/超类。它会继承/获取所有类成员(属性和方法)。

继承能让我们重新使用代码,也能更容易的创建和维护应用。Python支持如下种类的继承:
单继承:一个类继承自单个基类
多继承:一个类继承自多个基类
多级继承:一个类继承自单个基类,后者则继承自另一个基类
分层继承:多个类继承自单个基类
混合继承:两种或多种类型继承的混合

6.在Python中是如何管理内存的?

答:Python有一个私有堆空间来保存所有的对象和数据结构。作为开发者,我们无法访问它,是解释器在管理它。但是有了核心API后,我们可以访问一些工具。Python内存管理器控制内存分配。

另外,内置垃圾回收器会回收使用所有的未使用内存,所以使其适用于堆空间。

7.解释Python中的help()和dir()函数

Help()函数是一个内置函数,用于查看函数或模块用途的详细说明:

import copy

help(copy.copy)

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

以下实例展示了 dir 的使用方法:

dir(copy.copy)

运行结果为:

[‘__annotations__’, ‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’, ‘__defaults__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__get__’, ‘__getattribute__’, ‘__globals__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__init_subclass__’, ‘__kwdefaults__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__name__’, ‘__ne__’, ‘__new__’, ‘__qualname__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’

8.当退出Python时,是否释放全部内存?

答案是No。循环引用其它对象或引用自全局命名空间的对象的模块,在Python退出时并非完全释放。

另外,也不会释放C库保留的内存部分。

9.请解释使用*args和**kwargs的含义,Python中自定义的函数如何传递动态参数?

当我们不知道向函数传递多少参数时,比如我们向传递一个列表或元组,我们就使用*args。def func(*args):

for i in args:

print(i)

func(3,2,1,4,7)

运行结果为:

3

2

1

4

7

在我们不知道该传递多少关键字参数时,使用**kwargs来收集关键字参数。

def func(**kwargs):

for i in kwargs:

print(i,kwargs[i])

func(a=1,b=2,c=7)

运行结果为:

a.1

b.2

c.7

动态参数使用*args或者*kwargs

10.请写一个Python逻辑,计算一个文件中的大写字母数量

import os

os.chdir('d:\\PythonWorkDir')

with open('testData.txt') as d:

count=0

for i in d.read():

if i.isupper():

count+=1

print(count)

运行结果:26

11.什么是负索引?

我们先创建这样一个列表:

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

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

mylist[-3]

运行结果:6

它也能用于列表中的切片:

mylist[-6:-1]

结果:[3, 4, 5, 6, 7]

12.如何以就地操作方式打乱一个列表的元素?

为了达到就地打乱列表元素的目的,可以从random模块中导入shuffle()函数。

from random import shuffle

shuffle(mylist)

mylist

运行结果:

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

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

Join()能让我们将指定字符添加至字符串中

','.join('12345')

运行结果:

‘1,2,3,4,5’

Split()能让我们用指定字符分割字符串

'1,2,3,4,5'.split(',')

运行结果:

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

14.怎么移除一个字符串中的空格?

调用Istrip()可以去除前导空格,如果我们想去除后缀空格,就用rstrip()方法。去除前后空格用strip()

15.怎样将字符串转换为小写或大写?

字符串转化为小写'string'.lower()

字符串转化为大写'string'.upper()

使用isupper()和islower()方法检查字符串是否全为大写或小写。

16.Python中的闭包是什么?

当一个嵌套函数在其外部区域引用了一个值时,该嵌套函数就是一个闭包。其意义就是会记录这个值。

def A(x):

def B():

print(x)

return B

A(7)()

结果:7

17.python中的装饰器?装饰器的作用?

装饰器是修饰其他函数的功能的函数,他们有助于让我们的代码更简短。
装饰器本质上是一个 Python函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验
等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

17.解释一下Python中的//,%和 ** 运算符

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

7//23

这里整除后会返回3.5。

同样地,执行取幂运算。ab会返回a的b次方

2**101024

最后,%执行取模运算,返回除法的余数

13%76

3.5%1.50.5

18.怎样获取字典中所有键的列表?

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

mydict={'a':1,'b':2,'c':3,'e':5}

mydict.keys()

运行结果:

dict_keys(['a', 'b', 'c', 'e'])

19.python中的字典,至少用两种方法取值与赋值

dict = {'name':'zhangsan','age':'18'}
# 字典中赋值的两种方法
dict['sex'] = '男'
dict = {'education':'本科'}
# dict['key'] = 'value' 这种给字典赋值的方式不会改变字典的ID;dict = {'key':'value'} 这种给字典赋值的方式会改变字典的ID;
# 从字典中取值的两种方法
print(dict['name'],dict.get('name'))
# 直接使用dict['key']时,如果对应的key不存在时,会导致报错keyerror,提示没有该key的值;
# 而是用dict.get('key') 则不会产生错误,解析器返回值如果存在就返回相应的value, 如果不存在就返回None.

20.元组的解封装是什么?

首先我们来看解封装:

mytuple=3,4,5

mytuple(3, 4, 5)

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

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

x,y,z=mytuple

x+y+z

得到结果12

21.a > b ? a :b 转化为Python的写法

a if a > b else b

22.python的字符串进行去重排序

s1 = set(s) #set可以去重
l1 = list(s1) # set转化为list
l1.sort() #sort进行排序
print(''.join(l1))

23.is 与 == 区别

is判断的是a对象是否就是b对象,是通过id来判断的。
==判断的是a对象的值是否和b对象的值相等,是通过value来判断的。

24.sort和sorted的区别

sort是应用在list上的方法,sorted可以对所有可迭代的对象(包括字符串)进行排序操作。
对于一个无序列表a,调用a.sort(),对a排序后返回a,sort()函数修改待排序的列表内容。
而对于一个无序列表a,调用sorted(a),对a排序后返回一个新的列表,对a无影响。

25.等长的两个列表合并到一个字典,要求:合并成{'A': 1, 'B': 2, 'C': 3},请用一行代码实现

keys = ["A", "B", "C"]
values = ["1", "2", "3"]
print(dict(zip(keys, [int(x) for x in values])))

26.合并两个列表并消除重复值

list_1 = ["a", "b", "c", "1", "A", "winning"]
list_2 = ["a", "python", "string"]
print(set(list_1 + list_2))
# 执行结果:{'c', 'winning', '1', 'string', 'b', 'a', 'python', 'A'}

27.已知一个列表,根据字典中的x ,由大到小排序这个列表

a = [{"x": 1, "y": 2}, {"x": 2, "y": 3}, {"x": 3, "y": 4}]
aa1 = sorted(a, key=lambda item: item["x"], reverse=True)
print(aa1)
# 执行结果:[{'x': 3, 'y': 4}, {'x': 2, 'y': 3}, {'x': 1, 'y': 2}]

28.简述你所知道的延时等待方式

强制等待:

  • 也叫线程等待, 通过线程休眠的方式完成的等待,如等待5秒: Thread sleep(5000),

隐式等待:

  • 通过implicitly Wait完成的延时等待,注意这种是针对全局设置的等待,如设置超时时间为10秒,使用了implicitlyWait后,如果第一次没有找到元素,会在10秒之内不断循环去找元素,如果超过10秒还没有找到,则抛出异常

显式等待:

  • 也称为智能等待,针对指定元素定位指定等待时间,在指定时间范围内进行元素查找,找到元素则直接返回,如果在超时还没有找到元素,则抛出异常

29.你在写自动化框架的时候,测试用例保存到哪里?用什么去读取?

测试用例保存到Excel中,使用第三方库openpyxI完成对Excel的操作,当然也可以使用pandas来操作

30.使用monkey测试到了bug怎么提交的?

monkey对APP进行我们在测试的时候,会利用adb shell monkey-p包名-f脚本-V-V -v >D:log.txt把日志输出到本地,并且将出现错误时候的日志截图,把日志截图以及bug描述提交到禅道,指派给对应的开发。但是在提交bug之前会手动去重现下这个bug。

31.用python写一个函数,将一个字符串中给定的子串字符按从小到大的输出,第一个字符的位置为0

  • 如: myOrder( abejykhsesm',2,5)
  • 输出: ehjky

def my_order(s, start, len):
# 先切片
s = s[start:start + len]
# 强制转换为列表
li = list(s)
# 排序
li.sort()
# 在拼接为字符串
res = "".join(li)
print("输出结果为:", res)
my_order("abcedfgh", 2, 4)
结果为:cdef

32.对输入的整数数组,输出数组元素中的最大值、最大值的个数、最小值和最小值的个数

函数名称: max_ and_ min(list)

输入参数: list整数数组

输出: list整数数组,有四个值,分别表示最大值、最大值的个数、最小值和最小值的个数

  • 示例: max and. min([1,4,21,5,6,1,1]) => [21,1,1,3]
  • max_ and. min(1]) => [1,1,1,1]

def max_and_min(a):
b = sorted(a, reverse=True)
max = b[0]
max_num = b.count(max)
min = b[-1]
min_num = b.count(min)
return [max, max_num, min, min_num]
a = [5, 5, 5, 4, 3, 2, 2]
print(max_and_min(a))
# 执行结果:[5, 3, 2, 2]

33.字符串右补齐,根据len长度补齐str到src中

函数名称: rpad(src,len,str)

输入参数::src原字符串, len目标字符串长度, str用来填充的字符串

输出:补齐后的字符串

示例:

  • rpad ("abcd",10,"12") =>"abcd121212"
  • rpad ("abcd",11,"12") =>"abcd1212121"
  • rpad ("abcd",10,"12") =>"abcd121212”
  • rpad ("abd",12,"0") =>*"bd0000000”
  • rpad ("abcd",12,") =>"abcd

def rpad(src, length,string):
while len(src) < length:
for i in string:
src += i
if len(src) >= length:
return "" + src
else:
return "" + src
print(rpad("abcd", 10, "12")) # 10位
print(rpad("bbbb", 11, "12")) # 11位
print(rpad("cccc", 12, "12")) # 12位
print(rpad("dddd", 13, "0")) # 13位
print(rpad("ffff", 13, " ")) # 13位有空格
# 执行结果:
abcd121212
bbbb1212121
cccc12121212
dddd000000000
ffff

34.列表和字典有什么区别?

答(1)获取元素的方式不同。列表通过索引值获取,字典通过键获取。

(2)数据结构和算法不同。字典是hash算法,搜索的速度特别快。

(3)占用的内存不同。

35.如何结束一个进程?

(1)调用terminate方法。

(2)使用subProcess模块的Popen方法

36.什么是ORM?为什么要用ORM?不用ORM会带来什么影响?

  • ORM框架可以将类和数据表进行对应,只需要通过类和对象就可以对数据表进行操作。
  • 通过类和对象操作对应的数据表,类的静态属性名和数据表的字段名一一对应,不需要写 SQL 语句。
  • ORM另外一个作用,是根据设计的类生成数据库中的表。

37.写一段代码,ping 一个 ip地址,并返回成功、失败的信息。

p = subprocess.Popen('ping -c 3 8.8.8.8', stdout=subprocess.PIPE, shell=True)

print(p.stdout.read())

38.怎么验证元素enable/disabled/checked状态?

定位元素后:分别通过isEnabled(),isSelected(),isDisplayed()三个方法进行判断。

39.解释一下Python的垃圾回收机制

我们从三个方面来了解一下Python的垃圾回收机制。

一、引用计数

Python垃圾回收主要以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_ref,用来记录当前对象被引用的次数,也就是来追踪到底有多少引用指向了这个对象,当发生以下四种情况的时候,该对象的引用计数器+1

对象被创建 a=14

对象被引用 b=a

对象被作为参数,传到函数中 func(a)

对象作为一个元素,存储在容器中 List={a,”a”,”b”,2}

与上述情况相对应,当发生以下四种情况时,该对象的引用计数器-1

当该对象的别名被显式销毁时 del a

当该对象的引别名被赋予新的对象, a=26

一个对象离开它的作用域,例如 func函数执行完毕时,函数里面的局部变量的引用计数器就会减一(但是全局变量不会)

将该元素从容器中删除时,或者容器被销毁时。

.当指向该对象的内存的引用计数器为0的时候,该内存将会被Python虚拟机销毁

引用计数法有很明显的优点:

  1. 高效
  2. 运行期没有停顿 可以类比一下Ruby的垃圾回收机制,也就是 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
  3. 对象有确定的生命周期
  4. 易于实现

原始的引用计数法也有明显的缺点:

 

维护引用计数消耗资源,维护引用计数的次数和引用赋值成正比,而不像mark and sweep等基本与回收的内存数量有关。

无法解决循环引用的问题。A和B相互引用而再没有外部引用A与B中的任何一个,它们的引用计数都为1,但显然应该被回收。

循环引用的示例

为了解决这两个致命弱点,Python又引入了以下两种GC机制。

 

二、标记-清除

针对循环引用的情况:我们有一个“孤岛”或是一组未使用的、互相指向的对象,但是谁都没有外部引用。换句话说,我们的程序不再使用这些节点对象了,所以我们希望Python的垃圾回收机制能够足够智能去释放这些对象并回收它们占用的内存空间。但是这不可能,因为所有的引用计数都是1而不是0。Python的引用计数算法不能够处理互相指向自己的对象。你的代码也许会在不经意间包含循环引用并且你并未意识到。事实上,当你的Python程序运行的时候它将会建立一定数量的“浮点数垃圾”,Python的GC不能够处理未使用的对象因为应用计数值不会到零。

这就是为什么Python要引入Generational GC算法的原因!

『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?

对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

在上图中,我们把小黑圈视为全局变量,也就是把它作为root object,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。

标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

正如Ruby使用一个链表(free list)来持续追踪未使用的、自由的对象一样,Python使用一种不同的链表来持续追踪活跃的对象。而不将其称之为“活跃列表”,Python的内部C代码将其称为零代(Generation Zero)。每次当你创建一个对象或其他什么值的时候,Python会将其加入零代链表:

“标记-清除”法是为了解决循环引用问题。可以包含其他对象引用的容器对象(如list, dict, set,甚至class)都可能产生循环引用,为此,在申请内存时,所有容器对象的头部又加上了PyGC_Head来实现“标记-清除”机制。任何一个python对象都分为两部分: PyObject_HEAD + 对象本身数据

检测循环引用

随后,Python会循环遍历零代列表上的每个对象,检查列表中每个互相引用的对象,根据规则减掉其引用计数。在这个过程中,Python会一个接一个的统计内部引用的数量以防过早地释放对象。

三、分代回收

先给出gc的逻辑:(重点)

分配内存

-> 发现超过阈值了

-> 触发垃圾回收

-> 将所有可收集对象链表放到一起

-> 遍历, 计算有效引用计数

-> 分成 有效引用计数=0 和 有效引用计数 > 0 两个集合

-> 大于0的, 放入到更老一代

-> =0的, 执行回收

-> 回收遍历容器内的各个元素, 减掉对应元素引用计数(破掉循环引用)

-> 执行-1的逻辑, 若发现对象引用计数=0, 触发内存回收

-> python底层内存管理机制回收内存

Python中, 引入了分代收集, 总共三个”代”. Python 中, 一个代就是一个链表, 所有属于同一”代”的内存块都链接在同一个链表中

用来表示“代”的结构体是gc_generation, 包括了当前代链表表头、对象数量上限、当前对象数量

posted @ 2020-10-20 12:10  断浪狂刀忆年少  阅读(218)  评论(0编辑  收藏  举报