美文网首页
2020-09-19

2020-09-19

作者: 李扬_20f9 | 来源:发表于2020-09-23 13:57 被阅读0次

一、python数据类型

1、int :整数。 python3唯一的整数类型,python里没有long之类的类型,int指代所有整数型。

2、float :浮点数。混合计算时,python3会把整型转换成浮点数。

3、bool :布尔数。0==flase,1==true。一般用于判断。

4、complex :复数。复数由虚部和实部组成,a+bj,complex(a,b)。

5、string :字符串。一般用双引号或者单引号阔起来。反斜杠转译特殊字符,前面+r可以取消转译。支持index索引, 持for-loop遍历。

6、list :列表。中括号扩起来。可以嵌套,支持index遍历,forloop遍历。可以利用下标截取字符串。还可以进行切片操作,截取也可以设置step。
[a,b,s]=》a:起始坐标,b:终止坐标,s:步幅。

7、tuple :元祖。不可替换。小括号。

8、set :集合。无序唯一集合。里面的元素具有唯一性。

9、dictionary :字典。key-value pair。value可以嵌套别的类型。key值必须是唯一且不变的。

10、bytes :比特。python3新添加的类型。
string->encode()->bytes()。bytes()->decode()->string.

二、判断类型

python里有两个方法判断类型。

1、type():如果只传入一个参数,type会打印该参数的数据类型。子类不会被判断与父类相同。

>>a=4
>>type(a)
<class 'int'>
>>type(a)==int
True

2、isinstance():需要传入两个参数,会判断两个参数是否为相同类型,子类也会认为和父类是相同的。

class A:
  pass

class B(A):
  pass

>>isinstance(B(),A)
True

三、深拷贝浅拷贝

这里基本就是考两种拷贝的区别。
1、浅拷贝:
共享同一个内存地址,父类修改,子类也会变化,子类修改,父类也会变化。

import copy
a=[1,2,3,[4,5]]
b=copy.copy(a)
b=a

使用copy函数,或者直接赋值都可以达到相同的效果。
切片复制是浅拷贝!!!一定要注意!
并且可变类型和不可变类型一定要注意。
不可变类型,浅拷贝直接复制value。可变类型,例如list[],浅拷贝会拷贝引用。
切片复制,不可变类型,原变量改变,复制变量不变;可变类型,原变量改变,复制变量也会改变。
复制或者直接浅拷贝的话,两个都会改变。

2、深拷贝
父类与子类不共享内存地址,只是复制相同的value。

import copy
a=[1,2,3,[4,5]]
b=copy.deepcopy(a)
b=a.copy()

不用太拘泥于copy函数,两种写法都是深拷贝,或者建立个新的空列表,循环赋值也可以。

注意:我们在做一些动态规划的题目时,往往会先初始化一个二维矩阵。
我们可以使用numpy来帮助我们。如果不想用numpy的话,请使用for loop赋值。

import numpy

dp=zeros(5,5)

dp=[[0 for i in range(5)] for i in range(5)]

dp=[[0*5]*5]

最后一种方法是不行的,相当于“浅拷贝了”,每一个子列表的内存地址是一样的,修改一个,其他也会变化。

四、面向对象

python类的继承
把父类当作参数传入子类中。
构造函数:
init:
最常见的构造函数,比new要常用一些。

五、常用的函数

1、sort()函数
python的自带的排序算法是timsort,最优的时间复杂度是O(n),是稳定排序,放心使用。可以通过erverse=true来降序。
还有一个key参数,可以制定排序方法。

>>> a=[(1,3),(4,2),(5,7),(9,1)]
>>> a.sort(key=lambda i:i[1])
>>> a
[(9, 1), (4, 2), (1, 3), (5, 7)]
>>> 

2、counter函数
用来统计列表里面的元素出现的次数,返回值是一个字典,key是元素,value是次数。需要先引入

from collections import Counter

3、map函数
map函数会根据要求做对于制定序列的方法。
map(function, []...)后面可以传入多个序列。

>>map(square,[1,2,3,4])
[1,4,9,16]

>>map(lambda x,y:x+y, [1,3,5,7], [2,4,6,8])
[3,7,11,15]

返回值是一个迭代器。

4、reduce函数
python3里,reduce被放到functools里面了,使用前需要先引入。
辅助进行累计运算。

from functools import reduce
a=[1,2,3,4]
print(reduce(lambda x,y:x+y),a)
10

在进行一些亦或操作的时候,reduce可以有奇效。

六、装饰器、生成器、迭代器

1、装饰器:
在不改变当前函数的情况下,给函数增加新的功能。

def 外层函数(args):
       def 内层函数(*args,**kwargs):
              rerturn 参数(*args,**kwargs)
              rerurn 内存函数

@外层函数
def index():
    pass
def func(arg):
    def inner():
        v=arg()
        return v
    return inner

@func
def index():
    print(123)
    return 666

print(index)

2、迭代器:
涉及到可迭代对象和迭代类。
3、生成器:

七、python的gc机制

1、引用计数:
python的内存管理以引用计数为主。

>>> import sys
>>> a=[1,2,3]
>>> sys.getrefcount(a)
2
>>>b=a
>>> sys.getrefcount(a)
3
>>> 

