Python必学知识点总结

深度学习视觉

共 9078字,需浏览 19分钟

 · 2022-02-20

1. txt文件读取,考点:分批读取文件内容,避免内存不足的情况;

## 一次性全部读到内存
def get_lines():
with open('file.txt','rb') as f:
return f.readlines()

## 分批读到内存,避免内存不足;
def get_line():
data_list = list()
with open('file.txt','rb') as f:
data_item = f.readlines(60000)
data_list.append(data_item)
yield data_list

if __name__ == '__main__':
for e in get_lines():
process(e) # 处理每一行数据

2. 获取文件夹下面所有文件路径,包括多重文件夹

import os
## 递归获取所有文件
def get_files_path(root_dir):
file_path_list = list()
for item in os.listdir(root_dir):
item_path = os.path.join(root_dir,item)
if os.path.isdir(item_path):
file_path_list.extend(get_files_path(item_path))
else:
file_path_list.append(item_path)
return file_path_list

## 非递归,并且只需要“.jpg“文件
def get_file_path_list(path,file_type=".jpg"):
data_list = list()
for root,dirs,files in os.walk(path):
for file in files:
if file.endswith(file_type):
data_list.append(os.path.join(root,file))

return data_list

3. 判断这一天是这一年的第几天

import datetime
def day_of_year(year:int,month:int,day:int):
date1 = datetime.date(year=int(year),month=int(month),day=int(day))
date2 = datetime.date(year=int(year),month=int(1),day=int(1))
return (date1-date2).days+1

4. 字典、列表操作

## 字典推导式
d1 = {key:len(key) for key in ("test","python")}
## 字符串反转(对key进行反转)
d2 = {key[::-1]:value for (key,value) in d1.items()}
## 字典合并
d = dict(d1,**d2)
## 按key排序
dict(sorted(d.items(), key=lambda item: item[1]))
## 按value排序
dict(sorted(d.items(), key=lambda item: item[0]))
## 打乱list
import random
list1 = list(d.values()) # 返回的是一个 dict_keys 对象,不再是 list 类型,也不支持 index 索引
random.shuffle(list1)
## list元素去重
set_list = list(set(d1.values()))
## list元素排序
sorted_list = sorted(list1)
## list元素删除
sorted_list.remove(sorted_list[0])
## list 元素过滤
sorted_list = filter(lambda x:x>0,sorted_list)
## 找两个List的相同元素
set(d1.values())&set(d2.values())
## 找两个List的不相同元素
set(d1.keys())&set(d2.keys())
## 列表解析、列表推导式,并将字符串类型的key值全部大写
sorted_list = [item.upper() for item in list(d.keys())]

5. python新式类和经典类的区别

a.python里凡是继承了object的类,都是新式类;
b....

6. python中内置的数据结构有哪些

整型int、长整型long、浮点型float、复数complex、字符串str、
列表list、元组tuple、字典dict、集合set
python3中没有long,只有无限精度的int

7. 可变类型和不可变类型

1. 可变类型有list,dict;不可变类型有string,number,tuple.
2. 当进行修改操作时,可变类型传递的是内存中的地址,也就是说,直接修改内存中的值,并没有开辟新的内存。
3. 不可变类型被改变时,并没有改变原内存地址中的值,而是开辟一块新的内存,将原地址中的值复制过去,对这块新开辟的内存中的值进行操作。

8. python中的super()

Python中的super(Net, self).__init__()是指首先找到Net的父类(比如是类NNet),
然后把类Net的对象self转换为类NNet的对象,然后“被转换”的类NNet对象调用自己的init函数
其实简单理解就是子类把父类的__init__()放到自己的__init__()当中,
这样子类就有了父类的__init__()的那些东西。

super()如果不写参数的话,那么默认就是super(当前类, self)

9. Python中类方法、类实例方法、静态方法有何区别

类方法:是类对象的方法,在定义时需要在上方使用@classmethod进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用;
类实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;
静态方法:是一个任意函数,在其上方使用@staticmethod进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系;

10. Python单例

import threading
class Singleton(object):
_instance_lock = threading.Lock() # 如果不加锁,那么单例功能会有失效的情况。

def __init__(self):
pass

