Python知识点总结

Python简介

  • 有对象、模块、线程、异常处理和自动内存管理,可以加入其他语言的对比。
  • 代码运行之前不需要编译解释执行。
  • 动态类型语言,在声明变量时,不需要说明变量的类型。
  • 面向对象的编程,支持通过组合与继承的方式定义类。
  • 函数是第一类对象。
  • Python 代码编写快,但是运行速度比编译型语言通常要慢。

常见Python问题及知识点

赋值、浅拷贝和深拷贝的区别?

  1. 在 Python 中,对象的赋值就是简单的对象引用,这点和 C++不同。如下情况:

    1
    2
    a = [1,2,"hello",['python', 'C++']]
    b = a

    a和b指向同一片内存,b是a的引用。可以通过b is aid(a) == id(b)判断,两个列表的地址相同。
    赋值操作(包括对象作为参数、返回值)不会开辟新的内存空间,它只是复制了对象的引用。也就是说除了 b 这个名字之外,没有其他的内存开销。修改了 a,也就影响了 b,同理,修改了 b,也就影响了 a。

  2. 浅拷贝会创建新对象,其内容非原对象本身的引用,而是原对象内第一层对象的引用。浅拷贝有三种形式:切片操作、工厂函数、copy 模块中的 copy 函数。
    比如上述的列表 a,切片操作:b = a[:] 或者 b = [x for x in a];
    工厂函数:b = list(a);
    copy 函数:b = copy.copy(a);
    在这种情况下,列表 a 和 b 是不同的对象,修改列表 b 理论上不会影响到列表 a。

但是要注意的是,浅拷贝之所以称之为浅拷贝,是它仅仅只拷贝了一层,在列表 a 中有一个嵌套的 list,如果我们修改了它,情况就不一样了。
比如:a[3].append(‘java’),查看列表 b,会发现列表 b 也发生了变化,这是因为,我们修改了嵌套的 list,修改外层元素,会修改它的引用,让它们指向别的位置,修改嵌套列表中的元素,列表的地址并未发生变化,指向的都是用一个位置。

  1. 深拷贝只有一种形式,copy 模块中的 deepcopy() 函数。
  2. 注意
    对于非容器类型,如数字、字符,以及其他的“原子”类型,没有拷贝一说,产生的都是原对象的引用。

__init__ 和 __new__ 的区别

当我们使用「类名()」创建对象的时候,Python 解释器会帮我们做两件事情:1.为对象在内存分配空间,2.为对象进行初始化。分配空间是__new__ 方法,初始化是__init__方法。
__new__ 方法在内部做两件事情:1.对象分配空间。2.把对象的引用返回给 Python 解释器。当 Python 的解释器拿到了对象的引用之后,就会把对象的引用传递给__init__的第一个参数 self,__init__拿到对象的引用之后,就可以在方法的内部,针对对象来定义实例属性。
之所以要学习 __new__ 方法,就是因为需要对分配空间的方法进行改造,改造的目的就是为了当使用「类名()」创建对象的时候,无论执行多少次,在内存中永远只会创造出一个对象的实例,这样就可以达到单例设计模式的目的。

Python的变量、对象以及引用?

  1. 变量是到内存空间的一个指针,也就是拥有指向对象连接的空间;
  2. 对象是一块内存,表示它们所代表的值;
  3. 引用就是自动形成的从变量到对象的指针。

Python 是强语言类型还是弱语言类型?

Python 是强类型的动态脚本语言。

  1. 强类型:不允许不同类型相加。
  2. 动态:不使用显示数据类型声明,且确定一个变量的类型是在第一次给它赋值的时候。
  3. 脚本语言:一般也是解释型语言,运行代码只需要一个解释器,不需要编译。

Python中的作用域?

Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定。当 Python 遇到一个变量的话它会按照这的顺序进行搜索:

什么是 Python 自省?

自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。

什么是Python的命名空间?

命名空间是对作用域的一种特殊的抽象

dict 的 items() 方法与 iteritems() 方法的不同?

items方法将所有的字典以列表方式返回,其中项在返回时没有特殊的顺序。iteritems方法有相似的作用,但是返回一个迭代器对象。

os.path和sys.path的区别?

os.path是操作系统的指定文件的路径,sys.path指python解释器的路径

Python 中的 os 模块常见方法?