使用getrefcount也会建立临时引用,导致计数比原来大1。
一些常见的引用计数➕1情况:
1、对象创建 a=1
2、被赋值 b=a
3、被当作参数传入函数中 foo(a)
4、被当作容器对象的一个元素 x=[1,2,a]
引用计数减少的情况:
1、本地引用离开作用域,foo(a)函数结束,引用计数-1
2、对象的名称被销毁 del a \ del b
3、对象的名称被重新赋值了,a=2
4、被容器对象移除 x.pop()
5、容器对象本身被销毁 del x
在引用计数减少到0的时候,python进行垃圾回收,会把为0的对象清除。
gc机制会有一个阈值,一旦分配对象和取消分配对象的差值大于阈值的时候,就会触发python的垃圾回收机制。
2、标记清除
主要针对一些循环引用的容器对象。
循环引用,就是a、b两个对象相互引用,没用额外的外部引用,其实可以看作有效引用为0。

a=[]
b=[]
a.ppend(b)
b.append(a)

我们把相互引用的关系当作图结构的方向,每个变量都是一个节点,我们从一个root object出发,如果有些对象无法到达,我们会标记为不可达,可以到达的标记为可达。在下一轮扫描时,不可达的对象将会被销毁。
3、分代回收
python将所有的对象分为0、1、2三代
所有的新建对象都默认是0代
当某个对象在一轮gc扫描过后还存活,就会提升一代。
4、内存池机制
python中分为大内存和小内存(256k为界限)
大内存使用malloc分配
小内存使用内存池分配

小内存会开辟一块256k的内存空间,使用过后不会立刻free掉,将存留在内存池中以便下次使用。
大内存使用过后,会free掉。

八、进程、线程、协程

python的多线程是有先天缺陷的!

1、进程是cpu资源分配的最小单元,进程是一个实体,一个程序。
2、线程是独立运行和独立调度的最小单元,线程就相当于程序里的一个功能,视频网站的音频,视频都是不同的线程掌管的。
3、线程依赖于进程。一个进程可以有多个线程,一个线程只能属于一个进程。
4、进程有自己的资源空间,当进程退出时,该进程产生的线程都会被清除退出。
5、线程的调度与切换比进程快很多。
6、线程在运行时,只保留一点基本的系统信息(计数器,一组寄存器和栈)
7、协程不被操作系统内核管理,被程序本身管理。
8、协程适用于大量不需要cpu操作时的场景(I/O密集型任务)。
9、什么是资源?当时面试字节的时候真的被问傻了。
资源分为两类:软件资源:程序和数据;硬件资源:cpu,存储器,i/o设备等。软件资源与硬
件资源共同组成了计算机的资源。
协程事例:

def customer():
    while True:
        number = yield
        print('开始消费:',number)
        
custom = customer()
next(custom)
for i in range(10):
    print('开始生产:',i)
    custom.send(i)

这里还涉及一个概念:并行与并发:
并行:当操作系统有多个cpu时,cpu1可以运行线程1,cpu2可以运行线程2,双方互不干扰不抢占对方的资源,同时进行。
并发:在某一段时间,会有多个进程运行在cpu上运行,但是在某一点时间,只会有一个进程运行。

僵尸进程:
如果一个进程使用fork()创建子进程,在子进程exit()后,父进程没有使用wait()/waitpid()去更新查看子进程的状态信息,那么这个子进程的状态信息描述依然会保持存在时的状态,这样被称作僵尸进程,使用ps命令查看,会有z字样描述。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

Linux查看进程命令:
PS命令
ps -ef 会查看当前所有的进程状态

九、设计模式

单例模式,单例模式的缺点
工厂模式

十、open and with open
open出现错误异常会报错,with不会
open

1,打开文件

file=open("文件名",“读写模式”)

2,操作文件

***

3,关闭文件

file.close()

注意事项:

使用open方法,文件操作完毕之后必须关闭,否则长期保持对文件的连接状态,造成内存溢出的现象发生。

with open

1,打开文件

with open ("文件名",“读写模式”) as file:

2,操作文件

***

3,关闭文件(自动关闭)

python gil锁:

血泪教训,二面折戟于此!!!
这是python的全局变量锁,简称 GIL锁。
我们都知道python的多线程是为多线程,这正是因为gil锁的存在,导致在某一个精确时间,只能有一个线程在运行!当然,gil锁也有好的一面,避免的多线程的死锁现象。
tips:对于i/o密集型,python的多线程还是有点效果的;对于cpu密集型,切换带来的巨大消耗使得多线程并没有效率的提升。

参考链接:https://www.cnblogs.com/zipxzf/p/11621630.html

进程间的通信方式:
socket、消息队列、等

python字典的底层,为什么不用红黑树?
字典结构大多数都是有数组和链表组成的,简单来说就是一个数组,每个位置对应一个hashcode,插入的一组key-value pair,会先被hash加密算法计算,这里可以有多个哈希算法。计算后,很具hashcode放入对应的位置,如果位置上已经有值了,也就是哈希冲突了,那么我们可以开放寻址(跳到下个空位上),链表法(!)。就是在位置上建立一个链表结构,连接起来。java1.8里使用了红黑树和链表。

python的列表底层:
python的list底层是一个顺序表,或者说c语言的数组。当时参加字节面试,小哥上来就让我说底层,并且问我底层的struct,我人就傻了。c语言的数组,是一个连续的内存空间,并且是不可变的。当然了,python的list是可变大小的,并且支持hash,以及前后POP。
这里还会关联到其他结构的底层是什么?数组和链表的比较等等。

fork()返回值:
它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

ping命令是那一层的?
应用层

相关文章

网友评论

      本文标题:2020-09-19

      本文链接:https://www.haomeiwen.com/subject/ntreyktx.html