知识点-python

记录 Python 相关知识点。

会一直持续更新。

1. 五个常用python库

os:提供了与操作系统相关联的函数

sys:通常用于命令行参数

re:正则匹配

math:数学运算

datetime:处理日期时间

numpy:矩阵运算,数据处理

2. Python的GIL与多线程

​ GIL是Python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行Python程序的时候会霸占Python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。

​ 多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个Python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大。

​ GIL确保每次只能执行一个“线程”。一个线程获取GIL执行相关操作,然后将GIL传递到下一个线程。虽然看起来程序被多线程并行执行,但它们实际上只是轮流使用相同的CPU核心。

​ 所有这些GIL传递都增加了执行的开销。这意味着多线程并不能让程序运行的更快。

3. 面向对象中__new__和__init__区别?

1、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别。

2、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例。

3、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。

4、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。

4. python中生成随机整数、随机小数、0–1之间小数方法?

1
2
3
4
import random
print(random.randint(1, 10)) # 随机整数,1-10,包括1和10
print(random.random()) # 0-1随机小数
print(random.uniform(2, 6)) # 指定随机小数

5. 正则表达式输出汉字

1
2
3
4
5
import re

a = "not 404 found 中国 2018 我爱你"
r1 = '[a-zA-Z0-9’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+\s?'
print(re.sub(r1, '', a))

6. Logging模块

1
2
3
4
5
6
7
8
9
10
import logging

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")


7. 自定义异常代码

1
2
3
4
5
6
7
8
9
10
11
#自定义异常用raise抛出异常

def fn():
try:

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

fn() ==》数字大于2了

**8.**Zip函数

zip() 函数将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表。

1
2
3
4
5
6
list1 = [1, 2, 3, 5]
list2 = [4, 5, 6]
zipped = zip(list1, list2)

print(list(zipped)) # [(1, 4), (2, 5), (3, 6)]
print(list(zip(*zipped))) # [(1, 2, 3), (4, 5, 6)]

9. 提高python运行效率的方法

1、使用生成器,因为可以节约大量内存

2、循环代码优化,避免过多重复代码的执行

3、核心模块用Cython PyPy等,提高效率

4、多进程、多线程、协程

5、多个if elif条件判断,可以把最有可能先发生的条件放到前面写,这样可以减少程序判断的次数,提高效率

10. 多进程与多线程

进程是资源(CPU、内存等)分配的基本单位,是程序执行时的一个实例。

线程是程序执行时的最小单位,它是进程的一个执行流。

进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵

线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多

11. Lambda函数(重点)

lambda函数也叫匿名函数,该函数可以包含任意数量的参数,但只能有一个执行操作的语句。

12. [lambda i*x for i in range(4)]

1
2
3
4
5
6
def num(): 
return [lambda x:i*x for i in range(4)]


[m(1) for m in num()]
#[3, 3, 3, 3]

13. *args与**kwargs

当不确定将多少个参数传递给函数,或者我们想要将存储的列表或参数元组传递给函数时,我们使用* args。

当我们不知道将多少关键字参数传递给函数时使用kwargs,或者它可以用于将字典的值作为关键字参数传递。

标识符args和kwargs是一个约定,你也可以使用* bob和** billy。

14. self

self是类的实例或对象。在Python中,self包含在第一个参数中。但是,Java中的情况并非如此,它是可选的。它有助于区分具有局部变量的类的方法和属性。init方法中的self变量引用新创建的对象,而在其他方法中,它引用其方法被调用的对象。

self在python 中不是一个关键字,就是一个普通的变量名

与C++中的this相比,C++的成员函数第一个参数是个隐藏参数,是指向对象本身的指针,这个指针就是this,因为是隐式的,用户无法改变他的名称,this就成为一个关键字,这一点与self不一样。

15. is与==

==是比较操作符,只是判断对象的值(value)是否一致,而 is 则判断的是对象之间的身份(内存地址)是否一致。对象的身份,可以通过id()方法来查看。

16. 深浅拷贝(重要)