def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"): # 如果该类“不“含有实例化对象
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
# 用父类(object)的new方法创建一个该类(cls==Singleton)的实例。
Singleton._instance = object.__new__(cls)
return Singleton._instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)

def task(arg):
obj = Singleton()
print(obj)

for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()

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

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

12. 编写函数的4个原则

1.函数设计要尽量短小;
2.函数声明要做到合理、简单、易于使用;
3.函数参数设计应该考虑向下兼容;
4.一个函数只做一件事情,尽量保证函数语句粒度的一致性;

13. 什么是lambda函数?有什么好处?

lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数;
1.lambda函数比较轻便,即用即
扔,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下;
2.匿名函数,一般用来给filter,map这样的函数式编程服务;
3.作为回调函数,传递给某些应用,比如消息处理;

14. 什么是闭包

在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。

15. Python中的yield

yield类似return会停止,但是不会结束。yield作为可迭代的 generator(生成器)对象,
每次迭代的时候会在yield语句后停止
def simple_generator():
x = 2
yield x**2
yield x**3
yield x**4

generator_object = simple_generator()
[item for item in generator_object]
#[4, 8, 16]

16. Python实现私用变量的效果

1. 单下划线表示的私有,但是依然可以直接访问;
2. 双下划线表示的私有,因为被强制改名,所以不可以直接访问,但访问这个改成的变量名;
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
rect = Rect(30)
#直接通过方法名来访问 area 方法
print("矩形的面积是:",rect.area)
#假私有,_Rect__area就是__area新的变量名。
rect._Rect__area

17. 进程、线程、协程

进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid
一个运行的程序就是一个进程,没有运行的代码叫程序。
进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,且开销大。

多进程:适合CPU密集操作cpu指令比较多,如位多的浮点运算)。

线程:cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在。一个进程至少有一个线程,叫做主线程。
而多个线程共享内存(数据共享,共享全局变量),从而极大的提高了程序的运行效率。

多线程:适合IO密集性操作(读写数据操作比较多的,比如爬虫);

协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。
协程调度时,将寄存器上下文和栈保存到其它地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,
直接操作栈基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

三者关系:进程里面有线程,线程里面有协程。
线程是并发,进程是并行。

并行:同一时刻多个任务同时运行;
并发:不会在同一时刻同时运行,存在交替执行的情况。

18. Python异步的使用场景

1. 不涉及共享资源,或者对于共享资源只读等非互斥操作;
2. 没有时序上的严格关系;
3. 不需要原子操作,或可以通过其它方式控制原子性;
4. 常用于IO操作等耗时操作,因为比较影响客户体验和使用性能;
5. 不影响主线程逻辑。
所谓原子操作是指不会被 线程调度 机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

19. 什么是多线程竞争

线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态,
即:数据几乎同步被多个线程占有,造成数据混乱,即所谓的线程不安全。为此可添加锁。

锁是Python提供的对线程控制的对象。有互斥锁,可重入锁,死锁。
锁的好处:确保某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行;能解决资源竞争下的原子操作问题。
锁的坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率大大下降。

20. Python的线程同步

1. setDaemon(False),当一个进程启动之后,会默认产生一个主线程,因为线程时程序执行的最小单位。
当设置多线程时,主线程会创建多个子线程。在Python中,默认情况下就是setDaemon(False),
主线程执行完自己的任务以后就退出。此时子线程会继续执行自己的任务,直到自己的任务结束。

2. setDaemon(True),这时子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止。

3. join(线程同步),join所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,
一直等待所有的子线程结束以后,主线程再终止。
当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。
所以说,如果有10个子线程,全部等待时间就是每个timeout的累加和
如果没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,
但是子线程依然存活,并且持续运行,直到子线程全部结束,程序退出。(孤儿进程)
import threading
import time

def thread():
time.sleep(2)
print('---子线程结束---')

def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True) # 设置子线程守护主线程
t1.start()
t1.join(timeout=1) # 线程同步,主线程堵塞1s,然后主线程结束,子线程继续执行;
# 如果不设置timeout参数就等子线程结束后主线程再结束;
# 如果设置了setDaemon=True和timeout=1主线程等待1s后会强制杀死子线程,然后主线程结束。
print('---主线程结束---')

main()

21. 死锁