os.remove() 删除文件
os.rename() 重命名文件
os.walk() 生成目录树下的所有文件
os.chdir() 改变目录
os.mkdir/makedirs 创建目录/多层目录
os.rmdir/removedirs 删除目录/多层目录
os.listdir() 列出指定目录的文件
os.getcwd() 取得当前工作目录
os.chmod() 改变目录权限
os.path.basename() 去掉目录路径,返回文件名
os.path.dirname() 去掉文件名,返回目录路径
os.path.join() 将分离的各部分组合成一个路径名
os.path.split() 返回(dirname(),basename())元组
os.path.splitext() 返回(filename,extension)元组
os.path.getatime\ctime\mtime 分别返回最近访问、创建、修改时间
os.path.getsize() 返回文件大小
os.path.exists() 是否存在
os.path.isabs() 是否为绝对路径
os.path.isdir() 是否为目录
os.path.isfile() 是否为文件

字典和 json 的区别?

典是一种数据结构,json 是一种数据的表现形式。

什么是可变、不可变类型?

可变不可变指的是内存中的值是否可以被改变,不可变类型指的是对象所在内存块里面的值不可以改变,有数值、字符串、元组;可变类型则是可以改变,主要有列表、字典。

如何理解 Python 中字符串中的\字符?

  1. 转义字符
  2. 路径名中用来连接路径名
  3. 编写太长代码手动软换行

常用的 Python 标准库都有哪些?

random, time, os, threading, multiprocessing

如何在Python中管理内存?

python中的内存管理由Python私有堆空间管理。所有Python对象和数据结构都位于私有堆中。程序员无权访问此私有堆。python解释器负责处理这个问题。Python还有一个内置的垃圾收集器,它可以回收所有未使用的内存,并使其可用于堆空间。

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

except 捕获所有异常
except:<异常名> 捕获指定异常
except:<异常名 1, 异常名 2> 捕获异常 1 或者异常 2
except:<异常名>,<数据> 捕获指定异常及其附加的数据
except:<异常名 1,异常名 2>:<数据> 捕获异常名 1 或者异常名 2,及附加的数据

介绍一下raise用法?

raise [exceptionName [(reason)]]
raise ZeroDivisionError(“除数不能为零”)

1
2
3
4
5
6
try:
for i in range(5):
if i > 2:
raise Exception("数字大于2了")
except Exception as ret:
print(ret)

read、readline 和 readlines 的区别?

read:读取整个文件。
readline:读取下一行,使用生成器方法。
readlines:读取整个文件到一个迭代器以供我们遍历。

range 和 xrange 的区别?

两者用法相同,不同的是 range 返回的结果是一个列表,而 xrange 的结果是一个生成器,前者是直接开辟一块内存空间来保存列表,后者是边循环边使用,只有使用时才会开辟内存空间,所以当列表很长时,使用 xrange 性能要比 range 好。

一行代码实现

  1. 一行代码实现字符串整数列表变成整数列表

    1
    2
    a = ['1', '2', '3']
    list(map(lambda a: int(a), a))
  2. 一行代码删除列表中重复的值

    1
    2
    lst = [1, 1, 2, 3, 4]
    list(set(lst))
  3. 一行代码找出两个列表中相同的元素

    1
    2
    3
    a = [1, 1, 2, 2, 4]
    b = [2, 3, 4, 4]
    set(a) & set(b)
  4. 一行代码合并两个字典

    1
    2
    3
    des = {'name': 'Rock'}
    age = {'age': '18'}
    des.update(age)
  5. 一行代码实现字典键从小到大排序

    1
    2
    des = {'name': 'Rock', 'age': '18'}
    sorted(des.items(), key=lambda x: x[0])

Python 函数调用的时候参数的传递方式是值传递还是引用传递?

不可变参数用值传递(整数,字符串),可变参数是引用传递的(列表,字典)。

1
2
3
4
5
6
7
8
9
def func(d):
d['a'] = 10
d['b'] = 20
d = {'a': 1, 'b': 2}
d = {} # 1
func(d) # 2
print(d)
########打印结果########
{'a': 10, 'b': 20}

对缺省参数的理解?

缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。
*args 是不定长参数,他可以表示输入参数是不确定的,可以是任意多个。
**kwargs 是关键字参数,赋值的时候是以键 = 值的方式,参数是可以任意多对在定义函数的时候不确定会有多少参数会传入时,就可以使用两个参数。

面向对象中super的作用?

super() 函数是用于调用父类(超类)的一个方法。super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

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

