1. Python为什么是解释型语言
**编译型语言:**一些编程语言要求必须提前将所有源代码一次性转换成二进制指令,就是生成一个可执行程序(Windows 下的 .exe)。比如C语言、C++、Golang、Pascal(Delphi)等,这种编程语言称为编译型语言,使用的转换工具称为编译器。
**解释型语言:**一些编程语言可以一边执行一边转换,需要哪些源代码就转换哪些源代码,不会生成可执行程序。比如 Python、JavaScript、PHP、Shell 等,这种编程语言称为解释型语言,使用的转换工具称为解释器。
2. 面向对象和面向过程的区别
面向对象是把构成问题的事务分解成各个对象,建立对象来描述某个事务在解决问题的步骤中的行为;
面向过程是分析出解决问题所需要的步骤,然后用一些函数把这些步骤一步步实现,使用的时候依次调用函数就行了。
3. Python有什么优点和缺点
解释型,语法简单易懂,可读性强;
有很多库可以用,可以让我们站在巨人的肩膀上简单的实现想要的功能;
可扩展,和其他编程语言或其他软件有可连接的接口;
免费开源、可移植;
自动内存管理,让程序员可以专注于代码的实现;
缺点:
他的可解释特征使其运行速度变慢;
动态语言的特点可能会增加运行时错误。
4. 装饰器
python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
一般情况下调用装饰器:
import time
def decorator(func):
def wrapper():
print(time.time()) #先执行
func()#返回值(一个函数) 再执行函数f1结果如下
return wrapper
#以上内容就是一个装饰器,即wrapper被decorator包裹起来,像一个装饰器
def f1():
print('This is a function')
f=decorator(f1)
f()
#运行结果为
# 1533530657.8872964
#This is a function
'相当于执行了wrapper里面的内容'
注:A、 @符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作。
有了语法糖之后调用装饰器,可以直接调用,不需要加小括号了:
'如果一个装饰器只能完成一个函数的使用,那将失去意义,所以我们要实现未知函数参数个数的调用'
import time
def decorator(func):
def wrapper(*args):#*args为可变参数
print(time.time())
func(*args)
return wrapper
@decorator
def f1(func_name):
print('This is a function '+func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function '+func_name1)
print('This is a function '+ func_name2)
f1('test1')
f2('test2','test2')
#运行结果为
#1533534463.567321
#This is a function test1
#1533534463.567321
#This is a function test2
#This is a function test2
B、python的三个内置函数:
@classmethod:类方法,类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python为我们内置了函数classmethod来把类中的函数定义成类方法。
@staticmethod:静态方法用上面两个装饰器就可以不用在实用类前对类进行实例化了,
@property:将一个实例方法提升为属性,便于访问
5. 深拷贝、浅拷贝和等号赋值
**深拷贝:**原对象的外层/内层元素地址都变化。
**浅拷贝:**原对象的外层元素地址变化,内层元素的地址不变。这个就好理解了,前女友对你彻底死心,无论你怎么变都不要你了。
**复制:**原对象怎么变,我跟着变。
对复制/浅拷贝/深拷贝的对象进行改变,看原对象的变化:
import copy
a = [1, 2, [3, 4]]
print('原对象a: ',id(a), a)
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
b[0] = 9
print('对复制进行改变后的a:',id(a), a)
c[1] = 10
c[2].append(11)
print('对浅拷贝进行改变后的a:',id(a), a)
d[2].append(12)
print('对深拷贝进行改变后的a:',id(a), a)
#结果
原对象a: 2535141215304 [1, 2, [3, 4]]
对复制进行改变后的a: 2535141215304 [9, 2, [3, 4]]
对浅拷贝进行改变后的a: 2535141215304 [9, 2, [3, 4, 11]]
对深拷贝进行改变后的a: 2535141215304 [9, 2, [3, 4, 11]]
对可变对象进行复制、浅/深拷贝:
import copy
a = [1, 2, [3, 4]]
print("变化前的a",id(a), a)
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
a[1] = 5
a[2].append(6)
a.append(7)
print('变化后的a',id(a), a)
print('复制',id(b), b)
print('浅拷贝',id(c), c)
print('深拷贝',id(d), d)
#结果
变化前的a 2178310605896 [1, 2, [3, 4]]
变化后的a 2178310605896 [1, 5, [3, 4, 6], 7]
复制 2178310605896 [1, 5, [3, 4, 6], 7]
浅拷贝 2178310716424 [1, 2, [3, 4, 6]]
深拷贝 2178310715400 [1, 2, [3, 4]]
6. 在python中如何实现多线程和多进程
**多进程:**multiprocessing模块。
**多线程:**python中常用threading模块实现多线程。可以用GIL实现线程通信。
7. GIL(全局解释锁)
全局解释器锁[Global Interpreter Lock]是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即便在多核处理器上,使用 GIL 的解释器也只允许同一时间执行一个线程。可以看到GIL并不是Python独有的特性,是解释型语言处理多线程问题的一种机制而非语言特性。
8. 类
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
9. 类的继承
当一个类继承自另一个类,它就被称为一个子类/派生类,继承自父类/基类/超类。它会继承/获取所有类成员(属性和方法)。
10. Python如何内存管理
Python的内存管理主要有三种机制:引用计数机制,垃圾回收机制和内存池机制。
**引用计数机制:**python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
**垃圾回收:**python会检查引用计数为0的对象,清除其在内存占的空间;循环引用对象则用一个循环垃圾回收器来回收。
**内存池机制:**在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
1.Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
2.Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
3.Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。
4.对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
11. Python垃圾回收机制
(自动处理分配回收内存的问题,没用了内存泄漏的隐患),以引用计数机制为主,标记-清楚和分代收集两种机制为辅
计数机制就是python中的每一个对象都有一个引用计数的值,当有引用的时候,这个值会增加,引用他的对象被删除时,这个值减小,引用计数的值为0时,该对象生命结束,python会把这段内存自动回收。(缺点,循环引用,如果l1和l2相互引用,没用其他的对象引用他们,这两段内存永远无法被回收。
12. 猴子补丁
猴子补丁仅指在运行时动态改变类或模块,为的是将第三方代码打补丁在不按预期运行的bug或者feature上 。在运行时动态修改模块、类或函数,通常是添加功能或修正缺陷。猴子补丁在代码运行时内存中发挥作用,不会修改源码,因此只对当前运行的程序实例有效。
13. Python 的四种共享传参
Python 唯一支持的参数传递方式为共享传参(call by sharing),传递参数一共有四种传递方式,分别为:位置参数,默关键字参数和可变参数,其中可变参数分为两种(*args 和 **kargs)。
**1、位置参数:**函数调用时,参数会根据函数定义的参数位置而自动传递。
def func(a, b):
print(a)
print(b)
return a+b
>>func("A", "B")
A
B
'AB'
>>func("B", "A")
B
A
'BA'
在上述实例中,我们发现参数的传递必须严格按照参数的定义位置进行传递的,而且函数的参数与调用函数所传递的参数数量不一致时,就会引发TypeError。
**2、默认参数:**函数调用时,为函数的某个参数提供默认值,调用函数时可选择不传入改参数的值。
def func(a="B", b):
print(a)
print(b)
return a+b
SyntaxError: non-default argument follows default argument
def func(a, b="A"):
print(a)
print(b)
return a+b
>>func("A")
A
A
'AA'
>>func("A", "B"):
A
B
"AB"
从上述实例中,我们发现默认参数必须在位置参数的后面。个人认为默认参数是位置参数的一种缺省形式。这也可以解释为何默认参数必须在位置参数的后面。
**3、关键字参数:**在进行函数调用时,使用 “参数名”=“值” 的形式进行参数指定。清除位置参数在调用时的顺序要求。
def func(a, b):
print(a)
print(b)
return a+b
>>func(b="B", a="A")
A
B
"AB"
def func(a, b="B"):
print(a)
print(b)
return a+b
>>func(a="A")
A
B
'AB'
>>func(a="A", b="C"):
A
B
'AC
**4、可变参数:**可变参数是指在函数定义时使用 *args (*加参数名)和 **kargs (**加参数名)的形式作为参数,在函数调用时就可以传入多个参数,会在实际工程中更加灵活,其中 args 对应着传入多个位置参数,**kargs 对应传入多个关键字参数。
不知道向函数传递多少参数时,比如传递一个列表或元组,就使用args
def func(*args):
print(type(args))
print(args)
for i in args:
print(i)
>>func("A", "B")
<class 'tuple'>
('A', 'B')
A
B
>>> func()
<class 'tuple'>
()
不知道该传递多少关键字参数时,使用**kwargs来收集关键字参数(keyword argument)。
def func(**kargs):
print(type(kargs))
print(args)
for key, value in kargs.items():
print("%s : %s" % (key,value) )
>>> func(a="A", b="B")
<class 'dict'>
{'a': 'A', 'b': 'B'}
a : A
b : B
>>> func(b="B", a="A")
<class 'dict'>
{'b': 'B', 'a': 'A'}
b : B
a : A
>>> func()
<class 'dict'>
{}
14. 全局变量和局部变量
全局变量:在整个程序范围内都可以访问,定义在函数外的拥有全局作用域的变量。global 关键字
局部变量:只能在其被声明的函数范围内访问,定义在函数内部的一个拥有局部作用域的变量。Local关键字
解析:下例中全局变量name的值没有发生改变,原因是python认为changeName中的name是局部变量,所以全部都是Deris。
name = "Deris"
def sayHello():
print ("hello "+name + "!"")
def changeName(newName):
name = newName
#调用函数
sayHello ()
changeName ("Weng")
sayHello()
输出结果:
hello Deris!
hello Deris!
解析:下例中全局变量name的值发生改变,原因是global把changeName中的name变成全局变量
name = "Deris"
def sayHello():
print ("hello "+name + "!")
def changeName(newName):
global name
name = newName
#调用函数
sayHello ()
changeName ("Weng")
sayHello()
输出结果:
hello Deris!
hello Weng!
15. 常用的方法
1、
16. 模块、库和包
模块:python中包含并有组织的代码片段,xxx.py的xxx就是模块名。
包:模块之上的有层次的目录结构,定义了由很多模块或很多子包组成的应用程序执行环境。包是一个包含__init__.py文件和若干模块文件的文件夹。
库:具有相关功能模块的集合,python有很多标准库、第三方库…
1、Matplotlib是一个用于创立二维图和图形的底层库。藉由它的协助,你可以构建各种不同的图标,从直方图和散点图到费笛卡尔坐标图。matplotlib可以与许多盛行的绘图库结合运用。
2、sys:系统相关的参数和函数。 sys 库一般用来访问和修改系统相关信息,比如查看 python 版本、系统环境变量、模块信息和 python 解释器相关信息等等。
3、os:操作系统接口模块。这个库提供了访问操作系统相关依赖的方式,比如输入输出操作、读写操作、操作系统异常错误信息、进程线程管理、文件管理、调度程序等等。
4、math:数学函数库。 math 库提供了对 C 语言标准定义的数学函数访问,比如数论(Number-theoretic)的各种表示方法、幂和对数函数(Power and logarithmic functions)、三角函数(Trigonometric functions)、常量圆周率(π)和自然常数(e)等等。
5、random:生成伪随机数。伪随机数与随机数(真随机数)不同的是执行环境,随机数是真实世界中通过物理过程实践得出结论,而伪随机数是通过计算机的特定算法生成的数,所以这个过程是可预测的、有规律的,只是循环周期较长,并不能与现实场景相切合。
6、xlwt/xlrd,读写Excel格式的数据文件。
7、xlsxwriter,创建Excel格式的xlsx文件。
8、PyGame基于Python的多媒体开发和游戏软件开发模块。
9、SciPy,开源的Python算法库和数学工具包,SciPy包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
10、NumPy科学计算库,提供了矩阵,线性代数,傅立叶变换等等的解决方案, 最常用的是它的N维数组对象。
11、scikits.learn,构建在SciPy之上用于机器学习的 Python 模块。它包括简单而高效的工具,可用于数据挖掘和数据分析。涵盖分类,回归和聚类算法,例如SVM, 逻辑回归,朴素贝叶斯,随机森林,k-means等算法,代码和文档都非常不错,在许多Python项目中都有应用。
12、unittest,Python标准库,单元测试框架。
13、pytest,成熟的全功能的Python测试工具。
14、Selenium,web测试框架,Python绑定Selenium。
17. python闭包
闭包使得局部变量在函数外被访问成为可能。
Python中闭包是什么?
答:可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,外函数和内函数。在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
#闭包函数的实例
# outer是外部函数
def outer( a ):
# inner是内函数
def inner( b ):
#在内函数中 用到了外函数的临时变量
print(a+b)
# 外函数的返回值是内函数的引用
return inner
ret = outer(5) #ret = inner
ret(10) #15 ret 存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
18. python运算符
Python运算符包括:算术运算符、比较(关系)运算符、赋值运算符、逻辑运算符、位运算符、成员运算符、身份运算符7个大的类型。
1、算术运算符:
2. 比较(关系)运算符
3.赋值运算符
4. 逻辑运算符
5.位运算符
6. 成员运算符
7. 身份运算符
19. 多进制数字
0b二进制(bin),0o八进制,0x十六进制