定义:若干子线程在系统资源竞争的时候,都在等待对方对某部分资源解除占用状态,结果谁也不愿意先解锁,程序无法执行下去。
GIL锁:全局解释器锁;
作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以cpython里的多线程其实是伪多线程。
python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程。
进程和线程的切换是由系统决定,而协程由开发者决定,而模块gevent下切换是遇到了耗时操作时才会切换。

22. 多线程交互访问数据,如何避免重读。

创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,
在多线程访问数据的时候先查看数据是否在已访问的列表中,若存在就跳过。

23. 线程安全、互斥锁

每个对象都对应于一个可称为”互斥锁“的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
同一进程中的多线程之间共享系统资源,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一线程已经对其进行操作,
导致最终结果出现错误,此时需要对被操作对象添加互斥锁,保证每个线程对该对象的操作都得到正确的结果。

24. 同步、异步、阻塞,非阻塞

同步:多个任务之间有先后执行顺序,一个执行完下个才能执行。
异步:多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务结果(回调操作)。
阻塞:如果卡住了调用者,调用者不能继续往下执行,指的就是调用者发生阻塞。
非阻塞:如果不会卡住,可以继续执行,指的就是非阻塞。
同步、异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。

25. 什么是僵尸进程、孤儿进程

孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init进程(进程号为1)所收养,
并由init进程对他们的完成状态进行收集。
僵尸进程:进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait/waitpid获取子进程的状态信息,
那么子进程的进程描述符仍然保存在系统中的这些进程。

避免僵尸进程的方法:
1. fork两次用孙子进程去完成子进程的任务;
2. 用wait()函数使父进程阻塞;
3. 使用信号量,在signal handler中调用waitpid,这样父进程不用阻塞。

26. 多线程共同操作同一个数据互斥锁同步

上锁解锁过程
当一个线程调用锁的 acquire() 方法获得锁时,锁就进入“locked”状态。
每次只有一个线程可以获得锁。
如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,
直到拥有锁的线程调用锁的 release() 方法释放锁之后,锁进入“unlocked”状态。
线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

import threading
import time

g_num = 0

def test1(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁

print("---test1---g_num=%d" % g_num)

def test2(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁

print("---test2---g_num=%d" % g_num)

# 创建一个互斥锁
# 默认是未上锁的状态
mutex = threading.Lock()

# 创建2个线程,让他们各自对g_num加10000次
p1 = threading.Thread(target=test1, args=(10000,))
p1.start()

p2 = threading.Thread(target=test2, args=(10000,))
p2.start()

"""
enumerate() 是 Python 中线程模块的内置方法。
它用于返回当前处于活动状态的所有 Thread 类对象的列表。
它还包括守护线程、主线程和由 current_thread() 创建的虚拟线程对象。
它不计算已终止或尚未启动的线程。
"""
# 等待计算完成
while len(threading.enumerate()) != 1:
time.sleep(0.1)

print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

27. 进程通信队列与进程池

由于不同进程之间不通信,所以采用队列。
由于需要控制进程数量,所以有了进程池。过多的进程数量并不高效。

def read_data(queue):
# 循环读取数据
while True:
# 判断队列是否为空
if queue.qsize() == 0:
print("队列为空~")
break
# 从队列中读取数据
result = queue.get()
print(result)


if __name__ == '__main__':
# 创建进程池
pool = multiprocessing.Pool(2)
# 创建进程池队列
queue = multiprocessing.Manager().Queue()
# 在进程池中的进程间进行通信
# 使用线程池同步的方式,先写后读
# pool.apply(write_data, (queue, )) # 同步方式加载
# pool.apply(read_data, (queue, )) # 同步方式加载
# apply_async() 返回ApplyResult 对象
result = pool.apply_async(write_data, (queue, )) # 异步方式加载
# ApplyResult对象的wait() 方法,表示后续进程必须等待当前进程执行完再继续
result.wait() # 由于异步方式加载,但是必须写先完成,所以必须等待写进程完成
pool.apply_async(read_data, (queue, )) # 异步方式加载
pool.close()
# 异步后,主线程不再等待子进程执行结束,再结束
# join() 后,表示主线程会等待子进程执行结束后,再结束
pool.join()

公众号粉丝礼包:后台关键词:

python大礼包

整理不易,还请点击在看与分享,谢谢。

浏览 25
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报