简单地说,就是基于已有的函数定义新的函数。所谓高阶函数,就是以函数作为输入参数,返回也是函数。

什么是断言?应用场景?

assert断言——声明其布尔值必须为真判定,发生异常则为假。

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

with语句的作用是通过某种方式简化异常处理,它是所谓的上下文管理器的一种

__setattr__,__getattr__,__delattr__函数使用详解?

  1. setattr(self,name,value):如果想要给 name 赋值的话,就需要调用这个方法。
  2. getattr(self,name):如果 name 被访问且它又不存在,那么这个方法将被调用。
  3. delattr(self,name):如果要删除 name 的话,这个方法就要被调用了。

请描述抽象类和接口类的区别和联系?

  1. 抽象类
    规定了一系列的方法,并规定了必须由继承类实现的方法。由于有抽象方法的存在,所以抽象类不能实例化。可以将抽象类理解为毛坯房,门窗、墙面的样式由你自己来定,所以抽象类与作为基类的普通类的区别在于约束性更强。
  2. 接口类
    与抽象类很相似,表现在接口中定义的方法,必须由引用类实现,但他与抽象类的根本区别在于用途:与不同个体间沟通的规则(方法),你要进宿舍需要有钥匙,这个钥匙就是你与宿舍的接口,你的同室也有这个接口,所以他也能进入宿舍,你用手机通话,那么手机就是你与他人交流的接口。
  3. 区别和关联
  • 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类中可以有非抽象方法。抽象类是声明方法的存在而不去实现它的类。
  • 接口可以继承,抽象类不行。
  • 接口定义方法,没有实现的代码,而抽象类可以实现部分方法。
  • 接口中基本数据类型为 static 而抽类象不是。
  • 接口可以继承,抽象类不行。
  • 可以在一个类中同时实现多个接口。
  • 接口的使用方式通过 implements 关键字进行,抽象类则是通过继承 extends 关键字进行。

请描述方法重载与方法重写?

(1)方法重载
是在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。重载是让类以统一的方式处理不同类型数据的一种手段。

(2) 方法重写
子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。

Python 中 is 和==的区别?

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

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

面向对象是相对于面向过程而言的。面向过程语言是一种基于功能分析的、以算法为中心的程序设计方法。面向对象是一种基于结构分析的、以数据为中心的程序设计思想。在面向对象语言中有一个有很重要东西,叫做类。面向对象有三大特性:封装、继承、多态。

Python 中的进程与线程的使用场景?

多进程适合在 CPU 密集型操作(cpu 操作指令比较多,如位数多的浮点运算)。多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)。

简述多线程、多进程

进程:
1、操作系统进行资源分配和调度的基本单位,多个进程之间相互独立
2、稳定性好,如果一个进程崩溃,不影响其他进程,但是进程消耗资源大,开启的进程数量有限制
线程:
1、CPU进行资源分配和调度的基本单位,线程是进程的一部分,是比进程更小的能独立运行的基本单位,一个进程下的多个线程可以共享该进程的所有资源
2、如果IO操作密集,则可以多线程运行效率高,缺点是如果一个线程崩溃,都会造成进程的崩溃

列出几种魔法方法并简要介绍用途

__init__:对象初始化方法
__new__:创建对象时候执行的方法,单列模式会用到
__str__:当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
__del__:删除对象执行的方法

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

1
2
3
4
5
6
7
x = "abc"
y = "def"
z = ["d", "e", "f"]
m = x.join(y)
n = x.join(z)
print(m, n)
dabceabcf dabceabcf

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

try..except..else没有捕获到异常,执行else语句
try..except..finally不管是否捕获到异常,都执行finally语句

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

两个列表相加,等价于extend

递归求和

1
2
3
4
5
6
7
def get_sum(num):
if num >= 1:
res = num + get_sum(num - 1)
else:
res = 0
return res
res = get_sum(10)

python垃圾回收机制

python垃圾回收主要以引用计数为主,标记-清除和分代清除为辅的机制,其中标记-清除和分代回收主要是为了处理循环引用的难题。

关于多继承问题,扩展需要了解 MRO

1
2
3
4
5
6
7
8
9
10
11
class A(object):
x = 3
class B(A):
pass
class C(A):
pass
print(A.x, B.x, C.x) # 3 3 3
B.x = 4
print(A.x, B.x, C.x) # 3 4 3
A.x = 5
print(A.x, B.x, C.x) # 5 4 5
非常感谢各位老板投喂!