一般来说,在创建新实例类型时使用浅拷贝,并保留在新实例中复制的值。浅拷贝用于复制引用指针,就像复制值一样。这些引用指向原始对象,并且在类的任何成员中所做的更改也将影响它的原始副本。浅拷贝允许更快地执行程序,它取决于所使用的数据的大小。

​ 深拷贝用于存储已复制的值。深拷贝不会将引用指针复制到对象。它引用一个对象,并存储一些其他对象指向的新对象。原始副本中所做的更改不会影响使用该对象的任何其他副本。由于为每个被调用的对象创建了某些副本,因此深拷贝会使程序的执行速度变慢。

17. Filter、map、Reduce

Filter:用于过滤序列,它接收一个函数和一个序列,把函数作用在序列的每个元素上,然后根据返回值是True还是False决定保留还是丢弃该元素。

1
2
3
mylist = list(range(10)) 
list(filter(lambda x: x % 2 == 1, mylist))
# [1, 3, 5, 7, 9]

Map:传入一个函数和一个序列,并把函数作用到序列的每个元素上,返回一个可迭代对象。

1
2
3
4
list(map(lambda x: x % 2, mylist))
# [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
list(map(lambda x: x * 2, mylist))
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Reduce:用于递归计算,同样需要传入一个函数和一个序列,并把函数和序列元素的计算结果与下一个元素进行计算。

1
2
reduce(lambda x, y: x + y, range(101)) 
# 5050

18. 实现一行代码将列表展开

1
2
3
list1 = [[1, 2], [3, 4], [5, 6]]
[j for i in list1 for j in i]
[1, 2, 3, 4, 5, 6]

19. 转换字典与json

1
2
3
dict1 = {'zhangfei':1, "liubei":2, "guanyu": 4, "zhaoyun":3}
myjson = json.dumps(dict1) # 字典转JSON
mydict = json.loads(myjson) # JSON转字典

20. Python 垃圾回收与gc

Python中的垃圾回收机制是一个复杂的系统,用于管理不在使用的内存,防止内存泄漏并提高程序的性能,通常由引用计数,标记–清除,分代收集算法来处理循环引用等问题。

(1) 引用计数

当一个python对象被调用时,他的引用计数就会增加,当对象为空或删除时,它的引用技术就会减小,当为0时,垃圾回收机制就会释放该对象占用的内存

1
2
3
4
5
6
7
8
a = [1,2,3] 	#a对象被调用,引用技术+1=1
b = a #b对象被调用,引用技术+1=2
del a #a对象被删除,引用技术-1=1
del b #b对象被删除,引用技术-1=0

\#此时被释放内存
print(a)
# 输出:NameError: name 'a' is not defined,报错,因为该内存已被释放

(2) 标记–清除

通常分为两个阶段,第一阶段从根对象出发,遍历所有可达对象的”活动对象“并打上标记,第二阶段是清除阶段,释放所有未标记对象的空间。

(3) 分代收集

对于新对象进行高频率的检查,老对象则采用低频率检查,因而往往新对象更容易成为垃圾。主要目的是为了减少垃圾回收的开销。

21. 内存管理

(1)内存分配:

Python使用内存池(memory pools)来管理内存,用于减少内存碎片和分配/释放开销。

(2)引用计数:

Python使用引用计数机制来跟踪每个对象的引用次数。当对象被创建时,引用计数初始化为1,如果有新的引用指向该对象,则计数增加;当引用被删除时,计数减少。

当对象的引用计数降为0时,意味着没有任何引用指向该对象,对象将立即被释放。

(3)垃圾回收(Garbage Collection, GC):

引用计数是一种有效的内存管理方式,但无法处理循环引用的情况。为了解决这个问题,Python实现了一个垃圾回收器,使用引用计数和分代回收策略来跟踪和回收垃圾对象。

(4)循环垃圾收集:

为了处理循环引用,Python的垃圾回收器会定期执行循环检测。这个过程不是实时的,而是周期性地执行,以寻找并回收循环引用中涉及的对象。

(5)手动内存管理:

虽然Python的内存管理是自动的,但有时开发者可能需要手动管理内存。Python提供了gc模块,允许开发者启用或禁用垃圾回收,强制执行垃圾回收,以及获取关于对象的引用信息。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码

请我喝杯咖啡吧~

支付宝
微信